1、二叉查找树

  1. package search;
  2. import javax.swing.*;
  3. /**
  4. * @author zwlstart
  5. * @create 2020-12-26 20:55
  6. */
  7. public class BinerySearchTree {
  8. //返回树的全部节点数量
  9. private int size(Node x){
  10. if (x == null){
  11. return 0;
  12. }else{
  13. return x.n;
  14. }
  15. }
  16. //查找一个节点
  17. public Node get(Node x,int v){
  18. if (x == null){
  19. return null;
  20. }
  21. int i = x.val - v;
  22. if (i == 0){
  23. return x;
  24. }else if (i > 0){
  25. return get(x.left,v);
  26. }else{
  27. return get(x.right,v);
  28. }
  29. }
  30. //插入一个节点
  31. public Node put(Node x,int v){
  32. if (x == null){
  33. return new Node(v,1);
  34. }
  35. int i = x.val - v;
  36. if (i == 0){
  37. x.val = v;
  38. }else if (i > 0){
  39. x.left = put(x.left,v);
  40. }else{
  41. x.right = put(x.right,v);
  42. }
  43. x.n = size(x.left) + size(x.right) + 1;
  44. return x;
  45. }
  46. //查找第i个节点
  47. public int search(Node root,int i){
  48. if (root == null || i > size(root) || i < 0){
  49. return -1;
  50. }
  51. int size = size(root.left);
  52. if (size > i){
  53. return search(root.left,i);
  54. }else if(size < i){
  55. return search(root.right,i - size - 1);
  56. }else {
  57. return root.val;
  58. }
  59. }
  60. /**
  61. * 给定一个数,然后二叉树中节点值小于此数的节点数目
  62. * @param v
  63. * @return
  64. */
  65. public int rank(Node x,int v){
  66. if (x == null){
  67. return -1;
  68. }
  69. int i = x.val - v;
  70. if (i == 0){
  71. return size(x.left);
  72. }else if (i > 0){
  73. return rank(x.left,v);
  74. }else{
  75. return size(x.left) + 1 + rank(x.right,v);
  76. }
  77. }
  78. /**
  79. * 删除树中的最小值
  80. * @param root
  81. * @return
  82. */
  83. public Node deleteMin(Node root){
  84. if (root.left == null){
  85. return root.right;
  86. }
  87. root.left = deleteMin(root.left);
  88. root.n = size(root.left) + size(root.right) + 1;
  89. return root;
  90. }
  91. /**
  92. * 删除指定的值,分为三种情况,当该节点只有一个子节点时,直接删除即可,让该节点的指针
  93. * 指向唯一的子节点
  94. * 如果该节点有两个孩子,则不能直接删除,需要找到该节点的直接后继或直接前继节点然后再删除
  95. * 可分为四步:
  96. * 1、找到后续节点
  97. * 2、该节点指向后续节点
  98. * 3、删除后续节点
  99. * 4、后续的节点的左右孩子指向原节点的左右孩子节点
  100. * @param root
  101. * @param v
  102. * @return
  103. */
  104. public Node delete(Node root, int v){
  105. if (root == null){
  106. return null;
  107. }
  108. int i = root.val - v;
  109. if (i > 0){
  110. root.left = delete(root.left,v);
  111. }else if (i < 0){
  112. root.right = delete(root.right,v);
  113. }else{
  114. if (root.left == null){
  115. return root.right;
  116. }
  117. if (root.right == null){
  118. return root.left;
  119. }
  120. Node temp = root;
  121. root = searchMin(root.right);
  122. //这一步必须在前,否则删除的会有问题,
  123. //如果先执行 root.left = temp.left; 这步,则会将原本temp.left挂载到root.left上,
  124. //此时root还是temp.right子树上的最小节点,再执行root.right = deleteMin(temp.right);
  125. //删除的就不是temp了
  126. root.right = deleteMin(temp.right);
  127. root.left = temp.left;
  128. }
  129. root.n = size(root.right) + size(root.left) + 1;
  130. return root;
  131. }
  132. private Node searchMin(Node node) {
  133. while (node.left != null){
  134. node = node.left;
  135. }
  136. return node;
  137. }
  138. public BinerySearchTree() {
  139. }
  140. }

2、avl树的实现

  1. package search;
  2. import javax.swing.*;
  3. /**
  4. * @author zwlstart
  5. * @create 2020-12-28 10:45
  6. */
  7. public class AVL {
  8. /**
  9. * 返回以该节点为根的树高度
  10. */
  11. public int height(AvlNode x){
  12. if (x == null){
  13. return 0;
  14. }
  15. return x.height;
  16. }
  17. /**
  18. * 插入一个节点
  19. */
  20. public AvlNode put(AvlNode x,int value){
  21. if (x == null){
  22. return new AvlNode(value,1);
  23. }
  24. int i = x.val - value;
  25. if (i > 0){
  26. x.left = put(x.left,value);
  27. }else if (i < 0){
  28. x.right = put(x.right,value);
  29. }else {
  30. x.val = value;
  31. }
  32. if (height(x.left) - height(x.right) > 1){
  33. if (height(x.left.left) > height(x.left.right)){
  34. x = rotatlRight(x);
  35. }else{
  36. x.left = rotatlLeft(x.left);
  37. x = rotatlRight(x);
  38. }
  39. }else if (height(x.left) - height(x.right) < -1) {
  40. if (height(x.right.right) < height(x.right.left)){
  41. x = rotatlLeft(x);
  42. }else{
  43. x.right = rotatlRight(x.right);
  44. x = rotatlLeft(x);
  45. }
  46. }
  47. x.height = Integer.max(height(x.left),height(x.right)) + 1;
  48. return x;
  49. }
  50. /**
  51. * 左旋
  52. */
  53. private AvlNode rotatlLeft(AvlNode x) {
  54. AvlNode temp = x.right;
  55. x.right = temp.left;
  56. temp.left = x;
  57. x.height = Integer.max(height(x.left),height(x.right)) + 1;
  58. temp.height = Integer.max(x.height,height(temp.right)) + 1;
  59. return temp;
  60. }
  61. /**
  62. * 右旋
  63. */
  64. private AvlNode rotatlRight(AvlNode x) {
  65. AvlNode temp = x.left;
  66. x.left = temp.right;
  67. temp.right = x;
  68. x.height = Integer.max(height(x.left),height(x.right)) + 1;
  69. temp.height = Integer.max(height(temp.left),x.height) + 1;
  70. return temp;
  71. }
  72. public AvlNode delete(AvlNode root,int k){
  73. if (root == null){
  74. return null;
  75. }
  76. int i = root.val - k;
  77. if (i > 0){
  78. root.left = delete(root.left,k);
  79. }else if (i < 0){
  80. root.right = delete(root.right,k);
  81. }else{
  82. if (root.left == null && root.right == null){
  83. return null;
  84. }
  85. if (root.left != null && root.right == null){
  86. return root.left;
  87. }
  88. if (root.left == null && root.right != null){
  89. return root.right;
  90. }
  91. if (root.left != null && root.right != null){
  92. AvlNode t = searchMin(root.right);
  93. root.val = t.val;
  94. root.right = delete(root.right,t.val);
  95. }
  96. }
  97. if (height(root.left) - height(root.right) > 1){
  98. if (height(root.left.left) > height(root.left.right)){
  99. root = rotatlRight(root);
  100. }else{
  101. root.left = rotatlLeft(root.left);
  102. root = rotatlRight(root);
  103. }
  104. }else if (height(root.left) - height(root.right) < -1) {
  105. if (height(root.right.right) < height(root.right.left)){
  106. root = rotatlLeft(root);
  107. }else{
  108. root.right = rotatlRight(root.right);
  109. root = rotatlLeft(root);
  110. }
  111. }
  112. root.height = Integer.max(height(root.left),height(root.right)) + 1;
  113. return root;
  114. }
  115. private AvlNode searchMin(AvlNode x) {
  116. if (x.left != null){
  117. x = x.left;
  118. }
  119. return x;
  120. }
  121. }

3、红黑树实现

未全部实现,删除操作尚未实现。

  1. package search;
  2. /**
  3. * 红黑树的java实现
  4. * @author zwlstart
  5. * @create 2020-12-27 21:01
  6. */
  7. public class RedBalckTree {
  8. /**
  9. * 查找一个节点
  10. */
  11. public RBNode get(RBNode x,int k){
  12. if (x == null){
  13. return null;
  14. }
  15. int i = x.val - k;
  16. if (i == 0){
  17. return x;
  18. }else if (i > 0){
  19. return get(x.left,k);
  20. }else{
  21. return get(x.right,k);
  22. }
  23. }
  24. /**
  25. * 返回树的全部节点数量
  26. */
  27. public int size(RBNode x){
  28. if (x == null){
  29. return 0;
  30. }else{
  31. return x.n;
  32. }
  33. }
  34. /**
  35. * 插入一个节点,需保持红黑树的性质
  36. */
  37. public RBNode put(RBNode x,int v){
  38. if (x == null){
  39. return new RBNode(v,1,true);
  40. }
  41. int i = x.val - v;
  42. if (i == 0){
  43. x.val = v;
  44. }else if (i > 0){
  45. x.left = put(x.left,v);
  46. }else{
  47. x.right = put(x.right,v);
  48. }
  49. if (isRed(x.right) && !isRed(x.left)){
  50. x = rotateRight(x);
  51. }
  52. if (isRed(x.left) && isRed(x.left.left)){
  53. x = rotateLeft(x);
  54. }
  55. if (isRed(x.left) && isRed(x.right)){
  56. x = flipColors(x);
  57. }
  58. x.n = size(x.left) + size(x.right) + 1;
  59. return x;
  60. }
  61. /**
  62. * 判断该节点是否是红链接所指向的
  63. * @param x
  64. * @return
  65. */
  66. public boolean isRed(RBNode x){
  67. if (x == null){
  68. return false;
  69. }
  70. return x.color;
  71. }
  72. /**
  73. * 右旋
  74. * @param x
  75. * @return
  76. */
  77. public RBNode rotateRight(RBNode x){
  78. RBNode t = x.right;
  79. x.right = t.left;
  80. t.left = x;
  81. t.color = x.color;
  82. x.color = true;
  83. t.n = x.n;
  84. x.n = size(x.left) + size(x.right) + 1;
  85. return t;
  86. }
  87. /**
  88. * 左旋
  89. * @param x
  90. * @return
  91. */
  92. public RBNode rotateLeft(RBNode x){
  93. RBNode t = x.left;
  94. x.left = t.right;
  95. t.right = x;
  96. t.color = x.color;
  97. x.color = true;
  98. t.n = x.n;
  99. x.n = size(x.left) + size(x.right) + 1;
  100. return t;
  101. }
  102. /**
  103. * 变换节点颜色
  104. * @param x
  105. * @return
  106. */
  107. public RBNode flipColors(RBNode x){
  108. x.right.color = false;
  109. x.left.color = false;
  110. x.color = true;
  111. return x;
  112. }
  113. //查找第i个节点
  114. public int search(RBNode root,int i){
  115. if (root == null || i > size(root) || i < 0){
  116. return -1;
  117. }
  118. int size = size(root.left);
  119. if (size > i){
  120. return search(root.left,i);
  121. }else if(size < i){
  122. return search(root.right,i - size - 1);
  123. }else {
  124. return root.val;
  125. }
  126. }
  127. /**
  128. * 给定一个数,然后二叉树中节点值小于此数的节点数目
  129. * @param v
  130. * @return
  131. */
  132. public int rank(RBNode x,int v){
  133. if (x == null){
  134. return -1;
  135. }
  136. int i = x.val - v;
  137. if (i == 0){
  138. return size(x.left);
  139. }else if (i > 0){
  140. return rank(x.left,v);
  141. }else{
  142. return size(x.left) + 1 + rank(x.right,v);
  143. }
  144. }
  145. /**
  146. * 删除树中的最小值
  147. * @param root
  148. * @return
  149. */
  150. public RBNode deleteMin(RBNode root){
  151. if (root.left == null){
  152. return root.right;
  153. }
  154. root.left = deleteMin(root.left);
  155. root.n = size(root.left) + size(root.right) + 1;
  156. return root;
  157. }
  158. }

4、散列表的实现

  1. SeparateChainingHashST.java
  2. Below is the syntax highlighted version of SeparateChainingHashST.java.
  3. /******************************************************************************
  4. * Compilation: javac SeparateChainingHashST.java
  5. * Execution: java SeparateChainingHashST < input.txt
  6. * Dependencies: StdIn.java StdOut.java
  7. * Data files: https://algs4.cs.princeton.edu/34hash/tinyST.txt
  8. *
  9. * A symbol table implemented with a separate-chaining hash table.
  10. *
  11. ******************************************************************************/
  12. package edu.princeton.cs.algs4;
  13. /**
  14. * The {@code SeparateChainingHashST} class represents a symbol table of generic
  15. * key-value pairs.
  16. * It supports the usual <em>put</em>, <em>get</em>, <em>contains</em>,
  17. * <em>delete</em>, <em>size</em>, and <em>is-empty</em> methods.
  18. * It also provides a <em>keys</em> method for iterating over all of the keys.
  19. * A symbol table implements the <em>associative array</em> abstraction:
  20. * when associating a value with a key that is already in the symbol table,
  21. * the convention is to replace the old value with the new value.
  22. * Unlike {@link java.util.Map}, this class uses the convention that
  23. * values cannot be {@code null}—setting the
  24. * value associated with a key to {@code null} is equivalent to deleting the key
  25. * from the symbol table.
  26. * <p>
  27. * This implementation uses a separate chaining hash table. It requires that
  28. * the key type overrides the {@code equals()} and {@code hashCode()} methods.
  29. * The expected time per <em>put</em>, <em>contains</em>, or <em>remove</em>
  30. * operation is constant, subject to the uniform hashing assumption.
  31. * The <em>size</em>, and <em>is-empty</em> operations take constant time.
  32. * Construction takes constant time.
  33. * <p>
  34. * For additional documentation, see <a href="https://algs4.cs.princeton.edu/34hash">Section 3.4</a> of
  35. * <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
  36. * For other implementations, see {@link ST}, {@link BinarySearchST},
  37. * {@link SequentialSearchST}, {@link BST}, {@link RedBlackBST}, and
  38. * {@link LinearProbingHashST},
  39. *
  40. * @author Robert Sedgewick
  41. * @author Kevin Wayne
  42. */
  43. public class SeparateChainingHashST<Key, Value> {
  44. private static final int INIT_CAPACITY = 4;
  45. private int n; // number of key-value pairs
  46. private int m; // hash table size
  47. private SequentialSearchST<Key, Value>[] st; // array of linked-list symbol tables
  48. /**
  49. * Initializes an empty symbol table.
  50. */
  51. public SeparateChainingHashST() {
  52. this(INIT_CAPACITY);
  53. }
  54. /**
  55. * Initializes an empty symbol table with {@code m} chains.
  56. * @param m the initial number of chains
  57. */
  58. public SeparateChainingHashST(int m) {
  59. this.m = m;
  60. st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[m];
  61. for (int i = 0; i < m; i++)
  62. st[i] = new SequentialSearchST<Key, Value>();
  63. }
  64. // resize the hash table to have the given number of chains,
  65. // rehashing all of the keys
  66. private void resize(int chains) {
  67. SeparateChainingHashST<Key, Value> temp = new SeparateChainingHashST<Key, Value>(chains);
  68. for (int i = 0; i < m; i++) {
  69. for (Key key : st[i].keys()) {
  70. temp.put(key, st[i].get(key));
  71. }
  72. }
  73. this.m = temp.m;
  74. this.n = temp.n;
  75. this.st = temp.st;
  76. }
  77. // hash function for keys - returns value between 0 and m-1
  78. private int hashTextbook(Key key) {
  79. return (key.hashCode() & 0x7fffffff) % m;
  80. }
  81. // hash function for keys - returns value between 0 and m-1 (assumes m is a power of 2)
  82. // (from Java 7 implementation, protects against poor quality hashCode() implementations)
  83. private int hash(Key key) {
  84. int h = key.hashCode();
  85. h ^= (h >>> 20) ^ (h >>> 12) ^ (h >>> 7) ^ (h >>> 4);
  86. return h & (m-1);
  87. }
  88. /**
  89. * Returns the number of key-value pairs in this symbol table.
  90. *
  91. * @return the number of key-value pairs in this symbol table
  92. */
  93. public int size() {
  94. return n;
  95. }
  96. /**
  97. * Returns true if this symbol table is empty.
  98. *
  99. * @return {@code true} if this symbol table is empty;
  100. * {@code false} otherwise
  101. */
  102. public boolean isEmpty() {
  103. return size() == 0;
  104. }
  105. /**
  106. * Returns true if this symbol table contains the specified key.
  107. *
  108. * @param key the key
  109. * @return {@code true} if this symbol table contains {@code key};
  110. * {@code false} otherwise
  111. * @throws IllegalArgumentException if {@code key} is {@code null}
  112. */
  113. public boolean contains(Key key) {
  114. if (key == null) throw new IllegalArgumentException("argument to contains() is null");
  115. return get(key) != null;
  116. }
  117. /**
  118. * Returns the value associated with the specified key in this symbol table.
  119. *
  120. * @param key the key
  121. * @return the value associated with {@code key} in the symbol table;
  122. * {@code null} if no such value
  123. * @throws IllegalArgumentException if {@code key} is {@code null}
  124. */
  125. public Value get(Key key) {
  126. if (key == null) throw new IllegalArgumentException("argument to get() is null");
  127. int i = hash(key);
  128. return st[i].get(key);
  129. }
  130. /**
  131. * Inserts the specified key-value pair into the symbol table, overwriting the old
  132. * value with the new value if the symbol table already contains the specified key.
  133. * Deletes the specified key (and its associated value) from this symbol table
  134. * if the specified value is {@code null}.
  135. *
  136. * @param key the key
  137. * @param val the value
  138. * @throws IllegalArgumentException if {@code key} is {@code null}
  139. */
  140. public void put(Key key, Value val) {
  141. if (key == null) throw new IllegalArgumentException("first argument to put() is null");
  142. if (val == null) {
  143. delete(key);
  144. return;
  145. }
  146. // double table size if average length of list >= 10
  147. if (n >= 10*m) resize(2*m);
  148. int i = hash(key);
  149. if (!st[i].contains(key)) n++;
  150. st[i].put(key, val);
  151. }
  152. /**
  153. * Removes the specified key and its associated value from this symbol table
  154. * (if the key is in this symbol table).
  155. *
  156. * @param key the key
  157. * @throws IllegalArgumentException if {@code key} is {@code null}
  158. */
  159. public void delete(Key key) {
  160. if (key == null) throw new IllegalArgumentException("argument to delete() is null");
  161. int i = hash(key);
  162. if (st[i].contains(key)) n--;
  163. st[i].delete(key);
  164. // halve table size if average length of list <= 2
  165. if (m > INIT_CAPACITY && n <= 2*m) resize(m/2);
  166. }
  167. // return keys in symbol table as an Iterable
  168. public Iterable<Key> keys() {
  169. Queue<Key> queue = new Queue<Key>();
  170. for (int i = 0; i < m; i++) {
  171. for (Key key : st[i].keys())
  172. queue.enqueue(key);
  173. }
  174. return queue;
  175. }
  176. /**
  177. * Unit tests the {@code SeparateChainingHashST} data type.
  178. *
  179. * @param args the command-line arguments
  180. */
  181. public static void main(String[] args) {
  182. SeparateChainingHashST<String, Integer> st = new SeparateChainingHashST<String, Integer>();
  183. for (int i = 0; !StdIn.isEmpty(); i++) {
  184. String key = StdIn.readString();
  185. st.put(key, i);
  186. }
  187. // print keys
  188. for (String s : st.keys())
  189. StdOut.println(s + " " + st.get(s));
  190. }
  191. }