Introduction to Algorithms--Summary of Binary Search Tree Implemented by java Language

Posted by arkleyjoe on Fri, 12 Jul 2019 02:11:10 +0200

The pictures are all from Mucho. com, just for learning records.

1. Binary Search Tree

It can also be called a binary search tree. It can not only find data, but also insert and delete data efficiently.
Features: The key value of each node is larger than that of the left sub-node and smaller than that of the right sub-node. Note that it is not necessarily a complete binary tree.
So the key of the node is unique, and we index the corresponding value of the key through it. Note that all the keys in the graph are marked.

Therefore, binary search trees are not suitable to be represented by arrays, and they are usually represented by node nodes.
Advantages over the data structure of arrays:

Another advantage is that its keys can be defined by itself, such as String as a key to implement a lookup table, while arrays can only be indexed

2. Realization.
Implement each node first:
The elements of a node are key, value, left and right sub-nodes.
  1. public class Node {
  2. //Node's key
  3. private int mKey;
  4. //Value value corresponding to Node
  5. private int mValue;
  6. //The left and right sub-nodes are null in the initial state.
  7. private Node mLeftChild;
  8. private Node mRightChild;
  9. public Node(int key,int value){
  10. mKey = key;
  11. mValue = value;
  12. mLeftChild = null;
  13. mRightChild = null;
  14. }
  15. public int getValue(){
  16. return mValue;
  17. }
  18. public Node getLeftChild(){
  19. return mLeftChild;
  20. }
  21. public Node getRightChild(){
  22. return mRightChild;
  23. }
  24. public void setValue(int newValue) {
  25. mValue = newValue;
  26. }
  27. public void setLeftChild(Node left) {
  28. mLeftChild = left;
  29. }
  30. public void setRightChild(Node right) {
  31. mRightChild = right;
  32. }
  33. public int getKey(){
  34. return mKey;
  35. }
  36. }

Basic Implementation of Binary Search Tree
  1. package com.zy.serch;
  2. /**
  3. * Binary Search Tree
  4. * @author Administrator
  5. *
  6. */
  7. public class BinarySearchTree {
  8. //Root node.
  9. private Node mRoot;
  10. //There should also be a value to record quantities, and each insert should add 1 to the data.
  11. private int mCount;
  12. public int getSize(){
  13. return mCount;
  14. }
  15. //Sentence blank
  16. public boolean isEmpty(){
  17. return mCount == 0;
  18. }
  19. }
Implementation of inserting data
  1. /**
  2. * For external invocation
  3. * @param key key of data to be stored externally
  4. * @param value Value of data to be stored externally
  5. */
  6. public void insert(int key,int value){
  7. //Further invoke the internal insert to place the current key and value in the tree with mRoot as the root node.
  8. mRoot = insert(mRoot, key, value);
  9. }
  10. /**
  11. * Insert a node.
  12. * The core idea is to find the insertion position from the root node to satisfy the characteristics of the binary search tree, which is larger than the left sub-node and smaller than the right sub-node.
  13. * Steps:
  14. * 1,Starting with the root node, compare the current node, and if the current node is null, it is obvious that it should be inserted into the node.
  15. * 2,If the above node is not null, then compared with the current node, if it is smaller than the node, it will be placed in the left subtree, and if it is larger than the node, it will be placed in the right subtree.
  16. * 3,Then, the recursive operations of the left subtree or the right subtree are performed in steps 1 and 2 above respectively.
  17. *
  18. * Recursion is used at this point, so recursion is a problem, its sub-problems need to be the same model.
  19. * A minor problem here is that a node is then manipulated, so the parameter should have a node in order to loop.
  20. * Insert the node (key, value) into the binary search tree with node as its root. Here, the int type is used, and the external user is
  21. * You don't need to understand the concept of node. They just need to know the key and value passed in.
  22. * Temporary design makes it easy to understand the keys and value s that are passed into the user's own, and then it's also convenient to use them according to keys.
  23. *
  24. * @param node Because to use the idea of recursion, it's time to insert nodes.
  25. * @param key Externally imported key
  26. * @param value External incoming value
  27. * @return Returns the heel of the binary tree after the new insertion of the binary tree node.
  28. */
  29. private Node insert(Node node,int key,int value){
  30. //If the node to be inserted is null, then prove that we have found the location, just put it here.
  31. if(node == null){
  32. //Quantity plus 1
  33. mCount++;
  34. //But then when it's the first place to insert it, it's returned.
  35. return new Node(key, value);
  36. }
  37. //If the current node already has nodes (do not consider duplication? )
  38. //Here we compare the values of value.
  39. if(key < node.getKey()){
  40. //At this point, the left node should be processed recursively. The inserted node is finally put into the left child node.
  41. //Ultimately related to the left subtree.
  42. Node left = insert(node.getLeftChild(), key, value);
  43. node.setLeftChild(left);
  44. }else if(key > node.getKey()){
  45. // // At this point, the left node should be processed recursively. The inserted node should finally be placed in the right child node.
  46. Node right = insert(node.getRightChild(), key, value);
  47. node.setRightChild(right);
  48. }else{
  49. //Update the value directly when equal to
  50. node.setValue(value);
  51. }
  52. return node;//Return to the root node
  53. }
Implementation of query data:
  1. /**
  2. * Find the corresponding value according to the key value.
  3. * @param key The key to look up
  4. * @return Returns the value corresponding to the key, and returns null if the lookup fails.
  5. *
  6. */
  7. public int serch(int key){
  8. //Call internal functions recursively.
  9. return serch(mRoot,key);
  10. }
  11. /**
  12. *
  13. * @param node The first entry is the root node, which is indexed from the root node. After searching, the next entry is the next one to be searched.
  14. * @param key The key value to look for.
  15. * @return Returns the value corresponding to the key found.
  16. */
  17. private int serch(Node node,int key){
  18. //Certificate not found, directly return to the processing when not found
  19. if(node == null){
  20. return (Integer) null;//What's better if you don't find something to return to?
  21. }
  22. //The following is a comparison of the keys to be searched and the keys to the current Node in turn:
  23. // If equal: it proves that the current value has been returned directly
  24. // If the key to be searched is less than the key of the current node: then go to the left child of the current node to search recursively.
  25. // If the key to be searched is larger than the key of the current node: then the right child of the current node is searched recursively.
  26. if(node.getKey() == key){
  27. return node.getValue();
  28. //Look at it so that the key is unique and the key on the right is larger than the key on the left? You didn't guess wrong, haha, at first you got it wrong, Toury.
  29. //The value of all faces is key, not value.
  30. }else if (key < node.getKey()){
  31. //Processing on the left, continue processing the number of left subnodes, and return directly after finding. (Not very well understood here)
  32. //Here the function can be returned, and go directly to the next function recursively to find, the return value of this function is one.
  33. //The return value of the next function, so recursive.
  34. return serch(node.getLeftChild(), key);
  35. }else{
  36. return serch(node.getRightChild(), key);
  37. }
  38. }
Does the query contain any data?
  1. /**
  2. * Determine whether the key pair corresponding to the current key exists in the binary search tree
  3. * @param key The key to look for
  4. * @return Existence returns true, and none returns false.
  5. */
  6. public boolean contain(int key){
  7. return contain(mRoot,key);
  8. }
  9. //Realizing ideas is the same as searching, after all, to see if it's really the process of searching.
  10. private boolean contain(Node node,int key){
  11. if(node==null){
  12. return false;
  13. }
  14. if(node.getKey() == key){
  15. return true;
  16. //Look at it so that the key is unique and the key on the right is larger than the key on the left?
  17. }else if (key < node.getKey()){
  18. //Processing on the left, continue processing the number of left subnodes, and return directly after finding. (Not very well understood here)
  19. return contain(node.getLeftChild(), key);
  20. }else{
  21. return contain(node.getRightChild(), key);
  22. }
  23. }
The Mu lesson net test is designed with string as key and number of occurrences as value. This way of searching binary trees loops over blocks in while rather than sequentially
Quite a lot.

Traversal of binary search tree.
Traversal refers to making one visit to each node in the tree in turn along a search route. There are three kinds of traversing binary trees:
Preorder Traversal: First visit the current node, then recursively access the left and right subtrees.
Inorder Traversal: First, access the left subtree recursively, then access itself, then access the right subtree recursively
Postorder Traversal: Visit the left and right subtrees recursively, and then the current node.
How do you understand the first kind of recursive access above? For example, if the left sub-node of any node has not been visited, continue to visit its left sub-node until the left sub-node has finished.
After the complete traversal, the first node to be visited will be traversed in intermediate order, and then up in sequence.
These three kinds of order are the order of the current node (that is, the middle one).
Find the picture above Baidu:

Preorder traversal: A B C D E F G
Mid-order traversal: C B D A E F G
Post-order traversal: C D B G F E A
You can see that in general, the order of front, middle and back is relative to the current node, and will recursively go deep into the last layer of the node. Then from the bottom floor
Each node is executed in a specified order.
The last sequence traversal: traversal from top to bottom, left to right.
Sequence traversal: A B E C D F G
Preorder traversal:
  1. /**
  2. * Preorder traversal
  3. * Traveling through this block is easy to implement with recursive thinking, so the smallest size is for a node, and the function should have a parameter Node.
  4. */
  5. public void perTravelsal(){
  6. //Traverse from the root node
  7. perTravelsal(mRoot);
  8. }
  9. private void perTravelsal(Node node){
  10. //You don't have to go down until the node is null
  11. if(node != null){
  12. //For each node, the current node is traversed first.
  13. //Let's simply print the key value for traversal.
  14. System.out.print(node.getKey()+" ");
  15. //Then we recursively execute the left subtree, paying attention not to judge whether there is, because we will judge when we go in.
  16. perTravelsal(node.getLeftChild());
  17. //Recursive Execution of Right Subtree
  18. perTravelsal(node.getRightChild());
  19. }
  20. }
Intermediate traversal
  1. /**
  2. * An application of mid-order traversal is that it is orderly after traversal.
  3. */
  4. public void inorTravelsal(){
  5. //Call the internal recursive implementation.
  6. inorTravelsal(mRoot);
  7. }
  8. //Specific recursive implementation
  9. private void inorTravelsal(Node node){
  10. if(node!=null){
  11. //Traversing the left node first
  12. inorTravelsal(node.getLeftChild());
  13. //Then the current node
  14. System.out.print(node.getKey()+" ");
  15. inorTravelsal(node.getRightChild());
  16. }
  17. }
Postorder traversal
  1. /**
  2. * Postorder traversal
  3. */
  4. public void postTarvelsal(){
  5. //The reason is the same as the first two.
  6. postTarvelsal(mRoot);
  7. }
  8. private void postTarvelsal(Node node){
  9. if(node!=null){
  10. //Traversing the left node first
  11. postTarvelsal(node.getLeftChild());
  12. //Then the right child node
  13. postTarvelsal(node.getRightChild());
  14. //Finally, the current node
  15. System.out.print(node.getKey()+" ");
  16. }
  17. }
level traversal
  1. /**
  2. * level traversal
  3. * What we mentioned earlier is that depth-first traversal is achieved by recursion. As long as the downward nodes have the required conditions, they will continue to execute west-first and downward.
  4. * Sequence traversal is a breadth-first traversal method. First traverse the root node layer, then traverse the second layer, so from top to bottom, from left to right.
  5. * The idea here is to take advantage of the first-in-first-out (FIFO) feature of the queue.
  6. * When the queue is not empty, start the operation. If the queue is not empty, then the root node must exist. First, the root node should be replaced by the root node.
  7. * Enter the team, and then start a circular judgment: judge the condition queue as kong, first traverse the current node, then leave the queue, (at this time the queue is empty)
  8. * Then see if there are left and right sub-nodes in this node, if there is a queue (so it is not empty, and down a layer), left and right sub-nodes.
  9. * When the node has finished processing, continue to do the same operation in a loop.
  10. */
  11. public void levelTravelsal(){
  12. //Require queue coordination, first instantiate a queue
  13. Queue<Node> queue = new BlockingQueue<Node>() {
  14. //......
  15. };
  16. //If no element is returned directly.
  17. if(isEmpty()){
  18. return;
  19. }
  20. //There are elements to prove that the minimum root node is not null. First-in. Cyclic exit condition?
  21. //No elements in the queue? Layer by layer?
  22. //Get the Root Node into the Team First
  23. queue.add(mRoot);
  24. while(!queue.isEmpty()){
  25. //As long as it is not empty, the current node is processed first and the front element in the queue is removed.
  26. Node node = queue.poll();
  27. //Do traversal operation when leaving the queue
  28. System.out.print(node.getKey()+" ");
  29. //When the left node is not null, join the left node in the queue
  30. if(node.getLeftChild()!=null){
  31. queue.add(node.getLeftChild());
  32. }
  33. //Add the right node to the queue when the left node is not null
  34. if(node.getRightChild()!=null){
  35. queue.add(node.getRightChild());
  36. }
  37. //So if the current node has left and right nodes, the queue will not be null.
  38. //When we continue to cycle to the front, we first take out the front node (we put it in left-right order).
  39. //So the next cycle is to take the current node out of the queue, traverse the operation, and then the right node out of the queue traverse the operation.
  40. //Then continue to see if there are left and right nodes, so that the sequence traversal is achieved.
  41. }
  42. }
Get the maximum and minimum
  1. /**
  2. * Find the node with the smallest value, and return the key of the found node, after all, the user passes in the key and value.
  3. * Can't find it is returning null.
  4. * @return The key corresponding to the node with the smallest value.
  5. */
  6. public int getMinmum(){
  7. if(isEmpty())
  8. return (Integer) null;
  9. //Recursive calls to internal implementations.
  10. Node min = getMinmum(mRoot);
  11. return min.getKey();
  12. }
  13. private Node getMinmum(Node node){
  14. /*//Don't worry that node is null, because if it's root node, it won't get in at all.
  15. //If it's not the root node, we return directly when the left is null.
  16. Node left = node.getLeftChild();
  17. if(left != null){
  18. //Processing recursively when not null.
  19. getMinmum(left);
  20. }else{
  21. //The left child of the current node is null, which proves that the minimum value has been found.
  22. return node;
  23. }
  24. return node;*/
  25. //Below is God's concise code! Although the meaning is the same
  26. Node left = node.getLeftChild();
  27. if(left == null){
  28. return node;
  29. }
  30. //Otherwise, call it recursively to execute its left child node
  31. return getMinmum(left);
  32. }
  33. //Get the maximum node, just like the minimum node, according to the characteristics
  34. //Find the lowest child node of the right subtree.
  35. /**
  36. * Get the node with the largest value
  37. * @return The node with the largest value corresponds to the key.
  38. */
  39. public int getMammum(){
  40. if(isEmpty())
  41. return (Integer) null;
  42. Node max = getMammum(mRoot);
  43. return max.getKey();
  44. }
  45. private Node getMammum(Node node){
  46. Node right = node.getRightChild();
  47. if(right == null){
  48. return node;
  49. }
  50. return getMammum(right);
  51. }
Delete the maximum and minimum values of the binary search tree.
Delete the smallest node
  1. //Delete the minimum value of the binary search tree. Learn to delete the maximum and minimum values first.
  2. //Because when the maximum and minimum values are deleted, the current node, that is, the largest/smallest node, will not have two sub-nodes.
  3. //When the minimum value is deleted, either the current node has no child nodes or the current node has only one right child node. (It's not the smallest when you have left child nodes)
  4. //When the maximum value is deleted, either the current node has no children, or the current node has only one left child. (It's not the smallest when there are right subnodes)
  5. /**
  6. * Delete the smallest node from the binary tree
  7. *
  8. */
  9. public void removeMin(){
  10. /*//First, you should find the smallest node.
  11. Node min = getMinmum(mRoot);
  12. if(min == null)
  13. return;
  14. //If the current node has a right child, place the node on the index of the parent of the smallest node
  15. if(min.getRightChild()!=null){
  16. //How to get the parent of the smallest node? At this point, we do not set the attributes of the parent node, so we need to find a little bit.
  17. //This plan is not good.
  18. }*/
  19. //So you can only search again and delete it when you find it.
  20. //Need to find out, or continue to use recursion better understanding, the next call to the internal deletion function
  21. if(isEmpty()){
  22. return;
  23. }
  24. removeMin(mRoot);
  25. }
  26. /**
  27. *
  28. * @param node Initially, it passes in the root node, a mirror operation, and a value into the node on the left subtree.
  29. * Set the right subtree node in until the smallest node is deleted and return it to the parent node.
  30. * (Actually, it's not good enough to understand.
  31. *
  32. * @return Returns the root of the new binary search tree after deleting the node.In fact, it is the root of the node of the initial incoming binary tree.
  33. */
  34. private Node removeMin(Node node){
  35. Node left = node.getLeftChild();
  36. if(left == null){//It is proved that the smallest node has been found.
  37. //Start deleting, feel that java is nothing to do, release the node? ,
  38. //Should first get the right sub-node, whether or not, no is to get a null.
  39. Node right = node.getRightChild();
  40. node = null;//Release the memory of the current node
  41. mCount--;//Number of nodes--
  42. //Note that the return value here does not affect the return value of the final function. The return value of this block is only when it reaches the smallest node.
  43. //Return the right subtree of the current smallest node and cooperate (note that in the last function call, that is, the parent of the smallest node)
  44. //setLeftChild implements setting the node of the right subtree to the node of the left subtree of the parent.
  45. return right;
  46. }
  47. //The following recursion, when not reaching the smallest node, will always be stuck here and pay attention to not reaching the return node.
  48. //When the card is here, the first value is passed in to the current node's left node, and the left node is always set up.
  49. //Until you enter the smallest node, return to the right child of the smallest node, and then set it layer by layer. Finally, the root node is returned.
  50. Node temp = removeMin(left);
  51. node.setLeftChild(temp);
  52. return node;
  53. }
Delete the largest node
  1. /**
  2. * Removing the largest node is the same as removing the smallest node.
  3. */
  4. public void removeMax(){
  5. if(isEmpty()){
  6. return;
  7. }
  8. removeMax(mRoot);
  9. }
  10. /**
  11. *
  12. * @param node The current node that requires removeMax() function operation.
  13. * @return It returns the root node of the binary tree where the removed node is located, which is actually the root of the node of the original incoming binary tree.
  14. */
  15. private Node removeMax(Node node){
  16. //Get the right child node
  17. Node right = node.getRightChild();
  18. //When null equals null, it turns out that the largest one has been found.
  19. if(right == null){
  20. //Remove its left child node, whether or not it has
  21. Node left = node.getLeftChild();
  22. node = null;//Delete the current node
  23. mCount--;
  24. return left;//Return this to set the right child for the parent node
  25. }
  26. Node temp = removeMax(right);
  27. node.setRightChild(temp);
  28. return node;
  29. }
Delete any node:
  1. /**
  2. * Delete any node: A method proposed by Hibbard called Hubbard Deletion
  3. *The difference between deleting any node and deleting the smallest and largest node is that when deleting any node, it is possible to have both left and right sub-nodes.
  4. *First of all, we can't simply put the left or right child nodes in the position of the currently deleted node, because this is the case.
  5. *It is easy to cause dissatisfaction with the characteristics of binary search tree. We should find the current precursor or put it in the current position.
  6. *An element smaller than it; a successor: an element smaller than it hits. For example, in one way, we find all the nodes in its right child node.
  7. *The smallest node in the tree, and then put the smallest node into the deleted node, which still satisfies the characteristics of the binary search tree, the left sub-node.
  8. *They are smaller than it, and the right child nodes are larger than it. A similar approach is to find the largest node of all nodes in the left subtree.
  9. *Delete steps when finding the node to be deleted: (when there are only left or right sub-nodes, use the previous, determine that there are both left and right nodes)
  10. * 1,Find the minimum value of the right child node and delete it.
  11. * 2,Then put the deleted node in the location where it was found.
  12. * That is to assign the right and left child nodes of the found node to the deleted node respectively.
  13. * 3,Finally, the node should also assign the correct location to the parent of the deleted node.
  14. *All of these are implemented by looking up. You can't call the interface directly to find the node you want to delete, so you can't get it here.
  15. *Its parent node cannot be associated.
  16. * @param key The key of the node to be deleted is because we designed the key to be int.
  17. *
  18. */
  19. public void remove(int key){
  20. //Internal or Call Recursive Ideas for Implementation
  21. mRoot = remove(mRoot,key);
  22. }
  23. private Node remove(Node node,int key){
  24. //The first node to join, when internal remove() is called, still passes in root
  25. //If an empty node proves to have found the lowest level, it is not found.
  26. if(node == null){
  27. return null;//Just go back to empty.
  28. }
  29. //Note that the search is from the root node side.
  30. //If it is found that it is larger than the right child node, then continue to search for the right child node.
  31. if(key > node.getKey()){
  32. //It should recursively go to the right. The whole understanding below is not in place.
  33. Node right = node.getRightChild();
  34. //Continue to pass in the right node in the same way as the previous maximum/smallest understanding.
  35. //When you don't get to the bottom, it's at the parent node level: always pass in the child node on the right, and then
  36. //The value returned is set to the current right child node (because this function returns the current node and we pass in the right child node)
  37. //This is where the loop recurs until:
  38. // 1. If we don't find the node to delete, we will eventually go to node = null, which is the last layer.
  39. // The return is null assigned to the right of the parent node, and then returned recursively to the upper layer until the first layer of the incoming node.
  40. // There's nothing wrong with setting their right child nodes.
  41. // 2. When we find the node we want to delete, let's assume that the node is called D. Then we won't go to the last level.
  42. // Break, and go to the equivalent time judgment we designed below, in which we will return to the forerunner or successor we found, and then
  43. // This node is mounted under the right child of its parent node. This completes the linking of the entire binary tree.
  44. Node temp = remove(right, key);
  45. node.setRightChild(temp);
  46. return node;//Return to the current node, which is the first node to be passed in.
  47. }else if(key < node.getKey()){
  48. //Reason is the same as above
  49. Node left= node.getLeftChild();
  50. Node temp = remove(left, key);
  51. node.setLeftChild(left);
  52. return node;
  53. } else {//This is the time to find the node to delete.
  54. //There will be three more situations:
  55. //The first is that the node found does not have a left child, which is similar to deleting the minimum value.
  56. //At this point, a node represents the node to be deleted.
  57. if(node.getLeftChild() == null){
  58. //Get the right nodes directly, return them, and let them assign values one layer at a time, regardless of whether null or not.
  59. Node right = node.getRightChild();
  60. mCount--;
  61. node = null;
  62. return right;
  63. }
  64. //The second is that the node found does not have a right child, which is similar to deleting the maximum value.
  65. if(node.getRightChild() == null){
  66. //Ibid.
  67. Node left = node.getLeftChild();
  68. mCount--;
  69. node = null;
  70. return left;
  71. }
  72. //Third, when there are sub-nodes left and right, this is our Hubbard deletion.
  73. //Here we use the successor of finding and deleting nodes, which is the minimum value of the right subtree.
  74. //So you should first find the smallest node of the right subtree, multiplex getMinmum(node) and pass it to the right child of the current node.
  75. Node min = getMinmum(node.getRightChild());
  76. //Then removeMin is reused to delete the node. At this time, instead of passing in the root node, the right child node of the current node is passed in.
  77. //In this way, the value of the smallest node in all subtrees rooted on the right child of the current node is deleted and the incoming right child node is returned.
  78. //Internally, the index of that node in the binary tree will be null, but we got the new index in front of us, which also points to that place.
  79. Node rightRoot = removeMin(node.getRightChild());
  80. //Just assign the root of this right subsection to the right subnode of the min found.
  81. min.setRightChild(rightRoot);
  82. //Then you need to connect the left child of the deleted node to the left child of the found node.
  83. //Node is the node to be deleted.
  84. min.setLeftChild(node.getLeftChild());
  85. node = null;
  86. //mCount--;
  87. //At this point, I feel like I will subtract one more. In the previous remove, I subtract the smallest one, and then I subtract the current node.
  88. //But there is no mCount++ when connecting the smallest node found to the binary search tree.
  89. //mCount++; // Cable is not -- No.
  90. return min;//Returns the judgment of the two left and right subnodes used for the first judgment key.
  91. }
  92. }
The time complexity of deleting any node in the binary search tree is O(logn), and the time complexity of deleting a node in the sequence table is O(n).

3. Expanding Knowledge
On the sequentiality of binary search trees.
Forerunners and successors:
On the predecessor of a number: predecessor [pri:d ses(r)] predecessor/predecessor. On the successor of a number: successor [s k ses(r)]heir
For the precursor and successor of a number, the existence of this number is required, and the precursor and successor functions need to be considered when implementing:
1) Whether the current node is the minimum, there is no precursor at the minimum; similarly, whether it is the maximum, the maximum has no succession.
2) Whether there are two left and right sub-nodes, if so, the precursor will go to the left sub-node to find the maximum, and then go to the right sub-node to find the minimum.
3) embarrassment analysis can not come out. When the left and right child nodes are incomplete or none, it feels troublesome. Your consideration is that the current node is the child of the parent node, which is harmful.
It's messy to consider the situation of parents with fewer children. I don't know yet, but it's also arranged according to the order of key s in the end. Is it better to find it?

floor and ceil
The floor and ceil functions do not need the key s to be looked up, and if they exist, the value of the two functions is the return itself.
floor: The value corresponding to the key that is not larger than the incoming key is
ceil: no less than the value of the key passed in is
 
Implementation of floor
  1. /**
  2. * According to the key of the incoming node, the key of the corresponding node after floor operation is obtained.
  3. *
  4. * @param key The key of the node to floor
  5. * @return The key of the result node of the corresponding floor, if there is no return null.
  6. */
  7. public int floor(int key){
  8. //If the mCount in the binary tree is 0, or less than the lowest value, then there is no precursor
  9. if(mCount==0||key < getMinmum()){
  10. return (Integer) null;
  11. }
  12. //Call floor of the internal implementation.
  13. Node node = floor(mRoot, key);
  14. return node.getKey();
  15. }
  16. // In the binary search tree rooted by node, the node where the floor value of key is located is searched.
  17. private Node floor(Node node, int key){
  18. //Return null directly when the current node is null.
  19. if( node == null )
  20. return null;
  21. // If the key value of the node is equal to the key value to be looked for, the node itself is the floor node of the key.
  22. if( node.getKey() == key )
  23. return node;
  24. // If the key value of the current node is larger than the key value to be searched for, then the precursor must be in the left node.
  25. if( node.getKey() > key )
  26. //Go to the left node for recursive lookup
  27. return floor( node.getLeftChild() , key );
  28. // At this point, the key of the current node is less than the key to be looked up.
  29. // 1) At this point, the node is the floor corresponding to the key node.
  30. // 2) The node is not the floor corresponding to the key node, because there is a smaller value in the right node of the current node than the key of the node.
  31. // That is, there are other nodes larger than node - > key but smaller than key.
  32. // We need to try to find the right subtree of node. Generally speaking, the understanding is not deep, but the whole feeling should be recursive.
  33. // Consider only the current node situation, do not try to go one layer after another to consider the internal, only consider the current time, is to go to the right node and recursive search.
  34. // If found, return it, if not. Prove that the current node (smaller than key) is correct. Then return to the current node
  35. Node tempNode = floor( node.getRightChild() , key );
  36. //If we find a proof that there is a smaller direct return
  37. if( tempNode != null )
  38. return tempNode;
  39. //When we get here, group Hengming satisfies node. getKey () < key, and there is no smaller one in the right subtree of this node!
  40. return node;
  41. }
The implementation of ceil is equivalent to floor
  1. public int ceil(int key){
  2. //If the mCount in the binary tree is 0, or less than the lowest value, then there is no precursor
  3. if(mCount==0||key > getMammum()){
  4. return (Integer) null;
  5. }
  6. //Call floor of the internal implementation.
  7. Node node = ceil(mRoot, key);
  8. return node.getKey();
  9. }
  10. private Node ceil(Node node ,int key){
  11. //Return null directly when the current node is null.
  12. if(node == null){
  13. return null;
  14. }
  15. if(key == node.getKey()){
  16. return node;
  17. }
  18. //When the key is larger than the key of the current node, it means that we should go to the right subtree to find the minimum value larger than the key.
  19. //You can't be less than key.
  20. if(key > node.getKey()){
  21. return ceil(node.getRightChild(), key);
  22. }
  23. //See if the left node has a key larger than the key but smaller than the current node's key.
  24. Node tempNode = ceil( node.getLeftChild() , key );
  25. if( tempNode != null )
  26. return tempNode;//If there is a return to this
  27. //Otherwise, return to the current node.
  28. return node;
  29. }
Ranking of Binary Search Books
Want to know where a key in the binary search tree ranks in the book?
 
One way to achieve this is to add a field for each tree node, which marks how many sub-nodes the current node has, and then it can be calculated by simple logic and calculation.
What's the ranking?
Note that adding a domain record like this is the most difficult way to maintain the corresponding domain when insert and remove, so don't forget.

Binary Search Tree Supporting Duplicate Elements
 
The first implementation is to place the larger node in the right sub-node and the smaller or equal node in the left sub-node. But this wastes space when there are a lot of repetitive elements.
The second implementation: also add a domain to Node, which is used to mark the number of current nodes.

Limitations of binary search trees.
 
When the insertion order of data is close to order, the binary search tree may degenerate into a linked list, and the time complexity changes from logn to n.
But we can't mess up the elements at once, because it's possible that you can't get all the elements you type in a little bit of data. At this point, the improved binary tree:
The implementation of balanced binary tree includes:
1) Red and Black Trees
      2),2-3 tree
      3),AVL tree
      4),Splay tree
5) Treap balanced binary tree and heap combination.
Balanced Binary Tree has the following properties: it is an empty tree or the absolute value of the height difference between its left and right subtrees does not exceed 1, and the left and right subtrees are both balanced binary trees.
These are some concepts, and there are many things to learn. When we wait for the second time, we should study them in depth and in detail. There are also trie trees, word search trees.

There are other kinds of trees:
KD tree (k-dimensional tree for short) is a data structure that divides k-dimensional data space. It is mainly applied to the search of key data in multi-dimensional space (e.g.
Circumference search and nearest neighbor search. K-D tree is a special case of binary space partitioning tree.
Interval Tree: Interval Tree is an operation that supports the dynamic set of intervals as elements based on the red-black tree, in which the key value of each node is the interval.
Left endpoint.
Huffman tree: Given n n n weights as n leaf nodes, a binary tree is constructed. If the length of weighted path reaches the minimum, such a binary tree is called the optimal binary tree.
Tree, also known as Huffman Tree. Huffman tree is the shortest tree with weighted path length, and the node with larger weights is closer to the root.

The solution of various games is the search of binary tree.

Topics: less Java