zoukankan      html  css  js  c++  java
  • 《算法》第五章部分程序 part 4

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,Trie 树类,Trie 集合,三值搜索树(Ternary Search Trie)

    ● Trie 树类

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdIn;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.Queue;
      6 
      7 public class class01<Value>
      8 {
      9     private static final int R = 256;   // 扩展 ASCII
     10 
     11     private Node root;
     12     private int n;                      // 总节点数
     13 
     14     private static class Node           // 节点类,含当前节点代表的值,以及 R 路支链
     15     {
     16         private Object val;
     17         private Node[] next = new Node[R];
     18     }
     19 
     20     public class01() {}
     21 
     22     public boolean contains(String key)
     23     {
     24         if (key == null)
     25             throw new IllegalArgumentException("
    <contains> key == null.
    ");
     26         return get(key) != null;
     27     }
     28 
     29     public Value get(String key)
     30     {
     31         if (key == null)
     32             throw new IllegalArgumentException("
    <get> key == null.
    ");
     33         Node x = getKernel(root, key, 0);
     34         return (x == null) ? null : (Value)x.val;       // 找到了就返回,没找到返回 null
     35     }
     36 
     37     private Node getKernel(Node x, String key, int d)   // 注意返回的是节点,与 get 不同
     38     {
     39         if (x == null)                                  // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归
     40             return null;
     41         if (d == key.length())
     42             return x;
     43         return getKernel(x.next[key.charAt(d)], key, d + 1);
     44     }
     45 
     46     public void put(String key, Value val)
     47     {
     48         if (key == null)
     49             throw new IllegalArgumentException("
    <put> key == null.
    ");
     50         if (val == null)
     51             delete(key);
     52         else
     53             root = putKernel(root, key, val, 0);
     54     }
     55 
     56     private Node putKernel(Node x, String key, Value val, int d)
     57     {
     58         if (x == null)                  // 先判断当前节点是否为空,再判断是否到达搜索终点,然后考虑递归
     59             x = new Node();
     60         if (d == key.length())
     61         {
     62             if (x.val == null)          // 节点为空,节点数 +1
     63                 n++;
     64             x.val = val;                // 赋上新值
     65         }
     66         else
     67         {
     68             char c = key.charAt(d);
     69             x.next[c] = putKernel(x.next[c], key, val, d + 1);
     70         }
     71         return x;
     72     }
     73 
     74     public int size()
     75     {
     76         return n;
     77     }
     78 
     79     public boolean isEmpty()
     80     {
     81         return size() == 0;
     82     }
     83 
     84     public Iterable<String> keys()                              // 生成所有键的迭代器(遍历)
     85     {
     86         return keyPrefix("");
     87     }
     88 
     89     public Iterable<String> keyPrefix(String prefix)            // 生成具有给定前缀的所有键的迭代器
     90     {
     91         Queue<String> results = new Queue<String>();
     92         Node x = getKernel(root, prefix, 0);                    // 先抵达前缀结束时的搜索节点
     93         collectPrefix(x, new StringBuilder(prefix), results);   // 在此基础上遍历并放入迭代器
     94         return results;
     95     }
     96 
     97     private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results)   // 遍历 x 为根节点的表,prefix 用来生成结果的,不参与遍历
     98     {
     99         if (x == null)
    100             return;
    101         if (x.val != null)
    102             results.enqueue(prefix.toString());                 // 除了给定前缀,没有多余字符的情况
    103         for (char c = 0; c < R; c++)                            // 每次循环尝试添加一个字符,遍历子节点,然后删掉
    104         {
    105             prefix.append(c);
    106             collectPrefix(x.next[c], prefix, results);
    107             prefix.deleteCharAt(prefix.length() - 1);
    108         }
    109     }
    110 
    111     public Iterable<String> keyPattern(String pattern)          // 生成具有给定模式的所有键的迭代器
    112     {
    113         Queue<String> results = new Queue<String>();
    114         collectPattern(root, new StringBuilder(), pattern, results);
    115         return results;
    116     }
    117 
    118     private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results)
    119     {
    120         if (x == null)
    121             return;
    122         int d = prefix.length();
    123         if (d == pattern.length())                              // 已经到了模式的尽头
    124         {
    125             if (x.val != null)
    126                 results.enqueue(prefix.toString());
    127             return;
    128         }
    129         char c = pattern.charAt(d);
    130         if (c == '.')
    131         {
    132             for (char ch = 0; ch < R; ch++)                     // 模式是 '.',像 collectPrefix 那样尝试添加每一个字符来遍历子节点,然后删掉
    133             {
    134                 prefix.append(ch);
    135                 collectPattern(x.next[ch], prefix, pattern, results);
    136                 prefix.deleteCharAt(prefix.length() - 1);
    137             }
    138         }
    139         else                                                    // 否则只添加确定的字符,遍历其子节点,之后也要删掉
    140         {
    141             prefix.append(c);
    142             collectPattern(x.next[c], prefix, pattern, results);
    143             prefix.deleteCharAt(prefix.length() - 1);
    144         }
    145     }
    146 
    147     public String longestPrefixOf(String query)                 // 找出与给定串有相同前缀的键的最大长度
    148     {
    149         if (query == null)
    150             throw new IllegalArgumentException("
    <longestPrefixOf> query == null.
    ");
    151         int length = longestPrefixOfKernel(root, query, 0, -1);
    152         if (length == -1)
    153             return null;
    154         return query.substring(0, length);
    155     }
    156 
    157     private int longestPrefixOfKernel(Node x, String query, int d, int length)
    158     {
    159         if (x == null)
    160             return length;
    161         if (x.val != null)
    162             length = d;
    163         if (d == query.length())
    164             return length;
    165         return longestPrefixOfKernel(x.next[query.charAt(d)], query, d + 1, length);
    166     }
    167 
    168     public void delete(String key)
    169     {
    170         if (key == null)
    171             throw new IllegalArgumentException("
    <delete> key == null.
    ");
    172         root = deleteKernel(root, key, 0);
    173     }
    174 
    175     private Node deleteKernel(Node x, String key, int d)        // 删除节点
    176     {
    177         if (x == null)
    178             return null;
    179         if (d == key.length())                                  // 到达对应深度
    180         {
    181             if (x.val != null)                                  // 目标节点存在,总结点数 -1
    182                 n--;
    183             x.val = null;
    184         }
    185         else                                                    // 还没达到对应深度,继续下潜
    186         {
    187             char c = key.charAt(d);
    188             x.next[c] = deleteKernel(x.next[c], key, d + 1);
    189         }
    190         if (x.val != null)                                      // 返回途中,发现盖层 x 还没有被删,返回 x
    191             return x;
    192         for (int c = 0; c < R; c++)                             // x 已经被删,但是 x 还有子节点
    193         {
    194             if (x.next[c] != null)
    195                 return x;
    196         }
    197         return null;                                            // x 已经被删,且没有子节点,返回 null
    198     }
    199 
    200     public static void main(String[] args)
    201     {
    202         class01<Integer> st = new class01<Integer>();
    203         for (int i = 0; !StdIn.isEmpty(); i++)                  // 输入键
    204             st.put(StdIn.readString(), i);
    205         if (st.size() < 100)                                    // 输出保存的键
    206         {
    207             StdOut.println("keys(""):");
    208             for (String key : st.keys())
    209                 StdOut.println(key + " " + st.get(key));
    210             StdOut.println();
    211         }
    212 
    213         StdOut.println("longestPrefixOf("shellsort"):");
    214         StdOut.println(st.longestPrefixOf("shellsort"));
    215         StdOut.println();
    216 
    217         StdOut.println("longestPrefixOf("quicksort"):");
    218         StdOut.println(st.longestPrefixOf("quicksort"));
    219         StdOut.println();
    220 
    221         StdOut.println("keyPrefix("shor"):");
    222         for (String s : st.keyPrefix("shor"))
    223             StdOut.println(s);
    224         StdOut.println();
    225 
    226         StdOut.println("keyPattern(".he.l."):");
    227         for (String s : st.keyPattern(".he.l."))
    228             StdOut.println(s);
    229     }
    230 }

    ● Trie 集合

      1 package package01;
      2 
      3 import java.util.Iterator;
      4 import edu.princeton.cs.algs4.StdIn;
      5 import edu.princeton.cs.algs4.StdOut;
      6 import edu.princeton.cs.algs4.Queue;
      7 
      8 public class class01 implements Iterable<String>// 需要 string 的迭代器
      9 {
     10     private static final int R = 256;
     11 
     12     private Node root;
     13     private int n;
     14 
     15     private static class Node
     16     {
     17         private boolean isString;          // 是否存在以当前节点为结尾的键
     18         private Node[] next = new Node[R];
     19     }
     20 
     21     public class01() {}
     22 
     23     public boolean contains(String key)
     24     {
     25         if (key == null)
     26             throw new IllegalArgumentException("
    <contains> key == null.
    ");
     27         Node x = get(root, key, 0);
     28         return (x == null) ? false : x.isString;// 是否为空的判断方式不同
     29     }
     30 
     31     private Node get(Node x, String key, int d) // 没有 get 和 getKernel 的区分
     32     {
     33         if (x == null)
     34             return null;
     35         if (d == key.length())
     36             return x;
     37         return get(x.next[key.charAt(d)], key, d + 1);
     38     }
     39 
     40     public void put(String key)// 少了 val 参数
     41     {
     42         if (key == null)
     43             throw new IllegalArgumentException("
    <put> key == null.
    ");
     44         root = putKernel(root, key, 0);
     45     }
     46 
     47     private Node putKernel(Node x, String key, int d)
     48     {
     49         if (x == null)
     50             x = new Node();
     51         if (d == key.length())
     52         {
     53             if (!x.isString) // 是否为空的判断条件不同
     54                 n++;
     55             x.isString = true;
     56         }
     57         else
     58         {
     59             char c = key.charAt(d);
     60             x.next[c] = putKernel(x.next[c], key, d + 1);
     61         }
     62         return x;
     63     }
     64 
     65     public int size()
     66     {
     67         return n;
     68     }
     69 
     70     public boolean isEmpty()
     71     {
     72         return size() == 0;
     73     }
     74 
     75     public Iterator<String> iterator() // 不是 Iterable,Iterator
     76     {
     77         return keyPrefix("").iterator();
     78     }
     79 
     80     public Iterable<String> keyPrefix(String prefix)
     81     {
     82         Queue<String> results = new Queue<String>();
     83         Node x = get(root, prefix, 0);
     84         collectPrefix(x, new StringBuilder(prefix), results);
     85         return results;
     86     }
     87 
     88     private void collectPrefix(Node x, StringBuilder prefix, Queue<String> results)
     89     {
     90         if (x == null)
     91             return;
     92         if (x.isString)
     93             results.enqueue(prefix.toString());
     94         for (char c = 0; c < R; c++)
     95         {
     96             prefix.append(c);
     97             collectPrefix(x.next[c], prefix, results);
     98             prefix.deleteCharAt(prefix.length() - 1);
     99         }
    100     }
    101 
    102     public Iterable<String> keyPattern(String pattern)
    103     {
    104         Queue<String> results = new Queue<String>();
    105         collectPattern(root, new StringBuilder(), pattern, results);
    106         return results;
    107     }
    108 
    109     private void collectPattern(Node x, StringBuilder prefix, String pattern, Queue<String> results)
    110     {
    111         if (x == null)
    112             return;
    113         int d = prefix.length();
    114         if (d == pattern.length())
    115         {
    116             if (x.isString)
    117                 results.enqueue(prefix.toString());
    118             return;
    119         }
    120         char c = pattern.charAt(d);
    121         if (c == '.')
    122         {
    123             for (char ch = 0; ch < R; ch++)
    124             {
    125                 prefix.append(ch);
    126                 collectPattern(x.next[ch], prefix, pattern, results);
    127                 prefix.deleteCharAt(prefix.length() - 1);
    128             }
    129         }
    130         else
    131         {
    132             prefix.append(c);
    133             collectPattern(x.next[c], prefix, pattern, results);
    134             prefix.deleteCharAt(prefix.length() - 1);
    135         }
    136     }
    137 
    138     public String longestPrefixOf(String query)
    139     {
    140         if (query == null)
    141             throw new IllegalArgumentException("
    <longestPrefixOf> query == null.
    ");
    142         int length = longestPrefixOfKernel(root, query, 0, -1);
    143         if (length == -1)
    144             return null;
    145         return query.substring(0, length);
    146     }
    147 
    148     private int longestPrefixOfKernel(Node x, String query, int d, int length)
    149     {
    150         if (x == null)
    151             return length;
    152         if (x.isString)
    153             length = d;
    154         if (d == query.length())
    155             return length;
    156         return longestPrefixOfKernel(x.next[query.charAt(d)], query, d+1, length);
    157     }
    158 
    159     public void delete(String key)
    160     {
    161         if (key == null)
    162             throw new IllegalArgumentException("
    <delete> key == null.
    ");
    163         root = deleteKernel(root, key, 0);
    164     }
    165 
    166     private Node deleteKernel(Node x, String key, int d)
    167     {
    168         if (x == null)
    169             return null;
    170         if (d == key.length())
    171         {
    172             if (x.isString)
    173                 n--;
    174             x.isString = false;
    175         }
    176         else
    177         {
    178             char c = key.charAt(d);
    179             x.next[c] = deleteKernel(x.next[c], key, d+1);
    180         }
    181         if (x.isString)
    182             return x;
    183         for (int c = 0; c < R; c++)
    184         {
    185             if (x.next[c] != null)
    186                 return x;
    187         }
    188         return null;
    189     }
    190 
    191     public static void main(String[] args)
    192     {
    193         class01 st = new class01();
    194         for (; !StdIn.isEmpty(); st.put(StdIn.readString()));
    195         if (st.size() < 100)
    196         {
    197             StdOut.println("keys(""):");
    198             for (String key : st)
    199                 StdOut.println(key);
    200             StdOut.println();
    201         }
    202 
    203         StdOut.println("longestPrefixOf("shellsort"):");
    204         StdOut.println(st.longestPrefixOf("shellsort"));
    205         StdOut.println();
    206 
    207         StdOut.println("longestPrefixOf("xshellsort"):");
    208         StdOut.println(st.longestPrefixOf("xshellsort"));
    209         StdOut.println();
    210 
    211         StdOut.println("keyPrefix("shor"):");
    212         for (String s : st.keyPrefix("shor"))
    213             StdOut.println(s);
    214         StdOut.println();
    215 
    216         StdOut.println("keyPrefix("shortening"):");
    217         for (String s : st.keyPrefix("shortening"))
    218             StdOut.println(s);
    219         StdOut.println();
    220 
    221         StdOut.println("keyPattern(".he.l."):");
    222         for (String s : st.keyPattern(".he.l."))
    223             StdOut.println(s);
    224     }
    225 }

    ● 三值搜索树

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdIn;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.Queue;
      6 
      7 public class class01<Value>
      8 {
      9     private Node<Value> root;
     10     private int n;
     11 
     12     private static class Node<Value>
     13     {
     14         private char c;
     15         private Node<Value> left, mid, right;
     16         private Value val;
     17     }
     18 
     19     public class01() {}
     20 
     21     public boolean contains(String key)
     22     {
     23         if (key == null)
     24             throw new IllegalArgumentException("
    <contains> key == null.
    ");
     25         return get(key) != null;
     26     }
     27 
     28     public Value get(String key)
     29     {
     30         if (key == null || key.length() == 0)
     31             throw new IllegalArgumentException("
    <get> key == null || key.length() == 0.
    ");
     32         Node<Value> x = getKernel(root, key, 0);
     33         return (x == null) ? null : x.val;
     34     }
     35 
     36     private Node<Value> getKernel(Node<Value> x, String key, int d)
     37     {
     38         if (x == null)
     39             return null;
     40         char c = key.charAt(d);
     41         if (c < x.c)
     42             return getKernel(x.left, key, d);       // 向左右搜索的时候深度不变
     43         if (c > x.c)
     44             return getKernel(x.right, key, d);
     45         if (d < key.length() - 1)
     46             return getKernel(x.mid, key, d + 1);    // 向中路搜索的时候深度要变化
     47         return x;
     48     }
     49 
     50     public void put(String key, Value val)
     51     {
     52         if (key == null)
     53             throw new IllegalArgumentException("
    <put> key == null.
    ");
     54         if (!contains(key))
     55             n++;
     56         root = putKernel(root, key, val, 0);
     57     }
     58 
     59     private Node<Value> putKernel(Node<Value> x, String key, Value val, int d)
     60     {
     61         char c = key.charAt(d);
     62         if (x == null)
     63         {
     64             x = new Node<Value>();
     65             x.c = c;
     66         }
     67         if (c < x.c)
     68             x.left = putKernel(x.left, key, val, d);
     69         else if (c > x.c)
     70             x.right = putKernel(x.right, key, val, d);
     71         else if (d < key.length() - 1)
     72             x.mid = putKernel(x.mid, key, val, d + 1);
     73         else
     74             x.val = val;
     75         return x;
     76     }
     77 
     78     public int size()
     79     {
     80         return n;
     81     }
     82 
     83     public boolean isEmpty()
     84     {
     85         return size() == 0;
     86     }
     87 
     88     public Iterable<String> keys()  // 需要直接从前缀中去字符参加比较,不能用 keyPrefix("")
     89     {
     90         Queue<String> queue = new Queue<String>();
     91         collectPrefix(root, new StringBuilder(), queue);
     92         return queue;
     93     }
     94 
     95     public Iterable<String> keyPrefix(String prefix)
     96     {
     97         Queue<String> queue = new Queue<String>();
     98         Node<Value> x = getKernel(root, prefix, 0);
     99         if (x == null)
    100             return queue;
    101         if (x.val != null)
    102             queue.enqueue(prefix);
    103         collectPrefix(x.mid, new StringBuilder(prefix), queue);
    104         return queue;
    105     }
    106 
    107     private void collectPrefix(Node<Value> x, StringBuilder prefix, Queue<String> queue)
    108     {
    109         if (x == null)
    110             return;
    111         collectPrefix(x.left, prefix, queue);
    112         if (x.val != null)
    113             queue.enqueue(prefix.toString() + x.c);
    114         collectPrefix(x.mid, prefix.append(x.c), queue);
    115         prefix.deleteCharAt(prefix.length() - 1);
    116         collectPrefix(x.right, prefix, queue);
    117     }
    118 
    119     public Iterable<String> keyPattern(String pattern)
    120     {
    121         Queue<String> queue = new Queue<String>();
    122         collectPattern(root, new StringBuilder(), 0, pattern, queue);
    123         return queue;
    124     }
    125 
    126     private void collectPattern(Node<Value> x, StringBuilder prefix, int i, String pattern, Queue<String> queue)
    127     {
    128         if (x == null)
    129             return;
    130         char c = pattern.charAt(i);
    131         if (c == '.' || c < x.c)                                // 分解为 c 和 x.c 的三种情况,插上 '.' 的情况
    132             collectPattern(x.left, prefix, i, pattern, queue);
    133         if (c == '.' || c == x.c)
    134         {
    135             if (i == pattern.length() - 1 && x.val != null)
    136                 queue.enqueue(prefix.toString() + x.c);
    137             if (i < pattern.length() - 1)
    138             {
    139                 collectPattern(x.mid, prefix.append(x.c), i + 1, pattern, queue);
    140                 prefix.deleteCharAt(prefix.length() - 1);
    141             }
    142         }
    143         if (c == '.' || c > x.c)
    144             collectPattern(x.right, prefix, i, pattern, queue);
    145     }
    146 
    147     public String longestPrefixOf(String query)
    148     {
    149         if (query == null || query.length() == 0)
    150             throw new IllegalArgumentException("
    <longestPrefixOf> query == null || query.length() == 0.
    ");
    151         int length = 0;
    152         Node<Value> x = root;
    153         for (int i = 0; x != null && i < query.length();)       // i 为当前匹配的长度
    154         {
    155             char c = query.charAt(i);
    156             if (c < x.c)
    157                 x = x.left;
    158             else if (c > x.c)
    159                 x = x.right;
    160             else
    161             {
    162                 i++;
    163                 if (x.val != null)
    164                     length = i;
    165                 x = x.mid;
    166             }
    167         }
    168         return query.substring(0, length);
    169     }
    170 
    171     public static void main(String[] args)
    172     {
    173         class01<Integer> st = new class01<Integer>();
    174         for (int i = 0; !StdIn.isEmpty(); i++)
    175         {
    176             String key = StdIn.readString();
    177             st.put(key, i);
    178         }
    179 
    180         if (st.size() < 100)
    181         {
    182             StdOut.println("keys(""):");
    183             for (String key : st.keys())
    184                 StdOut.println(key + " " + st.get(key));
    185             StdOut.println();
    186         }
    187 
    188         StdOut.println("longestPrefixOf("shellsort"):");
    189         StdOut.println(st.longestPrefixOf("shellsort"));
    190         StdOut.println();
    191 
    192         StdOut.println("longestPrefixOf("shell"):");
    193         StdOut.println(st.longestPrefixOf("shell"));
    194         StdOut.println();
    195 
    196         StdOut.println("keysWithPrefix("shor"):");
    197         for (String s : st.keyPrefix("shor"))
    198             StdOut.println(s);
    199         StdOut.println();
    200 
    201         StdOut.println("keysThatMatch(".he.l."):");
    202         for (String s : st.keyPattern(".he.l."))
    203             StdOut.println(s);
    204     }
    205 }
  • 相关阅读:
    ubuntu下如何更改mysql数据存放路径
    collection_select
    发现星期六日的电视比较好看
    rails
    系统抢救10.04
    劫后重生,痛定思痛,ubuntu 10.04=>10.10
    随机查询N条记录
    which linux your like
    kindeditor的使用
    array
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9869294.html
Copyright © 2011-2022 走看看