Trie樹 的理論與實現


性質

它有3個基本性質:
根節點不包含字符,除根節點外每一個節點都只包含一個字符; 從根節點到某一節點,路徑上經過的字符連接起來,爲該節點對應的字符串; 每個節點的所有子節點包含的字符都不相同。

2基本操作

其基本操作有:查找、插入和刪除,當然刪除操作比較少見。我在這裏只是實現了對整個樹的刪除操作,至於單個word的刪除操作也很簡單。

3實現方法

搜索字典項目的方法爲(1) 從根結點開始一次搜索;
(2) 取得要查找關鍵詞的第一個字母,並根據該字母選擇對應的子樹並轉到該子樹繼續進行檢索;
(3) 在相應的子樹上,取得要查找關鍵詞的第二個字母,並進一步選擇對應的子樹進行檢索。
(4) 迭代過程……
(5) 在某個結點處,關鍵詞的所有字母已被取出,則讀取附在該結點上的信息,即完成查找。
其他操作類似處理

4應用

串的快速檢索

給出N個單詞組成的熟詞表,以及一篇全用小寫英文書寫的文章,請你按最早出現的順序寫出所有不在熟詞表中的生詞。
在這道題中,我們可以用數組枚舉,用哈希,用字典樹,先把熟詞建一棵樹,然後讀入文章進行比較,這種方法效率是比較高的。

“串”排序

給定N個互不相同的僅由一個單詞構成的英文名,讓你將他們按字典序從小到大輸出
用字典樹進行排序,採用數組的方式創建字典樹,這棵樹的每個結點的所有兒子很顯然地按照其字母大小排序。對這棵樹進行先序遍歷即可。

最長公共前綴

對所有串建立字典樹,對於兩個串的最長公共前綴的長度即他們所在的結點的公共祖先個數,於是,問題就轉化爲當時公共祖先問題(以後補上)。
Trie樹既可用於一般的字典搜索,也可用於索引查找。對於給定的一個字符串a1,a2,a3,...,an.則
採用TRIE樹搜索經過n次搜索即可完成一次查找。不過好像還是沒有B樹的搜索效率高,B樹搜索算法複雜度爲logt(n+1/2).當t趨向大,搜索效率變得高效。怪不得DB2的訪問內存設置爲虛擬內存的一個PAGE大小,而且幀切換頻率降低,無需經常的PAGE切換。

10.3 Trie樹

當關鍵碼是可變長時,Trie樹是一種特別有用的索引結構。

10.3.1 Trie樹的定義


Trie樹是一棵度 m ≥ 2 的樹,它的每一層分支不是靠整個關鍵碼的值來確定,而是由關鍵碼的一個分量來確定。

如下圖所示Trie樹,關鍵碼由英文字母組成。它包括兩類結點:元素結點和分支結點。元素結點包含整個key數據;分支結點有27個指針,其中有一個空白字符‘b’,用來終結關鍵碼;其它用來標識‘a’, ‘b’,..., ‘z’等26個英文字母。

在第0層,所有的關鍵碼根據它們第0位字符, 被劃分到互不相交的27個類中。

因此,root→brch.link[i] 指向一棵子Trie樹,該子Trie樹上所包含的所有關鍵碼都是以第 i 個英文字母開頭。

若某一關鍵碼第 j 位字母在英文字母表中順序爲 i ( i = 0, 1, ?, 26 ), 則它在Trie樹的第 j 層分支結點中從第 i 個指針向下找第 j+1 位字母所在結點。當一棵子Trie樹上只有一個關鍵碼時,就由一個元素結點來代替。在這個結點中包含有關鍵碼,以及其它相關的信息,如對應數據對象的存放地址等。



#include "stdafx.h"
#include <iostream>
#include<algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;
const int num_chars = 26;
class Trie {
public:
	Trie();
	Trie(Trie& tr);
	virtual ~Trie();
	int trie_search(const char* word, char* entry ) const;
	int insert(const char* word, const char* entry);
	int remove(const char* word, char* entry);
protected:
	struct Trie_node
	{
		char* data;
		Trie_node* branch[num_chars];
		Trie_node();
	};

	Trie_node* root;
};
Trie::Trie_node::Trie_node() 
{
	data = NULL;
	for (int i=0; i<num_chars; ++i) 
		branch[i] = NULL;
}
Trie::Trie():root(NULL)
{
}
Trie::~Trie()
{
}
int Trie::trie_search(const char* word, char* entry ) const 
{
	int position = 0;
	char char_code;
	Trie_node *location = root;
	while( location!=NULL && *word!=0 ) 
	{
		if (*word>='A' && *word<='Z') 
			char_code = *word-'A';
		else if (*word>='a' && *word<='z') 
			char_code = *word-'a';
		else return 0;
		location = location->branch[char_code];
		position++;
		word++;
	}
	if ( location != NULL && location->data != NULL ) 
	{
		strcpy(entry,location->data);
		return 1;
	}
	else return 0;
}
int Trie::insert(const char* word, const char* entry) 
{
	int result = 1, position = 0;
	if ( root == NULL ) root = new Trie_node;
	char char_code;
	Trie_node *location = root;
	while( location!=NULL && *word!=0 )
	{
		if (*word>='A' && *word<='Z') 
			char_code = *word-'A';
		else if (*word>='a' && *word<='z') 
			char_code = *word-'a';
		else return 0;
		if( location->branch[char_code] == NULL ) 
			location->branch[char_code] = new Trie_node;
		location = location->branch[char_code];
		position++;
		word++;
	}
	if (location->data != NULL)
		result = 0;
	else {
		location->data = new char[strlen(entry)+1];
		strcpy(location->data, entry);
	}
	return result;
}
int main()
{
	Trie t;
	char entry[100];
	t.insert("aa", "DET"); 
	t.insert("abacus","NOUN");
	t.insert("abalone","NOUN"); 
	t.insert("abandon","VERB");
	t.insert("abandoned","ADJ"); 
	t.insert("abashed","ADJ");
	t.insert("abate","VERB"); 
	t.insert("this", "PRON");
	if (t.trie_search("this", entry))
		cout<<"'this' was found. pos: "<<entry<<endl;
	if (t.trie_search("abate", entry))
		cout<<"'abate' is found. pos: "<<entry<<endl;
	if (t.trie_search("baby", entry))
		cout<<"'baby' is found. pos: "<<entry<<endl;
	else
		cout<<"'baby' does not exist at all!"<<endl;

	if (t.trie_search("aa", entry))
		cout<<"'aa was found. pos: "<<entry<<endl;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章