Binary lookup trees (binary search tree, also known as binary tree or binary sort tree) is a very important data structure, many high-level tree structures are two binary search tree variants, such as AVL tree, red and black trees, understanding binary search tree for the subsequent tree structure of learning has a good effect. At the same time, binary search tree can be used to sort, called binary ordering, is also a very important idea.
In this paper, the main reference algorithm introduction, the principle of binary search tree and specific Python and Java code implementation.
1. Definition
A lookup tree is a data structure that supports a variety of dynamic collection operations, including Search,minimum,maximum,predecessor,successor,insert and delete. It can be used as either a dictionary or as a priority queue.
Description of the wiki:
The nature of binary tree lookups:
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. The right subtree of any node is not empty, then 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. There are no nodes with key values equal (no duplicate nodes).
4. Two forks the advantage of finding trees compared to other data structures is that the time complexity of finding and inserting is low. is O (log n).
Binary lookup tree is a basic data structure used to construct more abstract data structures, such as collections, multiset, associative arrays, and so on.
Although the worst-case efficiency of a binary lookup tree is O (n), it supports dynamic querying, and there are many improved versions of the two-prong lookup tree that make the tree high for O (Logn), such as SBT,AVL, red-black trees, and so on.
Two. Python implementation
Take the following illustration of the two-fork tree as an example to illustrate the lookup algorithm
Node class
Create a class named node, which is a two-fork tree node structure, which includes: Zodi, right branch, node data three variables.
class Node: """ 二叉树左右枝 """ def __init__(self, data): """ 节点结构 """ self.left = None self.right = None self.data = data
For example, create a node with an integer 8. Because only a single node is created, the left and right branches are none.
root = Node(8)
This gives you a tree of only one node as shown.
Insert method
Now that there is a bare tree, with branches and leaves, you must add new nodes and data using the Insert data method.
def insert(self, data): """ 插入节点数据 """ if data < self.data: if self.left is None: self.left = Node(data) else: self.left.insert(data) elif data > self.data: if self.right is None: self.right = Node(data) else: self.right.insert(data)
To undertake the previous operation, you can increase the tree branches and leaves (left and right branch and node data) in the following way.
root.insert(3)root.insert(10)root.insert(1)
When the second node of data 3 is added, the program will:
- In the first step, root calls Insert (), whose arguments are data=3
- The second step, compare 3 and 8 (existing root node), 3:8 small. And the left branch of the tree is none, so it creates a new node on the left.
With the addition of the third node data 10, the program will:
- The first step, just like the first step in the front, is only data=10
- The second step, found that 10 is greater than 8, while the right is none, so it as the right to create a new branch node data.
Adding the fourth node Data 1, the program will:
- First step, ibid., data=1
- The second step, 1 is less than 8, so to be placed on the left branch of the tree;
- In the third step, the left branch already has child node 3, the node calls the Insert () method again, 1 is less than 3, so 1 is the child node of 3, and placed on the left side of the original is none.
So, the tree that was formed
Continue to increase node data
root.insert(6)root.insert(4)root.insert(7)root.insert(14)root.insert(13)
The final form of the tree
Traverse Tree
This method is used to find a node in the tree and returns the node if it is found, otherwise none is returned. For convenience, the parent node is also returned.
def lookup(self, data, parent=None): """ 遍历二叉树 """ if data < self.data: if self.left is None: return None, None return self.left.lookup(data, self) elif data > self.data: if self.right is None: return None, None return self.right.lookup(data, self) else: return self, parent
Test it, find the node with the data 6.
node, parent = root.lookup(6)
After calling lookup (), the program will do the following:
- Call lookup (), pass parameter data=6, default Parent=none
- Data=6, the value of the small root node 8
- The pointer goes to the left of the root node, at this point: data=6,parent=8, call lookup again ()
- Data=6 is greater than the first-level node data on the left 3
- The pointer goes to the right branch of 3, data=6,parent=3, and calls lookup again ()
- The node data equals 6, so the node and its parent node 3 are returned.
Delete method
Deletes the node data. The code is as follows:
def delete (self, data): "" "" "" "" "" "" node, parent = self.lookup (data) #已有节点 if node was not None: Children_count = Node.children_count () #判断子节点数 if Children_count = = 0: # If there are no child nodes under the node, you can delete If parent.left is node:parent.left = None Else:parent.right = None del node Elif children_count = = 1: # If there is a child node, let the child node move up and replace the node (the node disappears) if Node.left: n = node.left else:n = node.right if Parent:if parent.left is Node:parent.left = n else:parent.right = n del node else: # If there are two child nodes, then you want to judge all the leaves under the node parent = node successor = node.right while Su Ccessor.left:parent = Successor successor = Successor.left Node.data = successor . Data if PareNt.left = = Successor:parent.left = Successor.right Else:parent.right = Successo R.right
In the above method, after getting the number of child nodes under the current node, we need to judge three kinds of cases.
- If there are no child nodes, delete them directly
- If there is a child node, to move the next child node up to the current node, that is, replace the
- If you have two child nodes, judge the data of your own point and sort the nodes from the new one.
The method used in the above method to count the number of child nodes, the code is as follows:
def children_count(self): """ 子节点个数 """ cnt = 0 if self.left: cnt += 1 if self.right: cnt += 1 return cnt
Example 1: Delete a node with data 1, which is a child of 3, and 1 has no child nodes
root.delete(1)
Compare two binary trees
In the comparison of two binary tree methods, if one node (leaf) differs from another tree, it returns false, including the absence of a corresponding leaf.
def compare_trees(self, node): """ 比较两棵树 """ if node is None: return False if self.data != node.data: return False res = True if self.left is None: if node.left: return False else: res = self.left.compare_trees(node.left) if res is False: return False if self.right is None: if node.right: return False else: res = self.right.compare_trees(node.right) return res
For example, compare tree (3,8,10) and tree (3,8,11)
root2 是tree(3,8,11)的根root 是tree(3,8,10)的根root.compare_trees(root2)
Execute the above code and the program will go like this:
- Root calls the Compare_trees () method
- Root has a left child node, which invokes the node's compare_trees ()
- Two left child nodes comparison, return True
- Follow previous procedure, compare right node, find different, then return false
Print Tree
Print the two-fork tree in a certain order. No parameters are required. The practice is to first left and right (left less than right).
def print_tree(self): """ 按顺序打印数的内容 """ if self.left: self.left.print_tree() print self.data, if self.right: self.right.print_tree()
Operation:
root.print_tree()
Output: 1, 3, 4, 6, 7, 8, 10, 13, 14
Generator that contains all the tree elements
It is sometimes necessary to create a generator that contains all the tree elements. Given the memory problem, it is not necessary to generate all the node data lists in real time, but to return the value of the next node each time this method is called. To do this, use it to return an object and stop there, and the function will continue to return the value through the yield keyword the next time the method is called. In this case, you cannot use recursion to use the stack.
def tree_data(self): """ 二叉树数据结构 """ stack = [] node = self while stack or node: if node: stack.append(node) node = node.left else: node = stack.pop() yield node.data node = node.right
For example, get a tree by looping:
for data in root.tree_data(): print data
The program takes the data to the stack, stacks, and takes the values in order, and returns the results, according to the atoms on the left and right.
Three. Java implementation insert operation
Binary tree Find tree b the procedure for inserting an operation x is as follows:
1, if B is an empty tree, the inserted node is inserted directly as the root node.
2, x equals the value of the data of the root node of B, then returns directly, otherwise.
3. If x is less than the value of the data of the root node of B, change the position of the node where x is to be inserted to the left subtree of B, otherwise. 4. Change the position of the node where x is going to go to the right sub-tree of B.
/** Insert Element * / Public void Insert(T T) {roottree = insert (t, roottree); }/** Start judging the insertion element at a certain location * / PublicBinarynode<t>Insert(T t,binarynode<t> node) {if(node==NULL) {//New construct a binary search tree return NewBinarynode<t> (T,NULL,NULL); }intresult = T.compareto (node.data);if(result<0) node.left= Insert (t,node.left);Else if(result>0) node.right= Insert (t,node.right);Else;//donothing returnNode }
Find operations
The process of finding x in the binary lookup tree is as follows:
1, if the binary tree is empty tree, then the search failed.
2, if x equals the root node of the data, then find success, otherwise.
3, if X small root node data, then recursively find its left subtree, otherwise.
4, recursively find its right subtree.
Follow the steps above to write out the code for its find operation.
/** finds the specified element by default from the * root node of the start query */ Public Boolean contains(T T) {returnContains (t, Roottree); }/** start looking for elements from a node * / Public Boolean contains(t T, binarynode<t> node) {if(node==NULL)return false;//node is empty, lookup failed intresult = T.compareto (node.data);if(result>0)returnContains (t,node.right);//recursive query right subtree Else if(result<0)returnContains (t, Node.left);//recursive query left subtree Else return true; }/** Here I provide a search for the minimum value of the maximum value of a two-fork tree * / /** Find the minimum value in the two-fork find tree * / PublicTFindmin() {if(IsEmpty ()) {System.out.println ("binary tree is empty");return NULL; }Else returnFindmin (roottree). data; }/** Find the maximum value in a two-fork find tree * / PublicTFindmax() {if(IsEmpty ()) {System.out.println ("binary tree is empty");return NULL; }Else returnFindmax (roottree). data; }/** Query the node where the smallest element is located * / PublicBinarynode<t>Findmin(binarynode<t> node) {if(node==NULL)return NULL;Else if(node.left==NULL)returnNodereturnFindmin (Node.left);//Recursive lookup}/** Query the node where the largest element is located * / PublicBinarynode<t>Findmax(binarynode<t> node) {if(node!=NULL) { while(node.right!=NULL) Node=node.right; }returnNode }
A classical binary tree search algorithm
Self-use bug-free two-fork Tree algorithm code:
intBinarySearch (intArray[],intNint value){intleft =0;intright = N-1;//If this is int right = N, then there are two places below that need to be modified to ensure that one by one corresponds: //1, the following loop condition is while (left < right) ///2, within the loop when Array[middle] > value, right = Mid while(left <= right)//cycle conditions, timely and change{intMiddle = left + ((right-left) >>1);//Prevent overflow, shift is also more efficient. At the same time, each cycle needs to be updated. if(Array[middle] >value) {right = middle-1;//right assignment, timely and change}Else if(Array[middle] <value) {left = middle +1; }Else returnMiddle;//There may be readers who think that the first judgment is equal, but after all the inequality in the array is more //If each cycle is judged equal, it will be time consuming}return-1;}
Two-tree lookup algorithm in JDK:
/** * * @Title: JDK's own arrays two-tree Find implementation code * @Description: Find key in a array and return to its position * @date : 2016/6/22 19:16 * @param * @return * * //Like public version, but without range checks. Private Static int BinarySearch0(Object[] A,intFromIndex,intToindex, Object key) {intlow = FromIndex;intHigh = Toindex-1; while(Low <= High) {intMid = (low + high) >>>1;@SuppressWarnings("Rawtypes") Comparable midval = (comparable) a[mid];@SuppressWarnings("Unchecked")intCMP = Midval.compareto (key);if(CMP <0) Low = mid +1;Else if(CMP >0) High = mid-1;Else returnMid//Key found}return-(Low +1);//Key not found.}
See my github for detailed implementation code for Java and Python above.
Reference article: http://www.laurentluce.com/posts/binary-search-tree-library-in-python/comment-page-1/
Binary search Tree