題目:
給定兩個串a = a0a1……ap和b = b0b1……b1,其中每一個ai和每一個bj都屬於某個有序字元集,如果下面兩條規則之一成立,則說串a按字典序小於串b:
1)存在一個整數j,0<=j<=min(p,q),使得ai=bi,i=0,1,……,j-1,且aj<bj;
2)p<q,且ai=bi,對所有的i=0,1,……,p成立
例如,如果a和b是位串,則根據規則1)(設j=3),有10100 < 10110;根據規則2),有10100 < 101000。這與英語字典中的排序很相似。
圖12-5中示出的是基數樹(radix tree)資料結構,其中儲存了位串1011、10、011、100和0。當尋找某個關鍵字a = a0a1……ap時,在深度為i的一個結點處,若ai = 0則向左轉;若ai = 1則向右轉。設S為一組不同的二進位串構成的集合,各串的長度之和為n。說明如何利用基數樹,在O(n)時間內對S按字典序排序。例如,對圖12-5中每個結點的關鍵字,排序的輸出應該是序列0、011、10、100、1011
思考:
就是字典樹的一種特殊情況,字典樹的模版見用指標傳遞的字典樹
這題在以前的題目裡面出現過,使用了另一種解法,見演算法導論-8-3-排序不同長度的資料項目中的b
代碼:
#include <iostream>#include <string>using namespace std;//基數樹結點結構struct node{node *left;node *right;node *p;string str;node():left(NULL),right(NULL),p(NULL),str(""){}};//基數樹結點struct Radix_Tree{node *root;Radix_Tree(){root = new node;}};//向基數樹中插入一個位串void Insert(Radix_Tree *T, string s){int i;node *t = T->root, *p;//順著串依次向下找for(i = 0; i <s.length(); i++ ){//如果第i位是0,把串插入到左子樹的某個位置if(s[i] == '0'){//還沒有左子樹,就開闢一個if(t->left == NULL){p = new node;p->p = t;t->left = p;}elsep = t->left;}//如果第i位是1,把串插入到左子樹的某個位置else{//還沒有左子樹,就開闢一個if(t->right == NULL){p = new node;p->p = t;t->right = p;}elsep = t->right;}//一直找到串的最後一個字元,把串的內容存入這個節點中if(i == s.length() - 1)p->str = s;else t = p;}}//按字典序輸出,其實是先序遍曆的過程void Print(node *t){if(t == NULL)return;//如果某個節點有串的資訊,就將它輸出if(t->str != "")cout<<t->str<<endl;Print(t->left);Print(t->right);}int main(){string str, x;Radix_Tree *T = new Radix_Tree;while(1){cin>>str;if(str == "I"){cin>>x;Insert(T, x);}else if(str == "P"){Print(T->root);cout<<endl;}}return 0;}