This binary search tree content, there are several years of project experience is not necessarily!

You may have several years of project experience, and you may also be a leader in the technology field in your company, but you may not always be able to do this binary search tree.

Let's cut the crap and make it whole!

What is a two point search tree?

Binary search tree is also called binary search tree. It can be said that it is an application of binary tree and also a data structure of binary tree, as shown in the figure:

characteristic:

For each node, the left child is smaller than the node, and some children are larger than the node.

Since it is a binary tree, it is also a dynamic data structure. You can use node classes to store each node, as follows:

class Node{
	E e;
	Node left;	//Left child
	Node right;	//Right child
}

This structure of tree is very suitable for returning to realize various operations, and is often a confusing scene. If you don't develop the idea of recursion, you will often be confused about this recursive operation of the tree. Next, we will analyze various recursive operations.

add operation of binary search tree

Recursion starts at the root node and chains the new node into the binary tree by return. Cases ① and ② are the base cases of recursion, and recursion calls are made in cases ③ and ④.

private Node add(Node node, E e) {
	if(node == null) {
		size++;
		return new Node(e);
	}
	if(e.compareTo(node.e) < 0) {
		node.left = add(node.left, e);
	}
	if(e.compareTo(node.e) > 0){
		node.right = add(node.right, e);
	}
	return node;
}

Tips:

When comparing node values, we can't use basic operators (we choose generic type, only wrapper class and reference class, and can't use basic operators for object size comparison); we need to use comparaTo() in the comparable class

contains operation of binary search tree

Binary search tree gives binary tree a storage order, which makes our operations on binary tree easier.

The binary tree is not changed in the query operation, so the return node is not needed, only the Boolean value returned is used to judge the search result.

private boolean contains(Node node, E e) {
	if(node == null) {
		return false;
	}else if(e.compareTo(node.e) == 0) {
		return true;
	}else if(e.compareTo(node.e) < 0) {
		return contains(node.left, e);
	}else{
		return contains(node.right, e);
	}
}

Depth traversal of binary search tree

First root traversal (DLR), also known as first order traversal: first access to the root node, then traverse the left subtree, traverse the right subtree.

In the binary tree shown in the figure, the first root traversal result is: 53 12 9 14 64 78

private void perOrder(Node node) {
	//DLR
	if(node == null)
		return;
	else {
		System.out.print(node.e+" ");
		perOrder(node.left);
		perOrder(node.right);
	}
	}

Middle order traversal (LDR), also known as symmetric traversal: first traverse the left subtree, then visit the root node, traverse the right subtree.

In the binary tree shown in the figure, the traversal result in use is: 9 12 14 53 64 78

private void inOrder(Node node) {
	//LDR
	if(node == null)
		return;
	else {
		inOrder(node.left);
		System.out.print(node.e+" ");
		inOrder(node.right);
	}
}

Post order traversal (LRD): first traverses the left subtree, then traverses the right subtree, and then accesses the root node.

In the binary tree shown in the figure, the result of using post order traversal is: 9 14 12 78 64 53

private void postOrder(Node node) {
	//LRD
	if(node == null)
		return;
	else {
		postOrder(node.left);
		postOrder(node.right);
		System.out.print(node.e+" ");
	}
}

After looking at the three traversal methods, it is found that although the order is different, the order of the printed statements is mainly reflected in the programming; it is precisely because the execution depth and order of the statements before and after the recursive call are different, which supports the depth traversal of the tree.

Tips:

Depth traversal is defined according to recurrence. The default direction is from left to right, or from right to left, which is called reverse traversal.

Non recursive implementation of depth first traversal

First order traversal (DLR): using queues to assist traversal

Algorithm idea

Queue the root node. When the queue is not empty, repeat the following steps:

① Team leader node

② Print team header node

③ Determine whether the left subtree of the team head node is empty. If the left subtree is empty, the right subtree of the team head node (if the right subtree is not empty); otherwise, the left subtree and the right subtree of the team head node (if the right subtree is not empty), and at the same time, ensure that the left subtree is always in the team head

public void preOrder() {
	//Preorder traversal
	if(root == null)
		return;
	Queue<Node> que = new LinkedList<>();
	que.add(root);
	while(!(que.isEmpty())) {
		Node node = que.remove();
		if(node.left == null) {
			System.out.print(node.e+" ");
			if(node.right != null)
				que.add(node.right);
		}else {
			System.out.print(node.e+" ");
			int n = que.size();
			que.add(node.left);
			if(node.right != null)
				que.add(node.right);
			for(int i = 0; i < n; i++) {
				que.add(que.remove());
			}
		}
	}
}

Middle order traversal (LDR): using stack to achieve traversal

Algorithm idea

Starting from the root node, when the node is not empty or the stack is not empty, repeat the following steps:

① The current node is not empty. Queue the current node and traverse the left subtree to the empty tree

② The current node is empty, leave the top node of the queue stack and print, traverse the right subtree

public void inOrder() {
	Stack<Node> stack = new Stack<>();
	Node node = root;
	while(node != null || !(stack.isEmpty())) {
		if(node != null) {
			stack.push(node);
			node = node.left;
		}else {
			node = stack.pop();
			System.out.print(node.e+" ");
			node = node.right;
		}
	}
}

Post order traversal (LRD): using stack to achieve traversal

Algorithm idea

Starting from the root node, when the node is not empty or the stack is not empty, repeat the following steps:

① The current node is not empty, the current node and the child (the right child is not empty) are pushed, and the right subtree is traversed to the empty tree

② The current node is empty, the right subtree of the top element of the stack is empty or the right child has just visited it. After the stack is released and the top node of the stack is printed, set the current node as just visited; otherwise, traverse the right subtree

public void postOrder() {
	//Post order traversal (post root traversal)
	Stack<Node> stack = new Stack<>();
	Node node = root;
	Node visited = null;
	while(node!=null || !stack.isEmpty()) {
		if(node != null) {
			stack.push(node);
			if(node.right != null)
				stack.push(node.right);
			node = node.left;
		}else {
			node = stack.pop();
			if(node.right == null || node.right == visited) {
				System.out.print(node.e+" ");
				visited = node;
				node = null;
			}else {
				stack.push(node);
				node = node.right;
			}
		}
	}
}

Breadth first traversal of binary search tree

Breadth first traversal, also known as hierarchical traversal, traverses all nodes once per layer. Here we implement it with the help of queues.

Starting from the root node, first enter the queue root node, and repeat the following steps: if the left and right children of the queue head node are not empty, exit the queue head node and print, enter the left and right children of the queue node; otherwise, exit the queue head node and print.

public void levelOrder() {
	//level traversal 
	Queue<Node> temporary = new LinkedList<>();
	temporary.add(root);
	while(!temporary.isEmpty()) {
		Node node = temporary.remove();
		if(node.left != null)
			temporary.add(node.left);
		if(node.right != null) {
			temporary.add(node.right);
		}
		System.out.print(node.e+" ");
	}
}

minimum and maximum

Minimum and maximum represent the minimum and maximum values in the binary search tree. There are two operations about the maximum and minimum values. Find the maximum and minimum values in the binary search tree, and delete the maximum and minimum values.

Query minimum and maximum

The maximum and minimum value in binary search tree must be the left subtree with the largest depth and the right subtree with the largest depth. In this way, it can be operated directly by recursion. The query does not change the binary tree, so it does not need to change the root node.

private Node minimum(Node node) {
	if(node.left != null) {
		return minimum(node.left);
	}else {
		return node;
	}
}
private Node maximum(Node node) {
	if(node.right != null) {
		return maximum(node.right);
	}else {
		return node;
	}
}

Delete minimum and maximum

Delete operation will change the nodes of binary search tree. First, traverse the left (right) subtree to the empty tree (that is, to the maximum and minimum nodes of binary search tree), and chain the right subtree of the minimum (maximum) contact into the precursor node.

private Node removeMinimum(Node node) {
	if(node.left == null) {
		Node rightNode = node.right;
		node.right = null;
		size--;
		return rightNode;
	}else {
		node.left = removeMinimum(node.left);
		return node;
	}
}
private Node removeMaximum(Node node) {
	if(node.right == null) {
		Node leftNode = node.right;
		node.left = null;
		size--;
		return leftNode;
	}else{
		node.right = removeMaximum(node.right);
		return node;
	}
}

Tips:

When deleting a node, we can't use the cyclic iteration method to find and set the node value to null to complete the deletion. What we see in all binary tree codes is the reference of the node, and we can't delete the node. We can only change the reference of the node, point it to null, and link the deletion result into the binary tree, without the reference to the node , will be recycled by the garbage collection mechanism.

Delete any node of binary tree

First, let's look at the rules for deletion:

① The node to be deleted has no right subtree, and the left subtree of the node to be deleted is directly chained into the left subtree of the predecessor node

② The node to be deleted has no left subtree, and the right subtree of the node to be deleted is directly chained into the right subtree of the predecessor node

③ The node to be deleted is the right subtree. Find the minimum value node in the right subtree. Replace the node to be deleted with the minimum value node. At the same time, delete the minimum value node in the right subtree

When deleting a node, we first need to locate the deleted node, and then traverse the left and right subtrees according to the node value to find and delete the node.

private Node removeNode(Node node,E e) {
	if(node == null)
		return null;
	if(e.compareTo(node.e) > 0) {
		node.right = removeNode(node.right,e);
		return node;
	}else if(e.compareTo(node.e) < 0) {
		node.left = removeNode(node.left,e);
		return node;
	}else{
		if(node.left == null) {
			Node rightNode = node.right;
			node.right = null;
			size--;
			return rightNode;
		}
		if(node.right == null) {
			Node leftNode = node.left;
			node.left = null;
			size--;
			return leftNode;
		}
		Node minNode = minimum(node.right);
		minNode.right = removeMinimum(node.right);
		minNode.left = node.left;
		return minNode;
	}
}

Print tree binary search tree

Through the different depth of nodes in the binary tree, the binary tree with 90 ° inversion can be printed by traversing the inverse middle order:

Printing order: 78 64 53 14 12 9 (traversal in reverse order). Only one node is printed at a time.

public void printTree() {
	printTree(root, 0);
}
private void printTree(Node node, int n) {
	if(node == null) {
		return;
	}
	printTree(node.right, n+1);
	for(int i = 0; i < n; i++) {
		System.out.print("t");
	}
	System.out.println(node.e);
	printTree(node.left, n+1);
	
}

All codes

import java.util.Queue;
import java.util.Stack;
import java.util.LinkedList;

public class BST <E extends Comparable<E>>{
	private int size;
	private Node root;
	private class Node{
		public E e;
		public Node left;
		public Node right;
		public Node(E e) {
			this.e = e;
			left = null;
			right = null;
		}
	}
	public BST() {
		root = null;
		size = 0;
	}
	///Get size
	public int getSize() {
		return size;
	}
	boolean isEmpty() {
		return size == 0;
	}
	///Adding binary search tree
	public void add(E e) {
		root = add(root, e);
	}
	private Node add(Node node, E e) {
		if(node == null) {
			size++;
			return new Node(e);
		}
		if(e.compareTo(node.e) < 0) {
			node.left = add(node.left, e);
		}
		if(e.compareTo(node.e) > 0){
			node.right = add(node.right, e);
		}
		return node;
	}
	///Binary search tree query operation
	public boolean contains(E e) {
		return contains(root, e);
	}
	private boolean contains(Node node, E e) {
		if(node == null) {
			return false;
		}else if(e.compareTo(node.e) == 0) {
			return true;
		}else if(e.compareTo(node.e) < 0) {
			return contains(node.left, e);
		}else{
			return contains(node.right, e);
		}
	}
	///Traversal operation of binary search tree
	/*public void preOrder() {
		//Preorder traversal
		perOrder(root);
	}*/
	public void preOrder() {
		//Preorder traversal
		if(root == null)
			return;
		Queue<Node> que = new LinkedList<>();
		que.add(root);
		while(!(que.isEmpty())) {
			Node node = que.remove();
			System.out.print(node.e+" ");
			if(node.left == null) {
				if(node.right != null)
					que.add(node.right);
			}else {
				int n = que.size();
				que.add(node.left);
				if(node.right != null)
					que.add(node.right);
				for(int i = 0; i < n; i++) {
					que.add(que.remove());
				}
			}
		}
	}
	private void perOrder(Node node) {
		//DLR
		if(node == null)
			return;
		else {
			System.out.print(node.e+" ");
			perOrder(node.left);
			perOrder(node.right);
		}
	}
	public void inOrder() {
		//Middle order traversal (symmetric traversal)
		inOrder(root);
	}
	/*public void inOrder() {
		Stack<Node> stack = new Stack<>();
		Node node = root;
		while(node != null || !(stack.isEmpty())) {
			if(node != null) {
				stack.push(node);
				node = node.left;
			}else {
				node = stack.pop();
				System.out.print(node.e+" ");
				node = node.right;
			}
		}
	}*/
	private void inOrder(Node node) {
		//LDR
		if(node == null)
			return;
		else {
			inOrder(node.left);
			System.out.print(node.e+" ");
			inOrder(node.right);
		}
	}
	public void postOrder() {
		//Post order traversal (post root traversal)
		postOrder(root);
	}
	/*public void postOrder() {
		//Post order traversal (post root traversal)
		Stack<Node> stack = new Stack<>();
		Node node = root;
		Node visited = null;
		while(node!=null || !stack.isEmpty()) {
			if(node != null) {
				stack.push(node);
				if(node.right != null)
					stack.push(node.right);
				node = node.left;
			}else {
				node = stack.pop();
				if(node.right == null || node.right == visited) {
					System.out.print(node.e+" ");
					visited = node;
					node = null;
				}else {
					stack.push(node);
					node = node.right;
				}
			}
		}

	}*/
	private void postOrder(Node node) {
		//LRD
		if(node == null)
			return;
		else {
			postOrder(node.left);
			postOrder(node.right);
			System.out.print(node.e+" ");
		}
	}
	public void levelOrder() {
		//level traversal 
		Queue<Node> temporary = new LinkedList<>();
		temporary.add(root);
		while(!temporary.isEmpty()) {
			Node node = temporary.remove();
			if(node.left != null)
				temporary.add(node.left);
			if(node.right != null) {
				temporary.add(node.right);
			}
			System.out.print(node.e+" ");
		}
	}
	///Get the minimum
	public E minimum() {
		if(size == 0)
			throw new IllegalArgumentException("Error:size Is zero");
		return minimum(root).e;
	}
	private Node minimum(Node node) {
		if(node.left != null) {
			return minimum(node.left);
		}else {
			return node;
		}
	}
	///Get maximum
	public E maximum() {
		if(size == 0)
			throw new IllegalArgumentException("Error:size Is zero");
		return maximum(root).e;
	}
	private Node maximum(Node node) {
		if(node.right != null) {
			return maximum(node.right);
		}else {
			return node;
		}
	}
	///Delete minimum
	public void removeMinimum() {
		if(size == 0)
			throw new IllegalArgumentException("Error:size Is zero");
		root = removeMinimum(root);
	}
	private Node removeMinimum(Node node) {
		if(node.left == null) {
			Node rightNode = node.right;
			node.right = null;
			size--;
			return rightNode;
		}else {
			node.left = removeMinimum(node.left);
			return node;
		}
	}
	///Delete Max
	public void removeMaximum() {
		if(size == 0)
			throw new IllegalArgumentException("Error:size Is zero");
		root = removeMaximum(root);
	}
	private Node removeMaximum(Node node) {
		if(node.right == null) {
			Node leftNode = node.right;
			node.left = null;
			size--;
			return leftNode;
		}else{
			node.right = removeMaximum(node.right);
			return node;
		}
	}
	public boolean removeNode(E e) {
		if(contains(e)) {
			root = removeNode(root, e);
			return true;
		}else
			return false;
	}
	private Node removeNode(Node node,E e) {
		if(node == null)
			return null;
		if(e.compareTo(node.e) > 0) {
			node.right = removeNode(node.right,e);
			return node;
		}else if(e.compareTo(node.e) < 0) {
			node.left = removeNode(node.left,e);
			return node;
		}else{
			if(node.left == null) {
				Node rightNode = node.right;
				node.right = null;
				size--;
				return rightNode;
			}
			if(node.right == null) {
				Node leftNode = node.left;
				node.left = null;
				size--;
				return leftNode;
			}
			Node minNode = minimum(node.right);
			minNode.right = removeMinimum(node.right);
			minNode.left = node.left;
			return minNode;
		}
	}
	///Print tree binary tree
	public void printTree() {
		printTree(root, 0);
	}
	private void printTree(Node node, int n) {
		if(node == null) {
			return;
		}
		printTree(node.right, n+1);
		for(int i = 0; i < n; i++) {
			System.out.print("t");
		}
		System.out.println(node.e);
		printTree(node.left, n+1);
		
	}
}

At this point, the realization of binary search tree and the source code are all finished.

Original link: https://blog.csdn.net/weixin_42089228/java/article/details/106290387

Source network, only for learning, if there is infringement, please contact delete.

I have compiled the interview questions and answers into PDF documents, as well as a set of learning materials, including Java virtual machine, spring framework, java thread, data structure, design pattern, etc., but not limited to this.

Focus on the official account [java circle] for information, as well as daily delivery of quality articles.

file

Tags: Programming Java network Spring

Posted on Sat, 30 May 2020 02:06:55 -0400 by VertLime