1. 程式人生 > >Trie 樹的簡單實現

Trie 樹的簡單實現

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;
}