Http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html
YANGECNU (YANGECNU ' s blog on the blog Park)
Source: http://www.cnblogs.com/yangecnu/
The source of the original English text:
http://algs4.cs.princeton.edu/32bst/
This paper introduces two kinds of implementation of symbol table, unordered linked list and ordered array, unordered list has high flexibility when inserting, while ordered array has high efficiency when searching, this article introduces the two-fork search tree (binary search Tree,bst) This data structure combines the advantages of both of these data structures.
Binary search tree with high flexibility, the optimization can generate balanced binary tree, red and black trees and other efficient search and insert data structure, the article will be introduced.
A definition
Binary search trees (binary search tree), also known as ordered binary trees (ordered binary tree), are ordered binary trees (sorted), which refers to an empty tree or a two-fork tree with the following properties:
1. If the left subtree of any node is not empty, the value of all nodes on the left subtree is less than the value of its root node;
2. If the right subtree of any node is not empty, the value of all nodes on the right subtree is greater than the value of its root node;
3. The left and right subtree of any node is also a two-fork lookup tree, respectively.
4. No nodes with key values equal (no duplicate nodes).
For example, this is an ordinary two-fork tree:
On this basis, plus the size relationship between nodes, is the binary lookup tree:
Two implementations
In the implementation, we need to define an internal class node, which contains two nodes pointing to the left and right node, a key for sorting, and the value that the node contains, and a value number that records the count of the node and all child nodes.
public class Binarysearchtreesymboltable<tkey, tvalue>: Symboltables<tkey, tvalue> where tkey:icomparable <tkey>, iequatable<tvalue>{ private Node root; Private class node {public node ' left {get; set;} Public Node right {get; set;} public int number {get; set;} Public TKey Key {get; set;} Public TValue Value {get; set;} Public Node (TKey key, TValue value, int number) {this . key = key; This. value = value; This. Number = number; } } ...}
Find
The find operation is similar to a binary lookup, where key is compared to the node key, and if it is less than, then it is found on the left node node and, if it is greater than, on the right node node, and if it is equal, returns value directly.
The method is implemented in two ways: iterative and recursive.
The recursive approach is implemented as follows:
public override TValue Get (TKey key) { TValue result = Default (TValue); node node = root; while (node! = null) { if (Key.compareto (node. Key) > 0) { node = node. right; } else if (Key.compareto (node. Key) < 0) { node = node. Left; } else { result = node. Value; break; } } return result;}
The iterations are as follows:
Public TValue Get (TKey key) { return GetValue (root, key);} Private TValue GetValue (Node root, TKey key) { if (root = null) return to default (TValue); int cmp = Key.compareto (root. Key); if (CMP > 0) return GetValue (root. Right, key); else if (CMP < 0) return GetValue (root. Left, key); else return root. Value;}
Insert
Insert and find similar, first look for there is no same as key, if there is, update, if not found, then create a new node. and update the number value for each node, the code is implemented as follows:
public override void put (TKey key, TValue value) { root = Put (root, key, value);} Private node Put (node x, TKey key, TValue value) { //If the node is empty, create a new node and return //Otherwise compare whether the left or right node is judged by size, and then continue to find Zuozi or right subtree //Update the value of the number of the node if (x = = null) return new node (key, value, 1); int cmp = Key.compareto (x.key); if (CMP < 0) X.left = Put (X.left, key, value); else if (cmp > 0) x.right = Put (X.right, key, value); else x.value = Value; X.number = Size (x.left) + size (x.right) + 1; return x;} private int Size (node node) { if (node = = null) return 0; else return node. number;}
The insert operation diagram is as follows:
Here is the Insert animation effect:
Randomly inserting the tree into the animation below, you can see that when inserting the tree can still maintain an approximate balance state:
Maximum minimum value
As you can see, the maximum minimum value of a binary search tree is regular:
As you can see, the leftmost and most right nodes in the binary lookup tree are the minimum and maximum values, so we only need to iterate over the call.
public override TKey Getmax () { TKey MaxItem = default (TKey); Node s = root; while (s.right! = null) { s = s.right; } MaxItem = S.key; return MaxItem;} public override TKey Getmin () { TKey Minitem = default (TKey); Node s = root; while (s.left! = null) { s = s.left; } Minitem = S.key; return Minitem;}
The following is a recursive version:
Public TKey getmaxrecursive () { return getmaxrecursive (root);} Private TKey getmaxrecursive (Node root) { if (root). right = = null) return root. Key; return getmaxrecursive (root. right);} Public TKey getminrecursive () { return getminrecursive (root);} Private TKey getminrecursive (Node root) { if (root). left = = null) return root. Key; return getminrecursive (root. left);}
Floor and ceiling
The value of Find floor (key) is the maximum value of all <=key, instead finding the value of ceiling is the minimum value of all >=key, which is the search for the floor function:
To find floor For example, we first compare the key and root element, if the key is smaller than the root key, then it must be on the left subtree, if it is larger than the root key, it may be in the right subtree, and only if its right subtree has a node key value is less than or equal to the key If the key is equal to root, the floor value is key. According to the above analysis, the floor method code is as follows, the code of the ceiling method is similar, just need to change the symbol:
Public TKey Floor (TKey key) { Node x = Floor (root, key); if (x = null) return x.key; else return default (TKey);} Private node Floor (node x, TKey key) { if (x = = null) return null; int cmp = Key.compareto (x.key); if (cmp = = 0) return x; if (CMP < 0) return floor (X.left, key); else { Node right = Floor (x.right, key); if (right = = null) return x; else return right;} }
Delete
Deleting an element operation in a binary tree operation should be more complex. First of all, it is easier to delete the most minimal and least worthwhile method.
To remove the minimum value, we first find the minimum value, and the leftmost left subtree is empty, and then return its right subtree as the new left sub-tree. The operation is as follows:
The code is implemented as follows:
public void Delmin () { root = delmin (root);} Private node Delmin (node root) { if (root). left = = null) return root. Right; Root. left = Delmin (root. left); Root. Number = Size (root. left) + Size (root. right) + 1; return root;}
Deleting the maximum value is similar.
Now to analyze the general situation, suppose we want to delete a node of the specified key. The difficulty with this problem is that it is easier to delete the maximum minimum value, delete the node with only 1 child nodes, or have no child nodes. However, if you delete any node, it is possible to delete the node has 0, 1, 2 child nodes of the situation, now to analyze each.
When the deleted node has no child nodes , the link directly to the node that the parent node points to is set to null.
when the deleted node has only 1 child nodes , replace that point with the node you want to delete.
When the deleted node has 2 child nodes, the problem becomes complicated.
Suppose we delete a node T with two child nodes. Because T has a right child node, we need to find the smallest node in its right child node, replacing the location of the T node. Here are four steps:
1. Save the deleted node to the TEMP variable t
2. Save the Min node min (t.right) of the right node of T to the temporary node X
3. Set the right node of X to Deletemin (T.right), and the right node is the largest node after deletion, all than X.key.
4. Set the node of X as the left node of T.
The whole process is as follows:
The corresponding code is as follows:
public void Delete (TKey key) { root =delete (root, key); } Private node Delete (node x, TKey key) { int cmp = Key.compareto (x.key); if (cmp > 0) x.right = Delete (X.right, key); else if (CMP < 0) X.left = Delete (X.left, key); else { if (x.left = = null) return x.right; else if (x.right = = null) return x.left; else { Node t = x; x = Getminnode (t.right); X.right = Delmin (t.right); X.left = T.left; } } X.number = Size (x.left) + size (x.right) + 1; return x;} Private node Getminnode (node x) { if (x.left = = null) return x; else return Getminnode (x.left); }
The algorithm for deleting nodes above two forks find tree is not perfect, because the binary tree becomes less balanced as the deletion progresses, and the following is an animated demonstration.
Three-analysis
The run time of a binary lookup tree is related to the shape of the tree, and the shape of the tree is related to the order in which the elements are inserted. In the best case, the node is fully balanced, from the root node to the bottom leaf node only LGN nodes. In the worst case, the root node will have n nodes to the bottom leaf node. Under normal circumstances, the shape of the tree is close to the best situation.
When analyzing binary search trees, we usually assume that the order in which elements are inserted is random. The analysis of BST is similar to that found in fast sorting:
The element at the top of the BST is the first divided element in the quick sort, the element to the left of the element is all smaller than the element, and the element on the right is greater than the element.
For n different elements, randomly inserted two-fork search tree, its average find/insert time complexity of about 2lnN, this and the analysis of fast sequencing, the concrete proof method is no longer repeat, refer to the fast sorting.
Iv. Summary
With the analysis of the two-point search in the previous article, it should be easier to understand the two-fork search tree. Here is the time complexity of the two-fork find tree:
As with binary lookups, the time complexity of insertions and lookups is LGN, but in the worst case there is still a time complexity of N. The reason is that when inserting and deleting elements, the tree does not maintain balance. What we're looking for is that there's still a good time complexity in the worst case, and that's what's behind the balance finding tree. The following first explains the simplest form of balancing the search tree: 2-3 find tree.
Hopefully this article will help you understand the binary search tree.
Find, insert, and delete binary lookup trees-Java implementation