Trie 樹的簡單實現
阿新 • • 發佈:2019-01-30
Trie 樹, 又稱字首樹,是一種高校的動態儲存結構
查詢效率:O(m) m為串的長度
空間要優於BST(二叉搜尋樹),因為Trie 樹是字首複用的。
實現了插入、刪除、顯示
加了註釋,另外解構函式沒有實現,釋放樹資源的函式也沒有實現 :(
#define CHARSIZE 26 #include<assert.h> #include<stdlib.h> #include<iostream> using namespace std; /* 樹節點,用於儲存當前字元資訊 */ typedef struct NODE { char key;//該值可以沒有,由於程式的,可以註釋掉相關程式碼 bool isNode;//當前節點代表的字串是否是存入的節點 struct NODE* child[ CHARSIZE ];//26叉樹,按照a-z的順序,如果是NULL表示該字母位置為空 }* PNODE,*TRIE; class Trie{ public: Trie(); void Insert( char* sData ); void Show( ); void ShowTrie( PNODE root ); bool Delete( char* sData ); bool NoChild(PNODE pNode); struct NODE* Search( char* sData ); void DeleteTrie(); ~Trie(); private: PNODE pRoot;//樹指標 static char colls[];//代表26個字母,可以設定自定義的對映和長度 }; char Trie::colls[] = "abcdefghijklmnopqrstuvwxyz "; /* 建構函式,建立根節點 */ Trie::Trie(){ //root create this->pRoot = NULL; this->pRoot = (PNODE)malloc(sizeof(struct NODE)); this->pRoot->key = ' '; this->pRoot->isNode = false; for( int i=0; i<CHARSIZE; i++ ){ this->pRoot->child[ i ] = NULL; } } /* 插入新節點 */ void Trie::Insert( char* sData ){ //如果字串為空,不允許插入 if( sData==NULL || *sData == '\0' ){ return; } //獲取根指標,用於後邊的查詢正確的插入位置 PNODE p = this->pRoot; char* pData = sData;//當前字元指標 //迴圈直到處理完所有字元 while( *pData!='\0' ){ //如果對應位置的指標為空,就建立新的節點 if( p->child[ *pData-'a' ]==NULL ){ //make new Node PNODE node = (PNODE)malloc(sizeof(struct NODE)); //node->key = *pData;//key是多餘的欄位 node->isNode = true;//該新節點表示真正的儲存節點而不是字首 int i = 0; while( i < CHARSIZE ){ node->child[i] = NULL; i++; } //將新節點連結到樹中的合適位置 p->child[*pData-'a'] = node; } //go on loop p = p->child[ *pData-'a' ]; //deal with next character pData++; } } /* Show string stored in Trie tree :( not look well, but you can draw on paper from this output or whtn you delete one node, you will see the change */ void Trie::Show( ){ //為了便於遞迴呼叫,使用中間函式 ShowTrie( this->pRoot ); } void Trie::ShowTrie( PNODE root ){ if( root==NULL ){ return; } if( root->isNode == true ) cout<<root->key<<" "; for( int i=0; i<CHARSIZE; i++ ){ ShowTrie( root->child[i] ); } } /* Delete node from Trie tree */ bool Trie::Delete( char * sData ){ if( sData==NULL || *sData=='\0' ) return false; PNODE p = this->pRoot; PNODE pre = NULL; char *pData = sData; while(pData!=NULL && *pData!='\0'){ if( p==NULL || p->child[*pData-'a']==NULL ){ cout<<"No:"<<*sData<<endl; }else if( p->child[*pData-'a']->isNode==true ){ //delete this if( NoChild(p->child[*pData-'a']) ){ p->child[*pData-'a'] = NULL;//delete this node directly }else{//has children p->child[*pData-'a']->isNode = false; } return true; }else{ pre = p; p = p->child[*pData-'a']; pData++; } } return false; } /* Is a node has children */ bool Trie::NoChild(PNODE pNode){ if(pNode == NULL) return true; for( int i=0; i<CHARSIZE; i++ ){ if( pNode->child[i]!=NULL ){ return false; } } return true; } void Trie::DeleteTrie(){ } Trie::~Trie( ){}
主程式:
#include<iostream> #include"trie.h" using namespace std; int main( int argc, char* argv[] ){ Trie myTrie = Trie(); myTrie.Insert( "a" ); myTrie.Insert( "ab" ); myTrie.Insert( "ac" ); myTrie.Insert( "ad" ); myTrie.Insert( "ae" ); myTrie.Insert( "af" ); myTrie.Insert( "abc" ); myTrie.Insert( "abe" ); myTrie.Insert( "abf" ); myTrie.Insert( "add" ); myTrie.Insert( "bb" ); myTrie.Insert( "bh" ); myTrie.Show(); cout<<endl; myTrie.Delete("bb"); myTrie.Show(); cout<<endl; myTrie.DeleteTrie(); return 0; }