摘要:謝路云單詞查找樹(shù)查找所需要的單詞的時(shí)間和鍵的長(zhǎng)度成正比查找未命中只需檢查若干個(gè)單詞單詞查找樹(shù)單詞查找樹(shù)基本性質(zhì)每個(gè)鏈接對(duì)應(yīng)一個(gè)字符每個(gè)結(jié)點(diǎn)可能有一個(gè)值有值,說(shuō)明存在從根結(jié)點(diǎn)到這個(gè)結(jié)點(diǎn)的字符串。它的存在是為了簡(jiǎn)化查詢(xún)。
Algorithms Fourth Edition
Written By Robert Sedgewick & Kevin Wayne
Translated By 謝路云
Chapter 5 Section 2 單詞查找樹(shù)
查找所需要的單詞的時(shí)間和鍵的長(zhǎng)度成正比
查找未命中只需檢查若干個(gè)單詞
單詞查找樹(shù) 單詞查找樹(shù)API 基本性質(zhì)每個(gè)鏈接對(duì)應(yīng)一個(gè)字符
每個(gè)結(jié)點(diǎn)可能有一個(gè)值
有值,說(shuō)明存在從根結(jié)點(diǎn)到這個(gè)結(jié)點(diǎn)的字符串。
沒(méi)有值,說(shuō)明不存在從根結(jié)點(diǎn)到這個(gè)結(jié)點(diǎn)的字符串。沒(méi)有對(duì)應(yīng)的鍵值。它的存在是為了簡(jiǎn)化查詢(xún)。
查找
命中: 對(duì)應(yīng)結(jié)點(diǎn)有值(注意不單單是指向該對(duì)應(yīng)結(jié)點(diǎn)d鏈接存在,并且該結(jié)點(diǎn)一定要有值!)
未命中: 沒(méi)有值 or 鏈接為空
結(jié)點(diǎn)的表示
每個(gè)結(jié)點(diǎn)下面有R個(gè)鏈接,一個(gè)鏈接對(duì)應(yīng)一個(gè)字符
鍵隱式地保存在結(jié)點(diǎn)里
TrieST 代碼public class TrieST{ private static int R = 256; // radix private Node root; // root of trie private static class Node { private Object val; private Node[] next = new Node[R]; } public Value get(String key) { Node x = get(root, key, 0); if (x == null) return null; return (Value) x.val; } // Return value associated with key in the subtrie rooted at x. private Node get(Node x, String key, int d) { if (x == null) return null; if (d == key.length()) return x; char c = key.charAt(d); // Use dth key char to identify subtrie. return get(x.next[c], key, d + 1); } public void put(String key, Value val) { root = put(root, key, val, 0); } // Change value associated with key if in subtrie rooted at x. private Node put(Node x, String key, Value val, int d) { //神一般的遞歸思想 if (x == null) x = new Node(); if (d == key.length()) { x.val = val; return x; } char c = key.charAt(d); // Use dth key char to identify subtrie. x.next[c] = put(x.next[c], key, val, d + 1); //神來(lái)之筆 return x; } public Iterable keys() { return keysWithPrefix(""); } public Iterable keysWithPrefix(String pre) { Queue q = new Queue (); collect(get(root, pre, 0), pre, q); return q; } private void collect(Node x, String pre, Queue q) { if (x == null) return; if (x.val != null) q.enqueue(pre); for (char c = 0; c < R; c++) //這個(gè)效率簡(jiǎn)直了。。。爛到爆炸 collect(x.next[c], pre + c, q); } }
方法keys:返回一個(gè)Queue,里面有所有的字符串
方法keysWithPrefix(String pre):返回一個(gè)Queue,里面有所有以給定字符串pre開(kāi)頭的所有字符串
方法collect:遞歸用
通配符匹配
結(jié)構(gòu)差異
不含通配符的結(jié)構(gòu)。keysWithPrefix(); get(); collect();
含通配符的結(jié)構(gòu)。keysWithPrefix(); collect();
為什么結(jié)構(gòu)和之前不一樣呢?因?yàn)間et方法要重寫(xiě)。直接把重寫(xiě)的get方法歸并進(jìn)collect方法里去了。
public IterablekeysThatMatch(String pat) { Queue q = new Queue (); collect(root, "", pat, q); return q; } public void collect(Node x, String pre, String pat, Queue q) { int d = pre.length(); // begin修改于原get方法()和collect方法() if (x == null) // get&collect return; if (d == pat.length() && x.val != null) // 前collect,后get q.enqueue(pre); if (d == pat.length())// get return; // end 修改于原get方法()和collect方法() char next = pat.charAt(d); for (char c = 0; c < R; c++) if (next == "." || next == c) //如果next=="." 就要遍歷接在當(dāng)前字符后面的所有字符!??! collect(x.next[c], pre + c, pat, q); //還是神一般的遞歸想法 }
private Node get(Node x, String key, int d) { if (x == null) return null; if (d == key.length()) return x; char c = key.charAt(d); // Use dth key char to identify subtrie. return get(x.next[c], key, d + 1); }最長(zhǎng)前綴
public String longestPrefixOf(String s) { int length = search(root, s, 0, 0); return s.substring(0, length); } //當(dāng)前搜索的是第d位字符,返回的是具有最長(zhǎng)length位前綴的子字符 private int search(Node x, String s, int d, int length) { if (x == null) // 查到單詞樹(shù)的盡頭了 return length; if (x.val != null) // 如果存在這個(gè)單詞,就更新length值 length = d; if (d == s.length()) // 查到字符串的盡頭了(一定要先做上一步) return length; char c = s.charAt(d); return search(x.next[c], s, d + 1, length); //遞歸搜索下一位 }刪除操作
依舊是神一般的遞歸思路
如果它的鏈接不為空
刪去這個(gè)結(jié)點(diǎn)的值即可
如果它的所有鏈接都為空
刪去這個(gè)結(jié)點(diǎn)
檢查這個(gè)結(jié)點(diǎn)的父結(jié)點(diǎn)的所有鏈接是否為空
不為空,結(jié)束
為空,刪去父結(jié)點(diǎn)并檢查父結(jié)點(diǎn)的父結(jié)點(diǎn)是否為空
……循環(huán)如此
public void delete(String key) { root = delete(root, key, 0); } private Node delete(Node x, String key, int d) { if (x == null) return null; if (d == key.length()) //找到了的話(huà)就將該結(jié)點(diǎn)的值刪去 x.val = null; else { char c = key.charAt(d); x.next[c] = delete(x.next[c], key, d + 1); //依舊是神一般的遞歸思路 } if (x.val != null) //如果該結(jié)點(diǎn)有值,則不管當(dāng)前結(jié)點(diǎn)鏈接是否為空,該結(jié)點(diǎn)都在樹(shù)里,不能被刪去。 return x; for (char c = 0; c < R; c++) //否則就看該結(jié)點(diǎn)鏈接是否為空(即該結(jié)點(diǎn)沒(méi)有值) if (x.next[c] != null) //如果當(dāng)前結(jié)點(diǎn)鏈接不為空,則返回當(dāng)前結(jié)點(diǎn) return x; return null; //否則返回為空。(因?yàn)槭欠祷厣弦粚舆f歸, 即把自己置為空,也即刪除了自己) }復(fù)雜度
字母表大小為R,N個(gè)隨機(jī)鍵組成的單詞查找樹(shù)中
時(shí)間:
查找和插入最差時(shí)間為:鍵的長(zhǎng)度+1
查找未命中的平均時(shí)間為:logRN (查找未命中的時(shí)間和鍵的長(zhǎng)度無(wú)關(guān))
空間
與 R和所有鍵的字符總數(shù)之積 成正比
鏈接
一棵單詞查找樹(shù)的鏈接總數(shù)為RN到RNw之間,w為鍵的平均長(zhǎng)度
當(dāng)所有鍵較短時(shí),鏈接總數(shù)接近RN
當(dāng)所有鍵較長(zhǎng)時(shí),鏈接總數(shù)接近RNw
縮小R能節(jié)省大量空間
三向單詞查找樹(shù)避免空間消耗
每個(gè)結(jié)點(diǎn)含有一個(gè)字符,三個(gè)鏈接(小于,等于,大于),可能含有一個(gè)值
字符是顯式保存在每個(gè)結(jié)點(diǎn)中
TST 代碼public class TST{ private Node root; // root of trie private class Node { char c; // character Node left, mid, right; // left, middle, and right subtries Value val; // value associated with string } public Value get(String key) { Node x = get(root, key, 0); if (x == null) return null; return (Value) x.val; } private Node get(Node x, String key, int d) { if (x == null) return null; char c = key.charAt(d); if (c < x.c) return get(x.left, key, d); else if (c > x.c) return get(x.right, key, d); else if (d < key.length() - 1) return get(x.mid, key, d + 1); else return x; } public void put(String key, Value val) { root = put(root, key, val, 0); } private Node put(Node x, String key, Value val, int d) { char c = key.charAt(d); if (x == null) { x = new Node(); x.c = c; } if (c < x.c) x.left = put(x.left, key, val, d); else if (c > x.c) x.right = put(x.right, key, val, d); else if (d < key.length() - 1) x.mid = put(x.mid, key, val, d + 1); else x.val = val; return x; } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66546.html
摘要:算法圖示代碼復(fù)雜度時(shí)間初始化優(yōu)先隊(duì)列,最壞情況次比較每次操作成本次比較,最多還會(huì)多次和次操作,但這些成本相比的增長(zhǎng)數(shù)量級(jí)可忽略不計(jì)詳見(jiàn)空間 Algorithms Fourth EditionWritten By Robert Sedgewick & Kevin WayneTranslated By 謝路云Chapter 4 Section 3 最小生成樹(shù) 定義 樹(shù)是特殊的圖 圖的生...
摘要:在實(shí)際的測(cè)試中,算法的運(yùn)行效率也比算法高左右。此外,該算法與求無(wú)向圖的雙連通分量割點(diǎn)橋的算法也有著很深的聯(lián)系。學(xué)習(xí)該算法,也有助于深入理解求雙連通分量的算法,兩者可以類(lèi)比組合理解。固屬于同一連通分支。 參考資料http://blog.csdn.net/acmmmm/a...https://www.byvoid.com/blog/s...http://blog.csdn.net/noth...
摘要:由的位置決定乘以幾,依次為,,,,,。遞歸算法遞歸算法就是本次結(jié)果用另外的參數(shù)調(diào)用自己。然而這個(gè)函數(shù)方法本身并沒(méi)有用,因?yàn)榉椒ㄖ腥魝鬟f參數(shù)為基本型如,在方法中對(duì)其值的改變并不會(huì)在主函數(shù)中產(chǎn)生影響。 Algorithms Fourth EditionWritten By Robert Sedgewick & Kevin WayneTranslated By 謝路云 筆記 二分查找 Bin...
摘要:相關(guān)操作就是判斷的不等號(hào)符號(hào)改反,初始值設(shè)為負(fù)無(wú)窮副本的最短路徑即為原圖的最長(zhǎng)路徑。方法是同上面一樣構(gòu)造圖,同時(shí)會(huì)添加負(fù)權(quán)重邊,再將所有邊取反,然后求最短路徑最短路徑存在則可行沒(méi)有負(fù)權(quán)重環(huán)就是可行的調(diào)度。 Algorithms Fourth EditionWritten By Robert Sedgewick & Kevin WayneTranslated By 謝路云Chapter ...
閱讀 1423·2021-09-23 11:21
閱讀 3119·2019-08-30 14:14
閱讀 3205·2019-08-30 13:56
閱讀 4156·2019-08-30 11:20
閱讀 1961·2019-08-29 17:23
閱讀 2778·2019-08-29 16:14
閱讀 1708·2019-08-28 18:18
閱讀 1499·2019-08-26 12:14