《算法》第六章部分程序 part 2

▶ 书中第六章部分程序,包括在加上自己补充的代码,B-树

● B-树

  1 package package01;
  2 
  3 import edu.princeton.cs.algs4.StdOut;
  4 
  5 public class class01<Key extends Comparable<Key>, Value>
  6 {
  7     private static final int M = 4; // 子节点数量为 M-1
  8 
  9     private Node root;                              // 根节点
 10     private int height;                             // 树高
 11     private int n;                                  // 键值对的数量
 12 
 13     private static final class Node                 // 节点类
 14     {
 15         private int m;                              // 当前子节点数量
 16         private Entry[] children = new Entry[M];    // 子节点列表
 17 
 18         private Node(int k)                         // 构造有 k 个子节点的节点
 19         {
 20             m = k;
 21         }
 22     }
 23 
 24     private static class Entry                      // 子节点列表类,内部结点使用 key 和 next,外部节点使用 key 和 value
 25     {
 26         private Comparable key;
 27         private Node next;
 28         private final Object val;
 29 
 30         public Entry(Comparable inputKey, Object inputVal, Node inputNext)
 31         {
 32             key = inputKey;
 33             next = inputNext;
 34             val = inputVal;
 35         }
 36     }
 37 
 38     public class01()
 39     {
 40         root = new Node(0);
 41     }
 42 
 43     public int size()
 44     {
 45         return n;
 46     }
 47 
 48     public boolean isEmpty()
 49     {
 50         return size() == 0;
 51     }
 52 
 53     public int height()
 54     {
 55         return height;
 56     }
 57 
 58     public Value get(Key key)
 59     {
 60         if (key == null)
 61             throw new IllegalArgumentException("\n<get> key == null.\n");
 62         return search(root, key, height);
 63     }
 64 
 65     private Value search(Node x, Key key, int ht)   // 穿如数奉告,每次进入更深层时减一
 66     {
 67         Entry[] children = x.children;
 68         if (ht == 0)                                // 到达的是叶节点,遍历列表
 69         {
 70             for (int j = 0; j < x.m; j++)
 71             {
 72                 if (eq(key, children[j].key))       // 找到了,返回 val
 73                     return (Value)children[j].val;
 74             }
 75         }
 76         else                                        // 到达的是内部节点
 77         {
 78             for (int j = 0; j < x.m; j++)
 79             {
 80                 if (j == x.m - 1 || less(key, children[j + 1].key))         // j 到达最后或找到合适的子节点,进入下一层
 81                     return search(children[j].next, key, ht - 1);
 82             }
 83         }
 84         return null;
 85     }
 86 
 87     public void put(Key key, Value val)
 88     {
 89         if (key == null)
 90             throw new IllegalArgumentException("\n<put> key == null.\n");
 91         Node u = insert(root, key, val, height);                            // 执行插入插座并调整总键值对数量
 92         n++;
 93         if (u == null)                                                      // 没有需要调整的节点
 94             return;
 95         Node t = new Node(2);                                               // 根节点需要分裂,新建一个具有 2 个子节点的节点
 96         t.children[0] = new Entry(root.children[0].key, null, root);        // 第一个子节点是原来的根节点
 97         t.children[1] = new Entry(u.children[0].key, null, u);              // 第二个子节点是插入操作导致新增加的节点
 98         root = t;                                                           // root 编程新建的 t,并增加一层树高
 99         height++;
100     }
101 
102     private Node insert(Node h, Key key, Value val, int ht)
103     {
104         int j;
105         Entry t = new Entry(key, val, null);
106         if (ht == 0)                                                        // 到达的是外部节点
107         {
108             for (j = 0; j < h.m; j++)
109             {
110                 if (less(key, h.children[j].key))                           // 找到合适的位置就脱出循环
111                     break;
112             }
113         }
114         else                                                                // 到达的是内部节点
115         {
116             for (j = 0; j < h.m; j++)
117             {
118                 if ((j + 1 == h.m) || less(key, h.children[j + 1].key))     // j 到达最后或找到合适的子节点,进入下一层
119                 {
120                     Node u = insert(h.children[j++].next, key, val, ht - 1);// 在 h.children[j] 进行插入
121                     if (u == null)
122                         return null;
123                     t.key = u.children[0].key;                              // 把 u 的信息改造到 t 上
124                     t.next = u;                                             // 真正 next 是在这里赋值的,指向下一个子节点
125                     break;
126                 }
127             }
128         }                                                
129         for (int i = h.m; i > j; i--)               // 调整本层,排在插入位置之后的元素都向后移动一格
130             h.children[i] = h.children[i - 1];
131         h.children[j] = t;                          // 插入节点 t,增加 h 的子节点数量
132         h.m++;
133         return (h.m < M) ? null : split(h);         // 节点 h 满了就需要扩容,返回扩容后多出来的节点,用于上一层调整
134     }
135 
136     private Node split(Node h)                      // 分裂节点 h,并返回分裂出来的后一半节点
137     {
138         Node t = new Node(M / 2);
139         h.m = M / 2;                                // 改 h 的子节点数为一半,相当于废弃后一半记录
140         for (int j = 0; j < M / 2; j++)             // 后一半元素搬进 t
141             t.children[j] = h.children[M / 2 + j];
142         return t;
143     }
144 
145     public String toString()
146     {
147         return toStringKernel(root, height, "") + "\n";
148     }
149 
150     private String toStringKernel(Node h, int ht, String indent)                    // 遍历树转化为字符串
151     {
152         StringBuilder s = new StringBuilder();
153         Entry[] children = h.children;
154         if (ht == 0)                                                                // 叶节点,输出
155         {
156             for (int j = 0; j < h.m; j++)
157                 s.append(indent + children[j].key + " " + children[j].val + "\n");  // 注意换行
158         }
159         else                                                                        // 非叶节点,遍历子节点列表
160         {
161             for (int j = 0; j < h.m; j++)
162             {
163                 if (j > 0)
164                     s.append(indent + "(" + children[j].key + ")\n");
165                 s.append(toStringKernel(children[j].next, ht - 1, indent + "     "));
166             }
167         }
168         return s.toString();
169     }
170 
171     private boolean less(Comparable k1, Comparable k2)
172     {
173         return k1.compareTo(k2) < 0;
174     }
175 
176     private boolean eq(Comparable k1, Comparable k2)
177     {
178         return k1.compareTo(k2) == 0;
179     }
180 
181     public static void main(String[] args)                                          // 输入一堆网站和 IP 建立 B-树
182     {
183         class01<String, String> st = new class01<String, String>();
184 
185         st.put("www.cs.princeton.edu", "128.112.136.12");
186         st.put("www.cs.princeton.edu", "128.112.136.11");
187         st.put("www.princeton.edu", "128.112.128.15");
188         st.put("www.yale.edu", "130.132.143.21");
189         st.put("www.simpsons.com", "209.052.165.60");
190         st.put("www.apple.com", "17.112.152.32");
191         st.put("www.amazon.com", "207.171.182.16");
192         st.put("www.ebay.com", "66.135.192.87");
193         st.put("www.cnn.com", "64.236.16.20");
194         st.put("www.google.com", "216.239.41.99");
195         st.put("www.nytimes.com", "199.239.136.200");
196         st.put("www.microsoft.com", "207.126.99.140");
197         st.put("www.dell.com", "143.166.224.230");
198         st.put("www.slashdot.org", "66.35.250.151");
199         st.put("www.espn.com", "199.181.135.201");
200         st.put("www.weather.com", "63.111.66.11");
201         st.put("www.yahoo.com", "216.109.118.65");
202 
203         StdOut.println("cs.princeton.edu:  " + st.get("www.cs.princeton.edu"));
204         StdOut.println("hardvardsucks.com: " + st.get("www.harvardsucks.com"));
205         StdOut.println("simpsons.com:      " + st.get("www.simpsons.com"));
206         StdOut.println("apple.com:         " + st.get("www.apple.com"));
207         StdOut.println("ebay.com:          " + st.get("www.ebay.com"));
208         StdOut.println("dell.com:          " + st.get("www.dell.com"));
209         StdOut.println();
210 
211         StdOut.println("size:    " + st.size());
212         StdOut.println("height:  " + st.height());
213         StdOut.println(st);
214         StdOut.println();
215     }
216 }

● 测试函输出,即生成的树

cs.princeton.edu:  128.112.136.12
hardvardsucks.com: null
simpsons.com:      209.052.165.60
apple.com:         17.112.152.32
ebay.com:          66.135.192.87
dell.com:          143.166.224.230

size:    17
height:  2
          www.amazon.com 207.171.182.16
          www.apple.com 17.112.152.32
          www.cnn.com 64.236.16.20
     (www.cs.princeton.edu)
          www.cs.princeton.edu 128.112.136.12
          www.cs.princeton.edu 128.112.136.11
          www.dell.com 143.166.224.230
(www.ebay.com)
          www.ebay.com 66.135.192.87
          www.espn.com 199.181.135.201
          www.google.com 216.239.41.99
     (www.microsoft.com)
          www.microsoft.com 207.126.99.140
          www.nytimes.com 199.239.136.200
(www.princeton.edu)
          www.princeton.edu 128.112.128.15
          www.simpsons.com 209.052.165.60
     (www.slashdot.org)
          www.slashdot.org 66.35.250.151
          www.weather.com 63.111.66.11
     (www.yahoo.com)
          www.yahoo.com 216.109.118.65
          www.yale.edu 130.132.143.21

猜你喜欢

转载自www.cnblogs.com/cuancuancuanhao/p/9945076.html
今日推荐