字典樹簡介、應用以及與雜湊表的比較
阿新 • • 發佈:2019-01-21
題目要求:
1、設計並實現N-array trie,包括初始化,查詢,插入,刪除等。
2、應用trie結構實現文字文件的索引化,首先掃描文字文件,然後利用trie結構記錄單詞行號,最後在trie上實現查詢
3、使用者的查詢可以是針對一個單詞,也可以是某些字母開頭的。
我的思路:
根據題目的要求,用字典樹這一資料結構實現最為符合,下面介紹一下字典樹:
字典樹介紹:
我們拿儲存英文單詞的字典樹為例,從實質上來講,該字典樹就是一個26叉樹。(若是儲存數字如電話號碼,那麼就是一個10叉樹)。
比如說我想儲存he,her,boy這三個單詞,那麼其結構如下圖所示:
總結其基本性質如下: 根節點不包含字元,除根節點意外每個節點至多包含一個單詞。 從根節點到某一個節點,路徑上經過的字元連線起來,為該節點對應的字串。
程式碼實現:
TrieNode類(節點類):string rownum(儲存行號),26個指向TrieNode的指標(*a,*b,……),建構函式等;
Trie類(樹):
root(根節點)
storeWord()(插入單詞的方法):從根節點向子節點遍歷(若子節點為空,則新建子節點,直到到達對應位置)
queryWord(查詢單詞行號):從根節點向子節點遍歷到達對應位置返回行號
其中題目中提到的查詢以某些字母開頭的單詞,那麼只需遍歷以該節點為根的子樹即可(比如層次遍歷)。如下,想查詢以he開頭的單詞,遍歷藍色圈起來的子樹。
對字典樹的分析:
優點:
1、插入,查詢,刪除等操作複雜度為O(h),其中h為單詞的長度。為什麼會這麼快呢,本質是空間換時間(空間複雜度為26的h次方),利用指標來避免做其他不必要的查詢。(初始化的時間複雜度為n O(h),n為單詞個數) 2、當儲存大量單詞或者說儲存的單詞有著共同字首時節省了空間。(比如說用線性儲存boy,boyfriend如用trie儲存的差別)
缺點:
指標佔用的空間,空間複雜度大。如果儲存少量的單詞,並不能節省空間。
字典樹的應用:
1、 字串檢索:
事先將已知的一些字串(字典)的有關資訊儲存到trie樹裡,查詢另外一些未知字串是否出現過或者出現頻率。(本題既是如此)
2、 字串最長公共字首(轉化為尋找共同祖先問題)
與雜湊的比較
實際效果:
我儲存26400行的單詞,其中查詢很快,達到了預期,但初始化過程表現很差,用時約3分鐘。
我的改進:
在每個節點直接申請所有的指標,來獲得連續的空間,防止記憶體過於碎片化,但效果並不好。
下面是程式碼版本一
#include < stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#include <stdio.h>
#include<string.h>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stack>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
class BinaryTreeNode//二叉樹的節點類
{
public:
BinaryTreeNode() { a = b= c = d = e= f =g=h=i=j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z=0; }
BinaryTreeNode(string num) { rownum = num; a = b= c = d = e= f =g=h=i=j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z=0; }
//BinaryTreeNode(char c, BinaryTreeNode* left, BinaryTreeNode* right) { data = c; leftChild = left; rightChild = right; }
string rownum ;
BinaryTreeNode* a;BinaryTreeNode* b;BinaryTreeNode* c;BinaryTreeNode* d;BinaryTreeNode* e;BinaryTreeNode* f;
BinaryTreeNode* g;BinaryTreeNode* h;BinaryTreeNode* i;BinaryTreeNode* j;BinaryTreeNode* k;BinaryTreeNode* l;
BinaryTreeNode* m;BinaryTreeNode* n;BinaryTreeNode* o;BinaryTreeNode* p;BinaryTreeNode* q;BinaryTreeNode* r;
BinaryTreeNode* s;BinaryTreeNode* t;BinaryTreeNode* u;BinaryTreeNode* v;BinaryTreeNode* w;BinaryTreeNode* x;
BinaryTreeNode* y;BinaryTreeNode* z;
};
class Node //佇列類中用連結串列存
{
public:
BinaryTreeNode *data;
Node *next;
Node() { next = NULL; }
Node(BinaryTreeNode *item, Node* link = NULL) { data = item; next = link; }
};
//佇列類,作為層次遍歷的輔助資料結構用
class LinkQueue
{
private:
Node *front, *rear;
public:
LinkQueue() { rear = front = new Node; };
bool empty()
{
return front == rear;
}
void outQueue(BinaryTreeNode * &e)//出佇列
{
Node *tmpPtr = front->next;
e = tmpPtr->data;
front->next = tmpPtr->next;
if (rear == tmpPtr) rear = front;
delete tmpPtr;
}
void inQueue(BinaryTreeNode * &e)//入佇列
{
Node *tmpPtr = new Node(e);
rear->next = tmpPtr;
rear = tmpPtr;
}
};
//二叉樹類
class BinaryTree
{
public:
BinaryTree() { root = 0; }
void insertaChild(BinaryTreeNode* t, string rownum)//插入A孩子
{
t->a = new BinaryTreeNode(rownum);
}
void insertbChild(BinaryTreeNode* t, string rownum)//插入B孩子
{
t->b = new BinaryTreeNode(rownum);
}
void insertcChild(BinaryTreeNode* t, string rownum)//插入C孩子
{
t->c = new BinaryTreeNode(rownum);
}
void insertdChild(BinaryTreeNode* t, string rownum)//插入D孩子
{
t->d = new BinaryTreeNode(rownum);
}
void inserteChild(BinaryTreeNode* t, string rownum)//插入E孩子
{
t->e = new BinaryTreeNode(rownum);
}
void insertfChild(BinaryTreeNode* t, string rownum)//插入F孩子
{
t->f = new BinaryTreeNode(rownum);
}
void insertgChild(BinaryTreeNode* t, string rownum)//插入G孩子
{
t->g = new BinaryTreeNode(rownum);
}
void inserthChild(BinaryTreeNode* t, string rownum)//插入H孩子
{
t->h = new BinaryTreeNode(rownum);
}
void insertiChild(BinaryTreeNode* t, string rownum)//插入I孩子
{
t->i = new BinaryTreeNode(rownum);
}
void insertjChild(BinaryTreeNode* t, string rownum)//插入J孩子
{
t->j = new BinaryTreeNode(rownum);
}
void insertkChild(BinaryTreeNode* t, string rownum)//插入K孩子
{
t->k = new BinaryTreeNode(rownum);
}
void insertlChild(BinaryTreeNode* t, string rownum)//插入L孩子
{
t->l = new BinaryTreeNode(rownum);
}
void insertmChild(BinaryTreeNode* t, string rownum)//插入M孩子
{
t->m = new BinaryTreeNode(rownum);
}
void insertnChild(BinaryTreeNode* t, string rownum)//插入N孩子
{
t->n = new BinaryTreeNode(rownum);
}
void insertoChild(BinaryTreeNode* t, string rownum)//插入O孩子
{
t->o = new BinaryTreeNode(rownum);
}
void insertpChild(BinaryTreeNode* t, string rownum)//插入P孩子
{
t->p = new BinaryTreeNode(rownum);
}
void insertqChild(BinaryTreeNode* t, string rownum)//插入Q孩子
{
t->q = new BinaryTreeNode(rownum);
}
void insertrChild(BinaryTreeNode* t, string rownum)//插入R孩子
{
t->r = new BinaryTreeNode(rownum);
}
void insertsChild(BinaryTreeNode* t, string rownum)//插入S孩子
{
t->s = new BinaryTreeNode(rownum);
}
void inserttChild(BinaryTreeNode* t, string rownum)//插入T孩子
{
t->t = new BinaryTreeNode(rownum);
}
void insertuChild(BinaryTreeNode* t, string rownum)//插入U孩子
{
t->u = new BinaryTreeNode(rownum);
}
void insertvChild(BinaryTreeNode* t, string rownum)//插入V孩子
{
t->v = new BinaryTreeNode(rownum);
}
void insertwChild(BinaryTreeNode* t, string rownum)//插入W孩子
{
t->w = new BinaryTreeNode(rownum);
}
void insertxChild(BinaryTreeNode* t, string rownum)//插入X孩子
{
t->x = new BinaryTreeNode(rownum);
}
void insertyChild(BinaryTreeNode* t, string rownum)//插入Y孩子
{
t->y = new BinaryTreeNode(rownum);
}
void insertzChild(BinaryTreeNode* t, string rownum)//插入Z孩子
{
t->z = new BinaryTreeNode(rownum);
}
//下面是接收一個單詞儲存到樹中的方法
void storeWord(string word ,string rownum)
{
int length=word.length();//獲取當前單詞的長度
BinaryTreeNode* current = this->root;//current用來遍歷樹
//下面將word的字母一個個取出來判斷該單詞在樹中的位置
for(int i=0;i<length;i++)
{
string first;
first=word.substr(i,1);//依次獲取字母
cout << "當前的字母是:"+first<< endl;
if(i<length-1)//還沒到最終的位置
{
if(first.compare("a")==0)
{
if(current->a==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertaChild(current,"0");
current=current->a;
}
else//當前節點有該兒子
{
current=current->a;
}
}
else if(first.compare("b")==0)
{
if(current->b==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertbChild(current,"0");
current=current->b;
}
else//當前節點有該兒子
{
current=current->b;
}
}
else if(first.compare("c")==0)
{
if(current->c==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertcChild(current,"0");
current=current->c;
}
else//當前節點有該兒子
{
current=current->c;
}
}
else if(first.compare("d")==0)
{
if(current->d==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertdChild(current,"0");
current=current->d;
}
else//當前節點有該兒子
{
current=current->d;
}
}
else if(first.compare("e")==0)
{
if(current->e==NULL)//若當前節點沒有兒子則插入新兒子
{
this->inserteChild(current,"0");
current=current->e;
}
else//當前節點有該兒子
{
current=current->e;
}
}
else if(first.compare("f")==0)
{
if(current->f==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertfChild(current,"0");
current=current->f;
}
else//當前節點有該兒子
{
current=current->f;
}
}
else if(first.compare("g")==0)
{
if(current->g==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertgChild(current,"0");
current=current->g;
}
else//當前節點有該兒子
{
current=current->g;
}
}
else if(first.compare("h")==0)
{
if(current->h==NULL)//若當前節點沒有兒子則插入新兒子
{
this->inserthChild(current,"0");
current=current->h;
}
else//當前節點有該兒子
{
current=current->h;
}
}
else if(first.compare("i")==0)
{
if(current->i==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertiChild(current,"0");
current=current->i;
}
else//當前節點有該兒子
{
current=current->i;
}
}
else if(first.compare("j")==0)
{
if(current->j==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertjChild(current,"0");
current=current->j;
}
else//當前節點有該兒子
{
current=current->j;
}
}
else if(first.compare("k")==0)
{
if(current->k==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertkChild(current,"0");
current=current->k;
}
else//當前節點有該兒子
{
current=current->k;
}
}
else if(first.compare("l")==0)
{
if(current->l==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertlChild(current,"0");
current=current->l;
}
else//當前節點有該兒子
{
current=current->l;
}
}
else if(first.compare("m")==0)
{
if(current->m==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertmChild(current,"0");
current=current->m;
}
else//當前節點有該兒子
{
current=current->m;
}
}
else if(first.compare("n")==0)
{
if(current->n==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertnChild(current,"0");
current=current->n;
}
else//當前節點有該兒子
{
current=current->n;
}
}
else if(first.compare("o")==0)
{
if(current->o==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertoChild(current,"0");
current=current->o;
}
else//當前節點有該兒子
{
current=current->o;
}
}
else if(first.compare("p")==0)
{
if(current->p==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertpChild(current,"0");
current=current->p;
}
else//當前節點有該兒子
{
current=current->p;
}
}
else if(first.compare("q")==0)
{
if(current->q==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertqChild(current,"0");
current=current->q;
}
else//當前節點有該兒子
{
current=current->q;
}
}
else if(first.compare("r")==0)
{
if(current->r==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertrChild(current,"0");
current=current->r;
}
else//當前節點有該兒子
{
current=current->r;
}
}
else if(first.compare("s")==0)
{
if(current->s==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertsChild(current,"0");
current=current->s;
}
else//當前節點有該兒子
{
current=current->s;
}
}
else if(first.compare("t")==0)
{
if(current->t==NULL)//若當前節點沒有兒子則插入新兒子
{
this->inserttChild(current,"0");
current=current->t;
}
else//當前節點有該兒子
{
current=current->t;
}
}
else if(first.compare("u")==0)
{
if(current->u==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertuChild(current,"0");
current=current->u;
}
else//當前節點有該兒子
{
current=current->u;
}
}
else if(first.compare("v")==0)
{
if(current->v==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertvChild(current,"0");
current=current->v;
}
else//當前節點有該兒子
{
current=current->v;
}
}
else if(first.compare("w")==0)
{
if(current->w==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertwChild(current,"0");
current=current->w;
}
else//當前節點有該兒子
{
current=current->w;
}
}
else if(first.compare("x")==0)
{
if(current->x==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertxChild(current,"0");
current=current->x;
}
else//當前節點有該兒子
{
current=current->x;
}
}
else if(first.compare("y")==0)
{
if(current->y==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertyChild(current,"0");
current=current->y;
}
else//當前節點有該兒子
{
current=current->y;
}
}
else if(first.compare("z")==0)
{
if(current->z==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertzChild(current,"0");
current=current->z;
}
else//當前節點有該兒子
{
current=current->z;
}
}
}
else//到了最終的位置
{
if(first.compare("a")==0)
{
if(current->a==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertaChild(current,word+":"+rownum);
current=current->a;
}
else
{
this->insertaChild(current,word+":"+rownum);
}
}
else if(first.compare("b")==0)
{
if(current->b==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertbChild(current,word+":"+rownum);
current=current->b;
}
else
{
this->insertbChild(current,word+":"+rownum);
}
}
else if(first.compare("c")==0)
{
if(current->c==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertcChild(current,word+":"+rownum);
current=current->c;
}
else
{
this->insertcChild(current,word+":"+rownum);
}
}
else if(first.compare("d")==0)
{
if(current->d==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertdChild(current,word+":"+rownum);
current=current->d;
}
else
{
this->insertdChild(current,word+":"+rownum);
}
}
else if(first.compare("e")==0)
{
if(current->e==NULL)//若當前節點沒有兒子則插入新兒子
{
this->inserteChild(current,word+":"+rownum);
current=current->e;
}
else
{
this->inserteChild(current,word+":"+rownum);
}
}
else if(first.compare("f")==0)
{
if(current->f==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertfChild(current,word+":"+rownum);
current=current->f;
}
else
{
this->insertfChild(current,word+":"+rownum);
}
}
else if(first.compare("g")==0)
{
if(current->g==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertgChild(current,word+":"+rownum);
current=current->g;
}
else
{
this->insertgChild(current,word+":"+rownum);
}
}
else if(first.compare("h")==0)
{
if(current->h==NULL)//若當前節點沒有兒子則插入新兒子
{
this->inserthChild(current,word+":"+rownum);
current=current->h;
}
else
{
this->inserthChild(current,word+":"+rownum);
}
}
else if(first.compare("i")==0)
{
if(current->i==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertiChild(current,word+":"+rownum);
current=current->i;
}
else
{
this->insertiChild(current,word+":"+rownum);
}
}
else if(first.compare("j")==0)
{
if(current->j==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertjChild(current,word+":"+rownum);
current=current->j;
}
else
{
this->insertjChild(current,word+":"+rownum);
}
}
else if(first.compare("k")==0)
{
if(current->k==NULL)//若當前節點沒有兒子則插入新兒子
{
this->insertkChild(current,word+":"+rownum);
current=