Algorithm and data structure [Java implementation]: binary search tree

Linked list can easily store data, but the organization of data can only be linear, there can be no hierarchical organization of data, and the search elements need linear search, complexity O(n).

Binary search tree is a hierarchical way to organize data by sorting

It is characterized by:

(1) If the left subtree is not empty, the values of all nodes on the left subtree are smaller than the values of its root nodes;

(2) If the right subtree is not empty, the values of all nodes on the right subtree are greater than the values of its root nodes;

That is, for any subtree, the values of all nodes in the left subtree are less than the root node, and the values of all nodes in the right subtree are less than the root node.

The optimal complexity of searching, inserting and deleting is log(n)

In extreme cases, if the binary search tree data is sorted, the tree will degenerate into a linked list, which is as complex as the linked list.

Then:

In the random case, how efficient is the binary search tree?

Test code:

BST tree = new BST();
		
		Random rand = new Random();
		double totalTime = 0;
		for (int i=0;i<=3000000; i++)
			tree.Insert(rand.nextInt(10000000));
		//tree.tranformIntoPerfectTree();
		for (int i=0;i<100;i++) {
			long time = System.currentTimeMillis();
			tree.Contains(new BSTNode(rand.nextInt(10000000)));
			totalTime += System.currentTimeMillis()-time;	
		}
		System.out.println("The average time to find 1000 times in 10 million data: "+totalTime/100);

Test results:

Randomly generate 3 million data (too much memory to bear), add binary search tree, test 100 times, average time: 67.63ms

In order to improve the efficiency of searching, we want a binary tree to be as complete as possible

That is to say, only the bottom two layers of the whole tree are not satisfied, and the other layers are full.

Therefore, two algorithms are proposed

(1)DSW

After a certain amount of data is stored, the binary search tree is stretched into a linked list according to certain rules, and then the data is reorganized to make the data close to the complete binary tree. The following code uses this method to rebuild the binary search tree. Because this method is to rebuild a tree with all the data, it is also called "global reconstruction"

(2)AVL

After storing a data, it does not affect the balance of the whole tree, because the data is always inserted at the bottom. Therefore, only local adjustment can be made.

This method is also called "local reconstruction" (this method will be implemented in the next blog)

Let's see.

The efficiency of balanced binary search tree

The test code and test conditions are the same as above, and the balance function tranformIntoPerfectTree() is added

It doesn't change much. This is because we generate data randomly. If the data has certain rules, the efficiency will be improved a lot.

 

For binary search trees, there are the following:

Properties:

Root: the root of a tree, as the entry to the tree

Size: the size of the number. Unnecessary. It can be obtained by traversal when using

Method:

Insert: Insert

remove: delete and return the deleted data

isEmpty: judge whether the tree is empty

Contains: whether to include some data

Rotatereight / rotateleft: rotates the tree, which is a sub method used in the DSW method

transformIntoBackbone: the first step of DSW method, transforming tree into linked list

tranformIntoPerfectTree: global reconstruction of two tree using DSW method

dfs: depth first search, return search path, middle order traversal of binary search tree is data sorting, using recursion, consuming resources

bfs: breadth first traversal, large memory usage

 

Here is the code of binary search tree:

package BST;

import java.util.ArrayList;
import java.util.Random;

public class BST {
	int size;
	BSTNode root;
	
	public BST() {
		root = null;
		size = 0;
	}
	public boolean isEmpty() {
		return root == null;
	}
	public void Insert(int value) {
		Insert(new BSTNode(value));
	}
	
	public boolean Contains(BSTNode node) {
		return Contains(node, root);
	}
	
	public boolean Remove(BSTNode node) {
		BSTNode[] fatherNode = new BSTNode[1];
		BSTNode toDelete = Search(node, fatherNode);		
		if (toDelete == null)
			return false;
		if (toDelete.left == null && toDelete.right == null)
			return false;
		
		if (toDelete.left == null && toDelete.right != null) {
			fatherNode[0].right = toDelete.right;
		}
		else if (toDelete.left != null && toDelete.right == null) {
			fatherNode[0].left = toDelete.left;
		}
		else if (toDelete.left != null && toDelete.right != null) {
			if(toDelete.right.right != null) {
				toDelete.right.right.left = toDelete.right.left;
				toDelete.right.left = toDelete.left;
			}
			else {
				if(toDelete.right.left != null)
					Insert(toDelete.right.left);
				toDelete.right.left = toDelete.left;
			}
			if(root != fatherNode[0])
				if (BSTNode.equals(fatherNode[0].right, toDelete))
					fatherNode[0].right = toDelete.right;
				else 
					fatherNode[0].left = toDelete.right;
			else {
				root = toDelete.right;
			}
		}
		size--;
		return true;
	}
	
	public void tranformIntoPerfectTree() {
		if (isEmpty() || size == 1) return ;
		transformIntoBackbone();	//Convert to skeleton (right)
		//System.out.println("________________________________________");
		//printSelf();
		
		int n = this.size;
		int m = (int) Math.pow(2, Math.floor(Math.log10(n+1)/Math.log10(2))) - 1;
		int cnt = n-m;
		if(cnt>0) {
			rotateLeft(null, root);
			cnt--;
		}
		//System.out.println("m:"+m+" cnt: "+cnt);
		//printSelf();
		
		//System.exit(0);
		BSTNode grand = root;
		BSTNode now = root.right;
		if(cnt>0)
			while(true) {
				//System.out.println("___________In While_____________________________");
				//printSelf();
				rotateLeft(grand, now);
				//System.out.println("___________In While_____________________________");
				//printSelf();
				cnt--;
				if(cnt==0) break;
				grand = grand.right;
				now = grand.right;
			}
		
		while(m>1) {
			m=m/2;
			int tmp = m;
		
			if (tmp>=1) {
				rotateLeft(null, root);
				tmp--;
			}
			
			grand = root;
			now = root.right;
			//System.out.println("Pre Rotating: " + root.value + " " + root.right.value);
			while(tmp>0) {
				rotateLeft(grand, now);
				tmp--;
				if(tmp==0) break;
				grand = grand.right;
				now = grand.right;
			}
		}
		
	}
	
	public void transformIntoBackbone() {
		BSTNode grand = null;
		BSTNode now = root;
		while(now != null) {
			//System.out.println((grand==null?"null":grand.value) + " " + now.value);
			if (now.left != null) {
				rotateRight(grand, now);
				if(grand!=null)
					now = grand.right;
				else
					now = root;
				//System.out.println("exce 1");
				//System.out.println("___________In While_____________________________");
				//printSelf();
			}
			else {
				grand = now;
				now = now.right;
				//System.out.println("exce 2");
			}
		}
	}
	
	public void transformIntoBackboneLeft() {
		BSTNode grand = null;
		BSTNode now = root;
		while(now != null) {
			if (now.right != null) {
				rotateLeft(grand, now);
				if(grand!=null)
					now = grand.left;
				else
					now = root;
			}
			else {
				grand = now;
				now = now.left;
			}
			
		}
	}
	
	
	
	
	
	private void rotateRight(BSTNode grand, BSTNode node) {
		if (node.left == null) return ;
		BSTNode nodeLeft = node.left,
				nodeRight = node.right,
				child = node.left,
				childLeft = node.left.left,
				chileRight = node.left.right;
		node.left = chileRight;
		child.right = node;
		if(grand == null) {
			root = child;
		}
		else {
			grand.right = child;
		}
	}

	
	private void rotateLeft(BSTNode grand, BSTNode node) {
		if (node == null || node.right == null) return ;
		BSTNode nodeLeft = node.left,
				nodeRight = node.right,
				child = node.right,
				childLeft = node.right.left,
				chileRight = node.right.right;
		node.right = childLeft;
		child.left = node;
		if(grand == null) {
			root = child;
		}
		else {
			grand.right = child;
		}
	}
	
	private BSTNode Search(BSTNode node, BSTNode[] fatherNode) {
		if(isEmpty()) 
			return null;
		fatherNode[0] = root;
		BSTNode search = root;
		while(true) {
			if(search == null) return null;
			if (BSTNode.equals(search, node)) {return search;}
			fatherNode[0] = search;			
			if (node.value < search.value)
				search = search.left;
			else
				search = search.right;
		}
	}
	
	private void Insert(BSTNode node) {
		//System.out.print("Value: " + node.value + " ");
		if (isEmpty()) {
			root = node;
			size = 1;
			return ;
		}
		BSTNode search = root;
		while(true) {
			//System.out.print("node value: "+ search.value + " ");
			if (node.value < search.value)
				if (search.left == null) {
					search.left = node;
					//System.out.println("add to left ");
					break;
				}
				else {
					search = search.left;
					//System.out.println("add to left ");
				}
			else 
				if (search.right == null) {
					search.right = node;
					//System.out.println("add to right ");
					break;
				}
				else {
					search = search.right;
					//System.out.println("add to right ");
				}
		}
		size++;
	}
	
	private boolean Contains(BSTNode targetNode, BSTNode nowNode) {
		if (isEmpty())
			return false;
		if (nowNode == null)
			return false;
		if (BSTNode.equals(targetNode, nowNode))
			return true;
		return Contains(targetNode, nowNode.left) || Contains(targetNode, nowNode.right);
	}
	
	public void dfs(int[] result, int[] cnt, BSTNode node) {
		if (isEmpty())
			return ;
		//System.out.println("To Node:" + node.value);
		if (node.left != null) {
			//System.out.print("L"+node.value+" ");
			dfs(result, cnt, node.left);
		}
		result[cnt[0]++] = node.value;
		
		if (node.right != null) {
			//System.out.print("R"+node.value+" ");
			dfs(result, cnt, node.right);
		}
		return ;
	}
	public void bfs(int[] result, int[] cnt) {
		if (isEmpty())
			return ;
		ArrayList<BSTNode> list = new ArrayList();
		list.add(root);
		while(!list.isEmpty()) {
			BSTNode now = list.remove(0);
			if (now.left != null)
				list.add(now.left);	
			if (now.right != null)
				list.add(now.right);
			result[cnt[0]++] = now.value;
		}
	}
	
	public void printSelf() {
		int[] result = new int[this.size];
		int[] cnt = new int[1];
		this.dfs(result, cnt, this.root);
		System.out.println("\nDFS: ");
		for(int i=0; i<result.length; i++)
			System.out.print(result[i] + " ");
		System.out.println(" Size: "+ this.size);
		
		cnt[0] = 0;
		result = new int[this.size];
		this.bfs(result, cnt);
		System.out.println("BFS: ");
		for(int i=0; i<result.length; i++)
			System.out.print(result[i] + " ");
		System.out.println();
	}
	
	static public void main(String[] argv) {
		BST tree = new BST();
		
		Random rand = new Random();
		double totalTime = 0;
		for (int i=0;i<=3000000; i++)
			tree.Insert(rand.nextInt(10000000));
		tree.tranformIntoPerfectTree();
		for (int i=0;i<100;i++) {
			long time = System.currentTimeMillis();
			tree.Contains(new BSTNode(rand.nextInt(10000000)));
			totalTime += System.currentTimeMillis()-time;	
		}
		System.out.println("The average time to find 1000 times in 10 million data: "+totalTime/100);
		//tree.Insert(10);tree.Insert(5);tree.Insert(11);tree.Insert(6);tree.Insert(3);
		
		//tree.printSelf();
		
		//tree.Remove(new BSTNode(14));
		//tree.Remove(new BSTNode(10));
		//tree.printSelf();
		//tree.rotateRight(null, tree.root);
		
		//tree.transformIntoBackbone();
		//tree.printSelf();
		//tree.transformIntoBackboneLeft();
		//tree.printSelf();
		
		//tree.tranformIntoPerfectTree();
		//tree.printSelf();
	}
}


class BSTNode{
	public int value;
	public BSTNode left;
	public BSTNode right;
	
	static boolean equals(BSTNode a, BSTNode b) {
		if(a==b && b==null) return true;
		if(a==null || b==null) return false;
		return a.value == b.value;
	}
	
	public BSTNode(int value) {
		this.value = value;
	}
	public BSTNode(int value, BSTNode left, BSTNode right) {
		this.value = value;
		this.left = left;
		this.right = right;
	}
	
}

 

85 original articles published, 54 praised, 40000 visitors+
Private letter follow

Tags: less Java

Posted on Thu, 13 Feb 2020 09:19:17 -0500 by tave