字串 Trie字典樹

2021-10-10 05:48:49 字數 3223 閱讀 9521

目錄

trie字典樹 例題

1.什麼是字典樹?

2.字典樹的作用及性質

3.建樹

code:

效果圖:

4.查詢

code:

5.優勢

6.回到例題

code:

7.結束語

8.練習:

給出n個字串,以及m個詢問。每次詢問讀入乙個字串,求該字串是多少個字串的字首 

每個字串長度小於10^2,n和m小於10^5。

【樣例輸入】

4 anan 

amn 

aman 

anann 

3 ana 

ama 

a【樣例輸出】

2 1 

4樸素演算法:暴力搜尋,對於每個詢問,把所有的n個字串搜尋一遍,統計答案。時間複雜度大於10^10。顯然,這樣時間是非常大的。

如果要優化時間的話,我們就可以使用字典樹

字典樹,又叫做trie樹,顧名思義,首先它必須得是一棵樹。 

**而且它是用來儲存字串的!!!** 就像一本字典一樣,裡面什麼都有(只要你存了)

它的根節點為空,其餘每個節點代表乙個字元。從根節點開始,沿著一定的路徑,加上沿途遇到的字元,到達每個節點,都能得到對應的乙個字串。

字典樹的作用

1、可以判斷乙個字串之前是否出現過。

2、可以判斷當前這個字串是多少個字串的字首。

3、等等等等......

其實大概就這些了,具體應用就要靠讀者自己去思考了。

字典樹的性質

1、沿著字典樹一直走,如果經過乙個被標記的點,那麼從根節點到當前這個節點所經過的所有字元組成的字串一定出現過,也就是說如果乙個沒有出現過的字串在字典樹上是走不出來的。

2、不論沿著字典樹怎麼走,都不會走到兩個被標記的不同的點,使得它們沿途經過的點是完全相同的,意思就是說相同的字串在字典樹裡面只會出現一次。

設trie[i].to[c]表示字典樹中編號i節點的兒子中,字元c的兒子的編號。 

設trie[i].bz表示當前這個節點是否是乙個字串的結尾(1是0不是)。

設tot表示當前trie樹里節點的總數(也可以看做編號),當我們要加入乙個點的時候就將編號+1。

一開始字典樹是一棵空樹,不,實際上不是,因為它有乙個為空的根節點。

為了節約空間,只有需要用到的節點,才會被開啟,其餘都是不存在的。(這句話如果不好理解可以看看操作步驟和**)

設當前我們將字串s加入字典樹,步驟如下: 

1、先將當前的節點賦成根節點,之後我們從左到右掃s這個字串(注意字典樹的根節點為空); 

2、如果當前的點後面沒有乙個s[i]的字元,那就在當前這個點的下面加上s[i]這個字元的點;

3、然後沿著字典樹往s[i]這個字元走下去。

4、當字串中所有的字元都加入完了這棵字典樹時,要將這個字串的最後乙個字元的編號打上標記,表示當前這個節點是乙個字串的結尾。

int tot=0;//tot一定要是根節點的編號,因為當根節點往下走的時候tot+1不能和根節點的編號一樣

void insert(char s)

trie[t].bz=true;//表示當前節點是乙個字串的結尾

}for(int i=1;i<=n;i++)

如前面的樣例,四個字串用字典樹儲存的效果。 

同時,圖中被紅線畫出來的點都被打了標記;根節點的編號為0,從根節點往下的第乙個a的編號是1,以此類推,編號為1的a下面的n編號為2,編號為2的n下面的a編號為3,編號為3的a下面的n編號為4。編號為1的a下面的m編號為5,編號為5的m下面的n編號為6。編號為5的m下面的a編號為7,編號為7的a下面的n編號為8。最後編號為4的n下面的n編號為9。

如果我們要查詢乙個字串是否在字典樹**現該怎麼辦呢?

1、首先,我們按照這個字串中的每個字元在字典樹中走下去。

2、如果有乙個字元沒有出現在字典樹中,那麼這個字串就沒有出現,直接退出。

3、如果掃完了這個字串,也走完了這棵字典樹,那麼我們就判斷一下當前這個節點是否有標記,有標記就說明這個字串出現過。

int tot=0;//根節點編號為0

int find()

return tree[t].bz;//如果當前編號t是乙個字串的結尾,就說明這個字串出現過,否則就沒有出現。

}

由上圖顯而易見,當多個字串有相同字首時,相同的字元只會儲存一次,節省了很大的空間。 

同時,用字典樹儲存字串,可以對許多關於字串字首的題目有很大幫助。

顯然,這題我們需要先用n個字串建立一棵字典樹。 

與此同時,記錄tree[t].bz表示n個字串中字首為string[t]的個數,string[t]為字典樹中到節點i處所表示的字串(此處只是為了方便說明,在實現時這個string陣列並不存在)。每到乙個節點t,就給tree[t].bz+1。

如何處理詢問? 

將詢問串放入字典樹中,類似建樹的方式往下走。如果對應的節點不存在,則直接返回並輸出0。 

否則一直走到該串的末尾,對應的tree[i].bz即為答案。

#include#include#include#include#includeusing namespace std;

int n,m,len,tot=0;

struct treetrie[100000];

char s[1000][1000];

void insert(char s)

}int find(char s)

return trie[t].bz;

}int main()

scanf("%d",&m);

for(int i=1;i<=m;i++)

return 0;

}

此時,相信你已經學會了。字典樹模板都是一樣的,對於不同的題目不同的要求,都以模板為基礎,再按需新增各種操作,難題便迎刃而解。 

面對更多的困難與挑戰,需要你更多思考、靈活變通,一切都不是問題!

1.1099. 尋找字串

2.5795. 【2018提高組】模擬a組&省選 詞典

字串 Trie樹(字典樹)

關於這個字串的資料結構我就不多說什麼了,不知道的可以戳這裡.trie樹在oi中應用廣泛,時間優秀,缺點就是空間占用大。下文中我們將字符集大小稱為 k,模式串長度為p trie支援o np 建樹,o p 插入,查詢,刪除。可是如果二維陣列儲存的話,就要耗費kn 的空間,基本無法承受。空間上我們可以用指...

Trie樹 字典樹(字串排序)

有時,我們會碰到對字串的排序,若採用一些經典的排序演算法,則時間複雜度一般為o n lgn 但若採用trie樹,則時間複雜度僅為o n trie樹又名字典樹,從字面意思即可理解,這種樹的結構像英文本典一樣,相鄰的單詞一般字首相同,之所以時間複雜度低,是因為其採用了以空間換取時間的策略。下圖為乙個針對...

Trie樹 字典樹 字串排序

有時,我們會碰到對字串的排序,若採用一些經典的排序演算法,則時間複雜度一般為o n lgn 但若採用trie樹,則時間複雜度僅為o n trie樹又名字典樹,從字面意思即可理解,這種樹的結構像英文本典一樣,相鄰的單詞一般字首相同,之所以時間複雜度低,是因為其採用了以空間換取時間的策略。下圖為乙個針對...