日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构:字典树的基本使用

發(fā)布時間:2025/3/20 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构:字典树的基本使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述:

? 說來也奇怪,最近碰到的很多問題都需要用字典樹來解決,索性就來研究一番。在這篇博客中,我會通過一些實例來講解一下字典樹的一些基本使用。例如:創(chuàng)建、添加、查找、按字典序排序、按數(shù)值大小進行排序(對于一些數(shù)值序列的排序)等等。

?

關(guān)于字典的實際應(yīng)用實例,請參見本人的另一篇博客:《算法:兩種對拼音進行智能切分的方法》

?

本文鏈接:http://blog.csdn.net/lemon_tree12138/article/details/49177509 -- 編程小笙
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?--轉(zhuǎn)載請注明出處

?

版權(quán)說明


著作權(quán)歸作者所有。
商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
本文作者:Q-WHai
發(fā)表日期: 2015年10月19日
本文鏈接:
https://qwhai.blog.csdn.net/article/details/49177509
來源:CSDN
更多內(nèi)容:分類 >> 算法與數(shù)學(xué)

?

基本使用:

0.要點說明:

? 為了便于以下對字典樹的說明,我這里的節(jié)點Node可能會有一些對于讀者而并不必要的成員。例如,fre, visited, minLength, prefixCount等等。這里讀者可以根據(jù)自己的需求自行增減。

?

String name; // 結(jié)點的字符名稱int fre; // 單詞的詞頻boolean end; // 是否是單詞結(jié)尾boolean root; // 是否是根結(jié)點Node[] children; // 子節(jié)點信息boolean visited; // 是否已經(jīng)遍歷過了int minLength; // 通過該節(jié)點的最小的數(shù)字長度int prefixCount = 0; // 有多少單詞通過這個節(jié)點,即節(jié)點字符出現(xiàn)的次數(shù)Node parent; // 當(dāng)前節(jié)點的父節(jié)點

?

?

?

1.創(chuàng)建一棵新的字典樹

? 對于創(chuàng)建一棵空的字典樹,其實相對來說是比較容易的。因為,我們不需要對樹進行一些元素新增或是移除。我們只是對字典樹中的一些必要的成員進行了一些初始化的工作。下面是代碼部分:

?

Node root;int depth;public TrieTree(String name) {root = new Node(name);root.setFre(0);depth = 0;root.setEnd(false);root.setRoot(true);}

?

?

?

2.插入一個新的節(jié)點元素

? 對于在字典樹的新增元素的關(guān)鍵地方,應(yīng)該就是我們要在何是停止,即新增完成的條件是什么?

? 我們元素新增完成的條件是,我們在對新增的元素(如:"12345")進行遍歷,直到遍歷到字符串的末尾。

? 在我們對新增的字符串str進行插入字典樹的過程中,比如說已經(jīng)遍歷到位置i,如果str.chartAt(i)在字典樹中已經(jīng)存在,則我們可以直接pass,繼續(xù)遍歷i+1的位置;如果str.chartAt(i)在字典樹中是不存在的,那么我們就必須新增此節(jié)點,再將新增的此節(jié)點掛載到上一個點的后面,然后繼續(xù)遍歷i+1位置上元素str.chartAt(i+1)。然后在插入的字符串最后的位置上設(shè)置此節(jié)點為結(jié)束節(jié)點(即在此位置可以構(gòu)成單詞,或是完整添加的數(shù)字)。具體代碼如下:

?

public void insert(String number) {Node node = root;char[] numberCells = number.toCharArray();for (int i = 0; i < numberCells.length; i++) {int num = Integer.parseInt(String.valueOf(numberCells[i]));if (node.getChildren()[num] != null) {if (numberCells.length < node.getChildren()[num].getMinLength()) {node.getChildren()[num].setMinLength(numberCells.length);}if (i == numberCells.length - 1) {Node endNode = node.getChildren()[num];endNode.setFre(endNode.getFre() + 1);endNode.setEnd(true);}node.getChildren()[num].prefixCountIncrement();} else {Node newNode = new Node(numberCells[i] + "");newNode.setParent(node);if (i == numberCells.length - 1) {newNode.setFre(1);newNode.setEnd(true);newNode.setRoot(false);}newNode.setMinLength(numberCells.length);node.getChildren()[num] = newNode;depth = Math.max(i + 1, depth);}node = node.getChildren()[num];}}

?

?

?

3.返回Trie中某一節(jié)點被添加的次數(shù)

? 此功能的應(yīng)用點在于,詞頻統(tǒng)計。我們在每次新增一個元素時都會在原來的基本上,對詞頻進行自增處理。如果新增的詞在之前的字典樹中是不存在的,就設(shè)置初始值為1,如果原本有這個節(jié)點,就在原來的詞頻上+1.在上一步(插入一個新的節(jié)點元素)中可以看到具體操作。那么這里介紹一下查詢詞頻的操作。代碼如下:

?

public int searchFre(String number) {int fre = -1;Node node = root;char[] numberCells = number.toCharArray();for (int i = 0; i < numberCells.length; i++) {int num = Integer.parseInt(String.valueOf(numberCells[i]));if (node.getChildren()[num] != null) {node = node.getChildren()[num];fre = node.getFre();} else {fre = -1;break;}}return fre;}

?

?

?

4.計算有多少個單詞以prefix為前綴

? 對于前綴統(tǒng)計的操作,我們也需要在插入的過程中進行統(tǒng)計。這是因為,如果我們在插入的時候不進行統(tǒng)計,那么我們就必須在每次查詢一個前綴的時候,去遍歷前綴結(jié)束節(jié)點以下的所有子節(jié)點。這樣勢必會增加時間上的復(fù)雜度,是一種不理想的方式。不過,因為有時,我們并不會只是要求計算有多少以prefix為前綴的串。所以,可能遍歷是在所難免。還是要看需求吧。以下代碼是查詢過程:

?

public int countPrefix(String prefix) {if (prefix == null || prefix.length() == 0) {return -1;}Node node = root;char[] letters = prefix.toCharArray();for (int i = 0; i < prefix.length(); i++) {if (node.getChildren()[Integer.parseInt(String.valueOf(letters[i]))] == null) {return 0;} else {node = node.getChildren()[Integer.parseInt(String.valueOf(letters[i]))];}}return node.getPrefixCount();}

?

?

?

5.獲得trie的深度

? 對于樹深度的問題,對于其實際的應(yīng)用點,我目前還未知曉。只是在寫其他功能的時候想到了,就附帶了吧。

? 這個深度,也是要在新增節(jié)點的時候去實時更新的。這樣可以減小查詢時的時間復(fù)雜度。查詢代碼如下:

?

public int depth() {return depth;}

It's too easy, isn't it?

?

6.對字典樹進行字典序排序(即深度優(yōu)先搜索)

? 就以我們的數(shù)字字典樹為例。因為我們在構(gòu)造樹的過程就是一個以字典序為基礎(chǔ)的過程,所以我們的遍歷就可以直接對樹進行順序遍歷就Ok。對于字典樹而言,順序遍歷的過程,其實就是對樹的深度遍歷。如果大家還記得深度遍歷的過程,相信大家可以很容易地寫出此代碼。我的編碼過程如下(使用了遞歸):

?

public void dictOrder(Node node, String prefix) {if (node != null) {if (node.isEnd()) {System.out.println(prefix + node.getName());}for (Node children : node.getChildren()) {if (children == null) {continue;}dictOrder(children, prefix + (node.isRoot() ? "" : node.getName()));}}}

?

?

?

7.對數(shù)字字典樹按實際數(shù)值大小排序(即廣度優(yōu)先搜索)

? 在第6步中,我們看到對樹深度優(yōu)先搜索的過程就是對樹進行按字典序排序。那么可能你也會問另一個問題,那么是廣度優(yōu)先搜索又會是怎么樣的結(jié)果呢?廣度優(yōu)先搜索的另一個叫法,我們可以說是對樹的分層遍歷。既然是對樹進行分層,那么就是說"123"要排在"1234"的前面。而在第6步中我們也說到了,字典樹本身就是以字典序為基礎(chǔ)進行新增。也就是"123"必然是在"124"的前面。Ok,基于這樣的分析,我們可以得到一個很容易理解的結(jié)論:對字典樹進行廣度優(yōu)先搜索的過程就是對字典樹進行按數(shù)值大小進行排序。具體的實現(xiàn)代碼如下:

?

/*** 對數(shù)字字典樹按實際數(shù)值大小排序(即分層打印)* TrieTree*/public void sortNumberOrder(Node node, String prefix) {Queue<Node> queuing = new LinkedList<Node>();queuing.offer(node);while (!queuing.isEmpty()) {Node currentNode = queuing.poll();if (currentNode.isEnd()) {System.out.println(getNodePath(currentNode));}Node[] children = currentNode.getChildren();for (Node sonNode : children) {if (sonNode != null) {queuing.offer(sonNode);}}}}/*** 獲得某一節(jié)點的上層節(jié)點,即前綴字符串* @param node* @return*/public String getNodePath(Node node) {StringBuffer path = new StringBuffer();Node currentNode = node;while (currentNode.getParent() != null) {path.append(currentNode.getName());currentNode = currentNode.getParent();}return path.reverse().toString();}

?

?

Github

https://github.com/qwhai/simple-tree

總結(jié)

以上是生活随笔為你收集整理的数据结构:字典树的基本使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。