字典樹動態模板增刪查改一
阿新 • • 發佈:2018-12-15
//一個以連結串列實現帶刪除功能允許重複字串的字典樹 #include <stdio.h> #include <string.h> #include <stdlib.h> int charmapping[256]; //字元對映陣列,charmapping[i]=x表示ascii碼為i的字元對應於treenode中的next[x] void init_charmapping(){ for(int i='a';i<='z';i++){ //我的這個字典樹現在只允許輸入小寫字元組成的字串,然而由於有charmapping的存在,增加新字元新增對映並且增大maxn就好,很方便. charmapping[i]=i-'a'; } } const int maxn=26; //這裡假設字串中只出現26個小寫字母 const int maxm=100000; struct treenode{ int count; //標誌此節點所表示字串在所有字串中以字首形式出現的總次數 treenode* next[maxn]; }head; void init_trie(){ head.count=1; //初始化為1包括空串並且避免樹頭被刪 for(int i=0;i<maxn;i++) head.next[i]=NULL; } treenode* createnew(){ //申請一個新結點並初始化它 treenode* newnode; newnode=(treenode*)malloc(sizeof(treenode)); newnode->count=0; for(int i=0;i<maxn;i++) newnode->next[i]=NULL; return newnode; } void update(char* s,int num){ //向字典樹新增num個字串s int k=0,temp; treenode* t=&head; while(s[k]){ t->count+=num; temp=charmapping[s[k]]; if(!t->next[temp]) t->next[temp]=createnew(); t=t->next[temp]; k++; } t->count+=num; } bool search(char* s,int num){ //查詢字典樹中是否已經存在num個字串s int k=0,temp; treenode* t=&head; while(s[k]){ temp=charmapping[s[k]]; if(!t->next[temp]||t->next[temp]->count<num) return false; //根本不存在字串s或者存在的數目小於num直接失敗 t=t->next[temp]; k++; } int snum=t->count; for(int i=0;i<maxn;i++) if(t->next[i]) snum-=t->next[i]->count; //這裡是核心!!!結點t代表的字串出現的次數就是總次數減去所有子節點次數和 if(snum>=num) return true; //如果字串s的數目snum大於等於num return false; } void erase(char* s,int num){ //刪除字典樹中的num個字串s並釋放無用結點,刪除前一定要先search是否存在 int k=0,temp; treenode* t=&head; treenode* t1; //t1後面的結點都是刪除後需要被釋放的 head.count-=num; while(s[k]){ temp=charmapping[s[k]]; t->next[temp]->count-=num; if(t->next[temp]->count==0){ t1=t->next[temp]; t->next[temp]=NULL; k++; break; } t=t->next[temp]; k++; } while(s[k]){ //釋放無用結點 temp=charmapping[s[k]]; t=t1->next[temp]; free(t1); t1=t; k++; } free(t1); } char temp[1000]; void printall(treenode* tnode,int pos){ //遞迴列印字典樹咯,打出了就是字典序升序的 int count=tnode->count; for(int i=0;i<maxn;i++) if(tnode->next[i]) count-=tnode->next[i]->count; for(int i=0;i<count;i++) printf("\"%s\"\n",temp); for(int i='a';i<='z';i++){ if(tnode->next[charmapping[i]]){ temp[pos]=i; temp[++pos]='\0'; printall(tnode->next[charmapping[i]],pos); temp[--pos]='\0'; } } } int main(){ init_charmapping(); //初始化對映 init_trie(); //初始化字典樹 char x[1000]; char order; //命令 int num; //數目 printf("q:查詢\nu:插入\nd:刪除\np:列印字典樹\ne:退出\n"); while(1){ printf("請輸入命令:"); fflush(stdin); scanf("%c",&order); if(order=='q'){ printf("請輸入要查詢的字串與數目:"); scanf("%s%d",&x,&num); if(search(x,num)) printf("匹配成功。\n\n"); else printf("匹配失敗,不存在%d個\"%s\"\n\n",num,x); } else if(order=='u'){ printf("請輸入要插入的字串與數目:"); scanf("%s%d",&x,&num); update(x,num); printf("%d個\"%s\"已加入字典樹。\n\n",num,x); } else if(order=='d'){ printf("請輸入要刪除的字串與數目:"); scanf("%s%d",&x,&num); if(!search(x,num)){ printf("樹中無%d個字串\"%s\"請重新鍵入命令!\n\n",num,x); continue; } erase(x,num); printf("%d個\"%s\"已從字典樹中刪除。\n\n",num,x); } else if(order=='p'){ printf("當前字典樹內有如下字串:\n"); temp[0]='\0'; printall(&head,0); } else if(order=='e'){ printf("退出ing....\n"); break; } else printf("無效命令,請重新輸入!\n命令q:查詢是否存在字串\n命令u:往字典樹加入字串\n命令d:刪除某個字串\n命令p:按字典序升序輸出字典樹\n命令e:退出程式\n\n"); } return 0; }