Data structure and algorithm: the basic part of tree structure

Basic part of tree structure

1, Binary tree

1. Why do you need a tree data structure

1.1 analysis of array storage mode

Advantages: it is fast to access elements by subscript. For ordered arrays, binary search can also be used to improve the retrieval speed.
Disadvantages: if a specific value is to be retrieved, or the inserted value (in a certain order) will move as a whole, which is inefficient [schematic]
Draw the operation diagram:

1.2 analysis of chain storage mode

Advantages: the array storage method is optimized to a certain extent (for example, if you insert a numeric node, you only need to link the inserted node to the linked list, and the deletion efficiency is also very good).
Disadvantages: when retrieving, the efficiency is still low, for example (to retrieve a value, you need to traverse from the beginning of the node)
Operation diagram:

1.3 analysis of tree storage mode

It can improve the efficiency of data storage and reading. For example, using binary sort tree can not only ensure the speed of data retrieval, but also ensure the speed of data insertion, deletion and modification.
Case: [7, 3, 10, 1, 5, 9, 12]

2. Schematic diagram of tree

Common terms for trees(Understand in combination with schematic diagram):
1.node
2.Root node
3.Parent node
4.Child node
5.Leaf node (Nodes without child nodes)
6.Weight of node(Node value)
7.route(from root Node finds the route of the node)
8.layer
9.subtree
10.Tree height(Max layers )
11.forest :Many subtrees form a forest

3. Concept of binary tree

  1. There are many kinds of trees, and each node can only have two child nodes at most. One form is called binary tree.
  2. The child nodes of binary tree are divided into left node and right node
  3. Sketch Map

  1. If all leaf nodes of the binary tree are in the last layer, and the total number of nodes = 2 ^ n - 1, n is the number of layers, then we call it a full binary tree.

  1. If all leaf nodes of the binary tree are in the last or penultimate layer, and the leaf nodes of the last layer are continuous on the left and the leaf nodes of the penultimate layer are continuous on the right, we call it a complete binary tree

4. Description of binary tree traversal

Use preorder, inorder and postorder to traverse the following binary tree

  1. Preorder traversal: first output the parent node, and then traverse the left and right subtrees
  1. Middle order traversal: first traverse the left subtree, then output the parent node, and then traverse the right subtree

  2. Post order traversal: first traverse the left subtree, then traverse the right subtree, and finally output the parent node

  3. Summary: see the order of output parent nodes to determine whether it is pre order, middle order or post order

4.1 application examples of binary tree traversal (pre order, middle order and post order)

code implementation

//Method of writing preorder traversal
	public void preOrder() {
		System.out.println(this); //Output parent node first
		//Recursive pre order traversal to the left subtree
		if(this.left != null) {
			this.left.preOrder();
		}
		//Recursive right subtree preorder traversal
		if(this.right != null) {
			this.right.preOrder();
		}
	}
	//Medium order traversal
	public void infixOrder() {
		
		//Recursive traversal to the middle order of the left subtree
		if(this.left != null) {
			this.left.infixOrder();
		}
		//Output parent node
		System.out.println(this);
		//Recursive traversal in right subtree
		if(this.right != null) {
			this.right.infixOrder();
		}
	}
	//Postorder traversal
	public void postOrder() {
		if(this.left != null) {
			this.left.postOrder();
		}
		if(this.right != null) {
			this.right.postOrder();
		}
		System.out.println(this);
	}

test

public class BinaryTreeDemo {

	public static void main(String[] args) {
		//First you need to create a binary tree
		BinaryTree binaryTree = new BinaryTree();
		//Create required nodes
		HeroNode root = new HeroNode(1, "Song Jiang");
		HeroNode node2 = new HeroNode(2, "Wu Yong");
		HeroNode node3 = new HeroNode(3, "Lu Junyi");
		HeroNode node4 = new HeroNode(4, "Lin Chong");
		HeroNode node5 = new HeroNode(5, "Guan Sheng");
		
		//Note: we first create the binary tree manually, and then we learn to create the binary tree recursively
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binaryTree.setRoot(root);
		
		//test
		System.out.println("Preorder traversal"); // 1,2,3,5,4
		binaryTree.preOrder();
		
		//test 
		System.out.println("Medium order traversal");
		binaryTree.infixOrder(); // 2,1,5,3,4
        		
		System.out.println("Postorder traversal");
		binaryTree.postOrder(); // 2,5,4,3,1
		
	}

}

//Define BinaryTree binary tree
class BinaryTree {
	private HeroNode root;

	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//Preorder traversal
	public void preOrder() {
		if(this.root != null) {
			this.root.preOrder();
		}else {
			System.out.println("Binary tree is empty and cannot be traversed");
		}
	}
	
	//Medium order traversal
	public void infixOrder() {
		if(this.root != null) {
			this.root.infixOrder();
		}else {
			System.out.println("Binary tree is empty and cannot be traversed");
		}
	}
	//Postorder traversal
	public void postOrder() {
		if(this.root != null) {
			this.root.postOrder();
		}else {
			System.out.println("Binary tree is empty and cannot be traversed");
		}
	}
}

//Create the HeroNode node first
class HeroNode {
	private int no;
	private String name;
	private HeroNode left; //Default null
	private HeroNode right; //Default null
	public HeroNode(int no, String name) {
		this.no = no;
		this.name = name;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
	
	
	//Method of writing preorder traversal
	public void preOrder() {
		System.out.println(this); //Output parent node first
		//Recursive pre order traversal to the left subtree
		if(this.left != null) {
			this.left.preOrder();
		}
		//Recursive right subtree preorder traversal
		if(this.right != null) {
			this.right.preOrder();
		}
	}
	//Medium order traversal
	public void infixOrder() {
		
		//Recursive traversal to the middle order of the left subtree
		if(this.left != null) {
			this.left.infixOrder();
		}
		//Output parent node
		System.out.println(this);
		//Recursive traversal in right subtree
		if(this.right != null) {
			this.right.infixOrder();
		}
	}
	//Postorder traversal
	public void postOrder() {
		if(this.left != null) {
			this.left.postOrder();
		}
		if(this.right != null) {
			this.right.postOrder();
		}
		System.out.println(this);
	}
}

5. Binary tree - find the specified node

requirement

  1. Please write pre order search, middle order search and post order search methods.
  2. Three search methods are used to find the node with heroNO = 5
  3. And analyze various search methods, and compare how many times
  4. Train of thought analysis diagram

  1. code implementation
	//Preorder traversal search
	/**
	 * 
	 * @param no Find no
	 * @return If found, the Node is returned. If not found, null is returned
	 */
	public HeroNode preOrderSearch(int no) {
		System.out.println("Enter preorder traversal");
		//Compare whether the current node is
		if(this.no == no) {
			return this;
		}
		//1. Judge whether the left child node of the current node is empty. If not, recursive preorder search
		//2. If the left recursive preamble finds a node, it returns
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.preOrderSearch(no);
		}
		if(resNode != null) {//That means we found the left subtree
			return resNode;
		}
		//1. Left recursive preorder search. If a node is found, it returns. Continue to judge whether or not,
		//2. Whether the right child node of the current node is empty. If it is not empty, continue to search in the right recursive preamble
		if(this.right != null) {
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	
	//Middle order traversal search
	public HeroNode infixOrderSearch(int no) {
		//Judge whether the left child node of the current node is empty. If it is not empty, search in recursive middle order
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.infixOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("Enter middle order search");
		//If found, it returns. If not found, it is compared with the current node. If yes, it returns the current node
		if(this.no == no) {
			return this;
		}
		//Otherwise, continue the middle order search of right recursion
		if(this.right != null) {
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
		
	}
	
	//Postorder traversal search
	public HeroNode postOrderSearch(int no) {
		
		//Judge whether the left child node of the current node is empty. If it is not empty, it will be searched recursively
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.postOrderSearch(no);
		}
		if(resNode != null) {//Description found in the left subtree
			return resNode;
		}
		
		//If the left subtree is not found, the right subtree recursively performs a post order traversal search
		if(this.right != null) {
			resNode = this.right.postOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("Enter post order search");
		//If the left and right subtrees are not found, compare the current node
		if(this.no == no) {
			return this;
		}
		return resNode;
	}

test

public class BinaryTreeDemo {

	public static void main(String[] args) {
		//First you need to create a binary tree
		BinaryTree binaryTree = new BinaryTree();
		//Create required nodes
		HeroNode root = new HeroNode(1, "Song Jiang");
		HeroNode node2 = new HeroNode(2, "Wu Yong");
		HeroNode node3 = new HeroNode(3, "Lu Junyi");
		HeroNode node4 = new HeroNode(4, "Lin Chong");
		HeroNode node5 = new HeroNode(5, "Guan Sheng");
		
		//Note: we first create the binary tree manually, and then we learn to create the binary tree recursively
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binaryTree.setRoot(root);
		
		//Preorder traversal
		//Number of preorder traversals: 4 
		System.out.println("Preorder traversal mode~~~");
		HeroNode resNode = binaryTree.preOrderSearch(5);
		if (resNode != null) {
			System.out.printf("Yes, the information is no=%d name=%s", resNode.getNo(), resNode.getName());
		} else {
			System.out.printf("Can't find no = %d Hero of", 5);
		}
		
		//Middle order traversal search
		//Middle order traversal 3 times
		System.out.println("Middle order traversal mode~~~");
		HeroNode resNode = binaryTree.infixOrderSearch(5);
		if (resNode != null) {
			System.out.printf("Yes, the information is no=%d name=%s", resNode.getNo(), resNode.getName());
		} else {
			System.out.printf("Can't find no = %d Hero of", 5);
		}
		
		//Post order traversal search
		//The number of subsequent traversal lookups is 2
		System.out.println("postorder traversal ~~~");
		HeroNode resNode = binaryTree.postOrderSearch(5);
		if (resNode != null) {
			System.out.printf("Yes, the information is no=%d name=%s", resNode.getNo(), resNode.getName());
		} else {
			System.out.printf("Can't find no = %d Hero of", 5);
		}

	}

}

//Define BinaryTree
class BinaryTree {
	private HeroNode root;

	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//Preorder traversal
	public HeroNode preOrderSearch(int no) {
		if(root != null) {
			return root.preOrderSearch(no);
		} else {
			return null;
		}
	}
	//Medium order traversal
	public HeroNode infixOrderSearch(int no) {
		if(root != null) {
			return root.infixOrderSearch(no);
		}else {
			return null;
		}
	}
	//Postorder traversal
	public HeroNode postOrderSearch(int no) {
		if(root != null) {
			return this.root.postOrderSearch(no);
		}else {
			return null;
		}
	}
}

//Create the HeroNode node first
class HeroNode {
	private int no;
	private String name;
	private HeroNode left; //Default null
	private HeroNode right; //Default null
	public HeroNode(int no, String name) {
		this.no = no;
		this.name = name;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
	
	
	//Preorder traversal search
	/**
	 * 
	 * @param no Find no
	 * @return If found, the Node is returned. If not found, null is returned
	 */
	public HeroNode preOrderSearch(int no) {
		System.out.println("Enter preorder traversal");
		//Compare whether the current node is
		if(this.no == no) {
			return this;
		}
		//1. Judge whether the left child node of the current node is empty. If not, recursive preorder search
		//2. If the left recursive preamble finds a node, it returns
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.preOrderSearch(no);
		}
		if(resNode != null) {//That means we found the left subtree
			return resNode;
		}
		//1. Left recursive preorder search. If a node is found, it returns. Continue to judge whether or not,
		//2. Whether the right child node of the current node is empty. If it is not empty, continue to search in the right recursive preamble
		if(this.right != null) {
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	
	//Middle order traversal search
	public HeroNode infixOrderSearch(int no) {
		//Judge whether the left child node of the current node is empty. If it is not empty, search in recursive middle order
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.infixOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("Enter middle order search");
		//If found, it returns. If not found, it is compared with the current node. If yes, it returns the current node
		if(this.no == no) {
			return this;
		}
		//Otherwise, continue the middle order search of right recursion
		if(this.right != null) {
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
		
	}
	
	//Postorder traversal search
	public HeroNode postOrderSearch(int no) {
		
		//Judge whether the left child node of the current node is empty. If it is not empty, it will be searched recursively
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.postOrderSearch(no);
		}
		if(resNode != null) {//Description found in the left subtree
			return resNode;
		}
		
		//If the left subtree is not found, the right subtree recursively performs a post order traversal search
		if(this.right != null) {
			resNode = this.right.postOrderSearch(no);
		}
		if(resNode != null) {
			return resNode;
		}
		System.out.println("Enter post order search");
		//If the left and right subtrees are not found, compare the current node
		if(this.no == no) {
			return this;
		}
		return resNode;
	}
	
}

6. Binary tree - delete node

requirement

  1. If the deleted node is a leaf node, delete the node

  2. If the deleted node is a non leaf node, the subtree is deleted

  3. Test, delete No. 5 leaf node and No. 3 subtree

  4. Complete deletion thought analysis

  1. code implementation
	//Delete Vertex 
	public void delNode(int no) {
		if(root != null) {
			//If there is only one root node, judge whether root is to delete the node immediately
			if(root.getNo() == no) {
				root = null;
			} else {
				//Recursive deletion
				root.delNode(no);
			}
		}else{
			System.out.println("The tree is empty and cannot be deleted~");
		}
	}


//Recursively delete nodes
	//1. If the deleted node is a leaf node, delete the node
	//2. If the deleted node is a non leaf node, delete the subtree
	public void delNode(int no) {
		
		//thinking
		/*
		 * 	1. Because our binary tree is unidirectional, we judge whether the child node of the current node needs to be deleted, but not whether the current node needs to be deleted
			2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
			3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
			4. If the node is not deleted in steps 2 and 3, we need to delete it recursively to the left subtree
			5.  If the node is not deleted in step 4, it should be deleted recursively to the right subtree

		 */
		//2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
		if(this.left != null && this.left.no == no) {
			this.left = null;
			return;
		}
		//3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
		if(this.right != null && this.right.no == no) {
			this.right = null;
			return;
		}
		//4. We need to delete recursively to the left subtree
		if(this.left != null) {
			this.left.delNode(no);
		}
		//5. The right subtree should be deleted recursively
		if(this.right != null) {
			this.right.delNode(no);
		}
	}

Complete test

public class BinaryTreeDemo {

	public static void main(String[] args) {
		//First you need to create a binary tree
		BinaryTree binaryTree = new BinaryTree();
		//Create required nodes
		HeroNode root = new HeroNode(1, "Song Jiang");
		HeroNode node2 = new HeroNode(2, "Wu Yong");
		HeroNode node3 = new HeroNode(3, "Lu Junyi");
		HeroNode node4 = new HeroNode(4, "Lin Chong");
		HeroNode node5 = new HeroNode(5, "Guan Sheng");
		
		//Note: we first create the binary tree manually, and then we learn to create the binary tree recursively
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binaryTree.setRoot(root);
		
		//Test a delete node
		
		System.out.println("Before deletion,Preorder traversal");
		binaryTree.preOrder(); //  1,2,3,5,4
		binaryTree.delNode(5);
		//binaryTree.delNode(3);
		System.out.println("After deletion, the preamble traverses");
		binaryTree.preOrder(); // 1,2,3,4
	}

}

//Define BinaryTree
class BinaryTree {
	private HeroNode root;

	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//Delete Vertex 
	public void delNode(int no) {
		if(root != null) {
			//If there is only one root node, judge whether root is to delete the node immediately
			if(root.getNo() == no) {
				root = null;
			} else {
				//Recursive deletion
				root.delNode(no);
			}
		}else{
			System.out.println("The tree is empty and cannot be deleted~");
		}
	}
	//Preorder traversal
	public void preOrder() {
		if(this.root != null) {
			this.root.preOrder();
		}else {
			System.out.println("Binary tree is empty and cannot be traversed");
		}
	}
	
}

//Create the HeroNode node first
class HeroNode {
	private int no;
	private String name;
	private HeroNode left; //Default null
	private HeroNode right; //Default null
	public HeroNode(int no, String name) {
		this.no = no;
		this.name = name;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
	
	//Recursively delete nodes
	//1. If the deleted node is a leaf node, delete the node
	//2. If the deleted node is a non leaf node, delete the subtree
	public void delNode(int no) {
		
		//thinking
		/*
		 * 	1. Because our binary tree is unidirectional, we judge whether the child node of the current node needs to be deleted, but not whether the current node needs to be deleted
			2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
			3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
			4. If the node is not deleted in steps 2 and 3, we need to delete it recursively to the left subtree
			5.  If the node is not deleted in step 4, it should be deleted recursively to the right subtree

		 */
		//2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
		if(this.left != null && this.left.no == no) {
			this.left = null;
			return;
		}
		//3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
		if(this.right != null && this.right.no == no) {
			this.right = null;
			return;
		}
		//4. We need to delete recursively to the left subtree
		if(this.left != null) {
			this.left.delNode(no);
		}
		//5. The right subtree should be deleted recursively
		if(this.right != null) {
			this.right.delNode(no);
		}
	}
	
	//Method of writing preorder traversal
	public void preOrder() {
		System.out.println(this); //Output parent node first
		//Recursive pre order traversal to the left subtree
		if(this.left != null) {
			this.left.preOrder();
		}
		//Recursive right subtree preorder traversal
		if(this.right != null) {
			this.right.preOrder();
		}
	}
}

6.1 thinking questions (after class exercises)

  1. If the node to be deleted is a non leaf node, now we don't want to delete the subtree with the non leaf node as the root node. We need to specify the rules if they are as follows:
  2. If the non leaf node A has only one child node B, the child node B replaces node A
  3. If the non leaf node A has A left child node B and A right child node C, let the left child node B replace node A.
	//Recursively delete nodes
	public void delNode1(int no) {
		//2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
		if(this.left != null && this.left.no == no) {
            //Delete directly for leaf node
			if(this.left.left == null && this.left.right == null) {
				this.left = null;
                
            //Only one child node is directly replaced
			} else if(this.left.left != null && this.left.right == null) {
				this.left = this.left.left;
			}else if(this.left.left == null && this.left.right != null) {
				this.left = this.left.right;
                
    		//There are two nodes, the left node is replaced, and the right node is inserted into the rightmost leaf node of the left node
			}else if(this.left.left != null && this.left.right != null) {
				HeroNode temp = this.left.right;
				this.left = this.left.left;
				HeroNode temp1 = this.left;
				while (temp1.right != null){
					temp1 = temp1.right;
				}
				temp1.right = temp;
			}
			return;
		}
		//3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
		if(this.right != null && this.right.no == no) {
            //Delete directly for leaf node
			if(this.right.left == null && this.right.right == null) {
				this.right = null;
                
            //Only one child node is directly replaced
			} else if(this.right.left != null && this.right.right == null) {
				this.right = this.right.left;
			}else if(this.right.left == null && this.right.right != null) {
				this.right = this.right.right;
                
            //There are two nodes, the left node is replaced, and the right node is inserted into the rightmost leaf node of the left node
			}else if(this.right.left != null && this.right.right != null) {
				HeroNode temp = this.right.right;
				this.right = this.right.left;
				HeroNode temp1 = this.right;
				while (temp1.right != null){
					temp1 = temp1.right;
				}
				temp1.right = temp;
			}
			return;
		}
		//4. We need to delete recursively to the left subtree
		if(this.left != null) {
			this.left.delNode1(no);
		}
		//5. The right subtree should be deleted recursively
		if(this.right != null) {
			this.right.delNode1(no);
		}
	}

2, Sequential storage binary tree

1. The concept of sequential storage binary tree

1.1 basic description

From the perspective of data storage, array storage mode and tree storage mode can be converted to each other, that is, array can be converted into tree and tree can also be converted into array. See the following diagram.

2. Features of sequential storage binary tree:

  1. Sequential binary trees usually only consider complete binary trees
  2. The left child node of the nth element is 2 * n + 1
  3. The right child node of the nth element is 2 * n + 2
  4. The parent node of the nth element is (n-1) / 2
  5. n: indicates the number of elements in the binary tree (starting with 0, as shown in the figure)

3. Sequential storage binary tree traversal

Requirements: give you an array {1,2,3,4,5,6,7}, which is required to be traversed in the way of binary tree preorder traversal. The result of preorder traversal should be
1,2,4,5,3,6,7

3.1 code implementation:

public class ArrBinaryTreeDemo {

	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
		//Create an ArrBinaryTree
		ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr);
		arrBinaryTree.preOrder(); // 1,2,4,5,3,6,7
	}

}

//Write an ArrayBinaryTree to realize the traversal of sequential storage binary tree

class ArrBinaryTree {
	private int[] arr;//An array that stores data nodes

	public ArrBinaryTree(int[] arr) {
		this.arr = arr;
	}
	
	//Reload preOrder
	public void preOrder() {
		this.preOrder(0);
	}
	
	//Write a method to complete the preorder traversal of the sequential storage binary tree
	/**
	 * 
	 * @param index Subscript of array 
	 */
	public void preOrder(int index) {
		//If the array is empty, or arr.length = 0
		if(arr == null || arr.length == 0) {
			System.out.println("The array is empty and cannot be traversed in the order before the binary tree");
		}
		//Output the current element
		System.out.println(arr[index]); 
		//Left recursive traversal
		if((index * 2 + 1) < arr.length) {
			preOrder(2 * index + 1 );
		}
		//Right recursive traversal
		if((index * 2 + 2) < arr.length) {
			preOrder(2 * index + 2);
		}
	}
	
}

3.2 after class exercises

Complete the code of traversing the array in binary tree order and post order

//Overload postorder 	 public void postOrder() { 		 this.postOrder(0); 		 System.out.println(); 	}	// Write a method to complete the post order traversal of the sequential storage binary tree 	/**	 *	 * @ Subscript of param index array 	 */	 public void postOrder(int index) { 		// If the array is empty, or arr.length = 0 		 if(arr == null || arr.length == 0) { 			 System.out.println("the array is empty and cannot be traversed according to the previous order of the binary tree"); 		}		// Left recursive traversal 		 if(index * 2 + 1 < arr.length){ 			 postOrder(index * 2 + 1); 		}		// Right recursive traversal 		 if(index * 2 + 2 < arr.length){ 			 postOrder(index * 2 + 2); 		}		// Output the current element 		 System.out.print(arr[index] + " "); 	}	// Overload infixorder 	 public void infixOrder() { 		 this.infixOrder(0); 		 System.out.println(); 	}	// Write a method to complete the middle order traversal of the sequential storage binary tree 	/**	 *	 * @ Subscript of param index array 	 */	 public void infixOrder(int index) { 		// If the array is empty, or arr.length = 0 		 if(arr == null || arr.length == 0) { 			 System.out.println("the array is empty and cannot be traversed according to the previous order of the binary tree"); 		}		// Left recursive traversal 		 if((index * 2 + 1) < arr.length) { 			 infixOrder(2 * index + 1 ); 		}		// Output the current element 		 System.out.print(arr[index] + " "); 		// Right recursive traversal 		 if((index * 2 + 2) < arr.length) { 			 infixOrder(2 * index + 2); 		}	}

4. Sequential storage of binary tree application examples

The heap sorting in the eight sorting algorithms will use the sequential storage binary tree.

3, Cued binary tree

3.1 let's look at one question first

The sequence {1,3,6,8,10,14} is constructed into a binary tree n+1=7

Problem analysis:

  1. When we traverse the above binary tree in middle order, the sequence is {8, 3, 10, 1, 6, 14}
  2. However, the left and right pointers of nodes 6, 8, 10 and 14 are not fully utilized
  3. What if we want to make full use of the left and right pointers of each node so that each node can point to its own front and rear nodes?
  4. Solution - clue binary tree

3.2 basic introduction to clue binary tree

  1. The binary list of N nodes contains n+1 [Formula 2n-(n-1)=n+1] empty finger needle fields. The null pointer field in the binary list is used to store pointers to the precursor and successor nodes of the node in a certain traversal order (this additional pointer is called "clue")
  2. This binary linked list with clues is called clue linked list, and the corresponding binary tree is called threaded binary tree. According to the different properties of clues, clue binary trees can be divided into three types: pre order clue binary trees, middle order clue binary trees and post order clue binary trees
  3. The previous node of a node is called the precursor node
  4. The next node of a node is called the successor node

3.3 application cases of clue binary tree

Application case description: apply the following binary tree to the middle order clue binary tree. The sequence traversed in middle order is {8, 3, 10, 1, 14, 6}

3.3.1 train of thought analysis:

Results of medium order traversal: {8, 3, 10, 1, 14, 6}

3.3.2 Description:

After cueing the binary tree, the attributes left and right of the Node are as follows:

  1. Left refers to the left subtree or the precursor node For example, ① node left points to the left subtree, while ⑩ node left points to the precursor node
  2. Right refers to the right subtree or the successor node. For example, ① node right refers to the right subtree, while ⑩ node right refers to the successor node

3.3.3 code implementation

//Write the method of medium order cueing of binary tree 	/**	 * 	 * @ param node is the node that needs cueing at present 	 */	 public void threadedNodes(HeroNode node) { 				// If node==null, it cannot be threaded 		 if(node==null) { 			 return; 		}				// (1) Cue left subtree first 		 threadedNodes(node.getLeft()); 		// (2) Cue current node [difficult] 				// Handle the precursor node of the current node 		// Understand with 8 nodes 		// 8 nodes Left = null, 8 nodes leftType = 1 		 if(node.getLeft() == null) { 			// Let the left pointer of the current node point to the predecessor node 			 node.setLeft(pre);  			// Modify the type of the left pointer of the current node to point to the predecessor node 			 node.setLeftType(1); 		}				// Processing successor nodes 		 if (pre != null && pre.getRight() == null) { 			// Let the right pointer of the predecessor node point to the current node 			 pre.setRight(node); 			// Modify the right pointer type of the precursor node 			 pre.setRightType(1); 		}		//!!!  After each node is processed, the current node is the precursor node of the next node 		 pre = node; 				// (3) Online right subtree 		 threadedNodes(node.getRight()); 					}

test

public class ThreadedBinaryTreeDemo {	public static void main(String[] args) {		//Test the function of a medium order clue binary tree 		 HeroNode root = new HeroNode(1, "tom"); 		 HeroNode node2 = new HeroNode(3, "jack"); 		 HeroNode node3 = new HeroNode(6, "smith"); 		 HeroNode node4 = new HeroNode(8, "mary"); 		 HeroNode node5 = new HeroNode(10, "king"); 		 HeroNode node6 = new HeroNode(14, "dim"); 				// Binary tree, we will create it recursively later. Now it is simple to create it manually 		 root.setLeft(node2); 		 root.setRight(node3); 		 node2.setLeft(node4); 		 node2.setRight(node5); 		 node3.setLeft(node6); 				// Sequential cueing in testing 		 ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(); 		 threadedBinaryTree.setRoot(root); 		 threadedBinaryTree.threadedNodes(); 				// Test: test with node 10 		 HeroNode leftNode = node5.getLeft(); 		 HeroNode rightNode = node5.getRight(); 		 System. out. Println ("the precursor node of node 10 is =" + leftnode)// three 		 System. out. Println ("the successor node of node 10 is =" + rightnode)// one 			}}// Define threadedbinarytree, a binary tree class ThreadedBinaryTree that implements the cue function{ 	 private HeroNode root; 		// In order to realize cueing, you need to create a pointer to the precursor node pointing to the current node 	// In recursive cueing, pre always retains the previous node 	 private HeroNode pre = null; 	 public void setRoot(HeroNode root) { 		 this.root = root; 	}		// Overload a threadednodes method 	 public void threadedNodes() { 		 this.threadedNodes(root); 	}			// Write the method of medium order cueing of binary tree 	/**	 * 	 * @ param node is the node that needs cueing at present 	 */	 public void threadedNodes(HeroNode node) { 				// If node==null, it cannot be threaded 		 if(node==null) { 			 return; 		}				// (1) Cue left subtree first 		 threadedNodes(node.getLeft()); 		// (2) Cue current node [difficult] 				// Handle the precursor node of the current node 		// Understand with 8 nodes 		// 8 nodes Left = null, 8 nodes leftType = 1 		 if(node.getLeft() == null) { 			// Let the left pointer of the current node point to the predecessor node 			 node.setLeft(pre);  			// Modify the type of the left pointer of the current node to point to the predecessor node 			 node.setLeftType(1); 		}				// Processing successor nodes 		 if (pre != null && pre.getRight() == null) { 			// Let the right pointer of the predecessor node point to the current node 			 pre.setRight(node); 			// Modify the right pointer type of the precursor node 			 pre.setRightType(1); 		}		//!!!  After each node is processed, the current node is the precursor node of the next node 		 pre = node; 				// (3) Online right subtree 		 threadedNodes(node.getRight()); 					}}// Create the heronode node class first{ 	 private int no; 	 private String name; 	 private HeroNode left; // Default null 	 private HeroNode right; // Default null 	// explain 	// 1. If leftType == 0, it refers to the left subtree; if 1, it refers to the precursor node 	// 2. If rightType == 0, it means pointing to the right subtree; if 1, it means pointing to the successor node 	 private int leftType; 	 private int rightType; 			 public int getLeftType() { 		 return leftType; 	}	 public void setLeftType(int leftType) { 		 this.leftType = leftType; 	}	 public int getRightType() { 		 return rightType; 	}	 public void setRightType(int rightType) { 		 this.rightType = rightType; 	}	 public HeroNode(int no, String name) { 		 this.no = no; 		 this.name = name; 	}	 public int getNo() { 		 return no; 	}	 public void setNo(int no) { 		 this.no = no; 	}	 public String getName() { 		 return name; 	}	 public void setName(String name) { 		 this.name = name; 	}	 public HeroNode getLeft() { 		 return left; 	}	 public void setLeft(HeroNode left) { 		 this.left = left; 	}	 public HeroNode getRight() { 		 return right; 	}	 public void setRight(HeroNode right) { 		 this.right = right; 	}	@ Override 	 public String toString() { 		 return "HeroNode [no=" + no + ", name=" + name + "]"; 	}	}

3.4 traversing threaded binary tree

  1. Description: traverse the previously ordered threaded binary tree
  2. Analysis: because the direction of each node changes after cueing, the original traversal method cannot be used. At this time, a new method needs to be used to traverse the cued binary tree. Each node can be traversed by linear method, so there is no need to use recursive method, which also improves the efficiency of traversal. The order of traversal should be consistent with that of middle order traversal.
  3. code:
	//Method of traversing cued binary tree 	 public void threadedList() { 		// Define a variable to store the currently traversed node, starting from root 		 HeroNode node = root; 		 while(node != null) { 			// Loop to find the node with leftType==1, and the first to find is 8 nodes 			// The following changes with traversal, because when leftType==1, it indicates that the node is threaded 			// Effective nodes after processing 			 while(node.getLeftType() == 0) { 				 node = node.getLeft(); 			}						// Print the current node 			 System.out.println(node); 			// If the right pointer of the current node points to the subsequent node, it will be output all the time 			 while(node.getRightType() == 1) { 				// Gets the successor node of the current node 				 node = node.getRight(); 				 System.out.println(node); 			}			// Replace this traversal node 			 node = node.getRight(); 					}	}

Homework after class: write pre order clue binary tree and post order clue binary tree. Their analysis ideas are similar

Preordered cued binary tree

	public void preThreadedNodes() {		this.preThreadedNodes(root);	}//Write a method for preorder cueing of binary tree 	 public void preThreadedNodes(HeroNode node) { 		// If node==null, it cannot be threaded 		 if(node==null) { 			 return; 		}		// Handle the precursor node of the current node 		// Understand with 8 nodes 		// 8 nodes Left = null, 8 nodes leftType = 1 		 if(node.getLeft() == null) { 			// Let the left pointer of the current node point to the predecessor node 			 node.setLeft(pre); 			// Modify the type of the left pointer of the current node to point to the predecessor node 			 node.setLeftType(1); 		}		// Processing successor nodes 		 if (pre != null && pre.getRight() == null) { 			// Let the right pointer of the predecessor node point to the current node 			 pre.setRight(node); 			// Modify the right pointer type of the precursor node 			 pre.setRightType(1); 		}		//!!!  After each node is processed, the current node is the precursor node of the next node 		 pre = node; 		 if(node.getLeftType() == 0) { 			 preThreadedNodes(node.getLeft()); 		}		 if(node.getRightType() == 0) { 			 preThreadedNodes(node.getRight()); 		}	}// Method of traversing cued binary tree 	 public void preThreadedList() { 		// Define a variable to store the currently traversed node, starting from root 		 HeroNode node = root; 		 while(node != null) { 			 while(node.getLeftType() == 0) { 				// Print the current node 				 System.out.println(node); 				 node = node.getLeft(); 			}			// Print the current node 			 System.out.println(node); 			 node = node.getRight(); 		}	}

Post ordered cued binary tree

	public void postThreadedNodes(HeroNode node) {		if(node == null) return;		if(node.getLeftType() == 0){			postThreadedNodes(node.getLeft());		}		if(node.getRightType() == 0){			postThreadedNodes(node.getRight());		}		if(node.getLeft() == null){			node.setLeft(pre);			node.setLeftType(1);		}		if(pre != null && pre.getRight() == null){			pre.setRight(node);			pre.setRightType(1);		}		pre = node;	}	public void postThreadedList() {		HeroNode node = root;		while (node != null && node.getLeftType() == 0){			node = node.getLeft();		}		HeroNode pre = null;		while (node != null){			if(node.getRightType() == 1){				System.out.println(node);				pre = node;				node = node.getRight();			}else {				if(node.getRight() == pre){					System.out.println(node);					if(node == root){						return;					}					pre = node;					node = node.getParent();				}else {					node = node.getRight();					while (node != null && node.getLeftType() == 0){						node = node.getLeft();					}				}			}		}	}

Keywords: Algorithm data structure

Added by ealderton on Wed, 19 Jan 2022 14:01:14 +0200