Binary search tree and binary tree traversal (recursive and non-recursive)

definition

Binary Search Tree (Binary Search Tree) is also known as binary sort tree and binary search tree. Binary search tree is born to realize fast search. However, it not only supports quick search for a data, but also supports quick insertion and deletion of a data. Binary search tree requires that any node in the tree must be satisfied, and the value of each node in the left subtree must be less than the value of this node, and the value of each node in the right subtree is greater than the value of this node value.

Both of these are binary search trees.

Find

To find a node in the binary search tree, we first take the root node, and if it is equal to the data we are looking for, then return. If the data to be searched is smaller than the value of the root node, then recursively search in the left subtree; if the data to be searched is greater than the value of the root node, then recursively search in the right subtree.

Code implementation of lookup

public class BinarySearchTree {
    
    
    private Node root;

    public Node find(int data) {
    
    
        Node temp = root;
        while (temp != null) {
    
    
            if (data == temp.data) {
    
    
                return temp;
            } else if(data > temp.data) {
    
    
                temp = temp.rchild;
            } else {
    
    
                temp = temp.lchild;
            }
        }
        return null;
    }
}

public class Node {
    
    
    int data;
    Node lchild;
    Node rchild;

    public Node(int data) {
    
    
        this.data = data;
    }
}

insert

The operation of inserting is similar to that of searching. Starting from the root node, compare the relationship between the data to be inserted and the node in turn.
If the data to be inserted is larger than the data of the node, and the right subtree of the node is empty, insert the data directly into the position of the right subnode. If the right subtree is not empty, continue to traverse the right subtree; if you want The inserted data is smaller than the data of the node, and the left subtree of the node is empty, the data is directly inserted into the position of the left child node, if the left subtree is not empty, then continue to traverse the left subtree.

Inserted code implementation

public void insert(int data) {
    
    
        if (root == null) {
    
    
            root = new Node(data);
            return;
        }
        
        Node temp = root;
        while (true) {
    
    
            if (data > temp.data) {
    
    
                if (temp.rchild == null) {
    
    
                    temp.rchild = new Node(data);
                    return;
                }
                temp = temp.rchild;
            } else {
    
    
                if (temp.lchild == null) {
    
    
                    temp.lchild = new Node(data);
                    return;
                }
                temp = temp.lchild;
            }
        }
    }

delete

The operation of searching and inserting the binary search tree is relatively simple, but the operation of deleting is more complicated, which can be divided into three situations.
In the first case, the node to be deleted is a leaf node. At this time, it is only necessary to directly set the pointer to the node to be deleted in the parent node to null. Delete 28 as shown in the figure below.
In the second case, the node to be deleted has only one child node (left child node or right child node), we only need to update the pointer in the parent node to point to the byte point of the node to be deleted. See 34 in the figure below.
In the third case, the node to be deleted has two child nodes. In this case, we need to replace the node to be deleted with the smallest node in the right subtree of the node to be deleted. See 15 in the figure below.


After the deletion is complete, the

code is implemented

public TreeNode deleteNode(TreeNode root, int key) {
    
    
    if (root == null) return null;

    if (root.val == key) {
    
    
        if (root.left == null) return root.right;
        if (root.right == null) return root.left;

        TreeNode minNode = getMin(root.right);
        root.val = minNode.val;
        root.right = deleteNode(root.right, minNode.val);
    } else if (root.val > key) {
    
    
        root.left = deleteNode(root.left, key);
    } else {
    
    
        root.right = deleteNode(root.right, key);
    }

    return root;
}

private TreeNode getMin(TreeNode root) {
    
    
    while (root.left != null) {
    
    
        root = root.left;
    }
    return root;
}

Non-recursive implementation:

 public void delete(int data) {
    
    
        Node temp = root;  // temp指向要删除的节点
        Node ftemp = null; // ftemp指向要删除节点的父节点

        while (temp != null && temp.data != data) {
    
    
            ftemp = temp;
            if (data > temp.data) {
    
    
                temp = temp.rchild;
            } else {
    
    
                temp = temp.lchild;
            }
        }

        if (temp == null) return; // 没有找到对应的节点

        // 若找到,temp就是要删除的节点
        // 要删除的节点有两个子节点
        if (temp.lchild != null && temp.rchild != null) {
    
    
            Node minTemp = temp.rchild;  // 存储右子树的最小节点
            Node fminTemp = temp; // minTemp的父节点

            // 找到右子树的最小节点
            while (minTemp.lchild != null) {
    
    
                fminTemp = minTemp;
                minTemp = minTemp.lchild;
            }

            temp.data = minTemp.data; // 将最小节点的值替换到temp中
            temp = minTemp;  // 变成删除叶子节点
            ftemp = fminTemp;
        }

        // 删除节点是叶子节点或者仅有一个节点
        Node child; // temp的子节点
        if (temp.lchild != null) {
    
    
            child = temp.lchild;
        } else if (temp.rchild != null) {
    
    
            child = temp.rchild;
        } else {
    
    
            child = null;
        }

        if (ftemp == null) {
    
      // 删除的是根节点
            root = child;
        } else if (ftemp.lchild == temp) {
    
    
            ftemp.lchild = child;
        } else {
    
    
            ftemp.rchild = child;
        }
    }

Binary search tree supporting repeated data

The previous operations on the binary search tree are for the case where there is no duplicate data. If you need to store duplicate data, when inserting data, if the value of a node is equal to the value to be inserted, we put the data to be inserted in the right subtree of the node. In other words, treat the newly inserted data as a value greater than this node.

When looking for data, when we encounter a node with the same value, we do not stop the search operation, but continue to search in the right subtree until we encounter a leaf node. In this way, all nodes that meet the requirements can be found out.
When deleting a node, you also need to find each node to be deleted first, and then delete it in turn according to the previous delete operation.

Find the largest and smallest nodes

    public Node findMin() {
    
    
        if (root == null) return null;
        Node temp = root;
        while (temp.lchild != null) {
    
    
            temp = temp.lchild;
        }
        return temp;
    }

    public Node findMax() {
    
    
        if (root == null) return null;
        Node temp = root;
        while (temp.rchild != null) {
    
    
            temp = temp.rchild;
        }
        return temp;
    }

Traversal of binary tree

Pre-order, middle-order, and post-order traversal (recursive)

In order to traverse the binary search tree, it can output an ordered data sequence, and the time complexity is O(n), which is very efficient

    // 前序遍历
    public void preOrder(Node node) {
    
    
        if (node != null) {
    
    
            System.out.println(node.data);
            preOrder(node.lchild);
            preOrder(node.rchild);
        }
    }

    // 中序遍历
    public void inOrder(Node node) {
    
    
        if (node != null) {
    
    
            inOrder(node.lchild);
            System.out.println(node.data);
            inOrder(node.rchild);
        }
    }

    // 后序遍历
    public void postOrder(Node node) {
    
    
        if (node != null) {
    
    
            postOrder(node.lchild);
            postOrder(node.rchild);
            System.out.println(node.data);
        }
    }

Pre-order, middle-order, and post-order traversal (non-recursive)

prologue

    // 前序遍历
    public void preOrderTraversal(Node node) {
    
    
        if (node == null) return;

        Stack<Node> stack = new Stack<>();
        stack.push(node);

        while (!stack.isEmpty()) {
    
    
            node = stack.pop();
            if (node.rchild != null) {
    
    
                stack.push(node.rchild);
            }
            if (node.lchild != null) {
    
    
                stack.push(node.lchild);
            }
            System.out.println(node.data);
        }
    }

Middle order

    // 中序遍历
    public void inOrderTraversal(Node node) {
    
    
        Stack<Node> stack = new Stack<>();

        while (node != null || !stack.isEmpty()) {
    
    
            if (node != null) {
    
    
                stack.push(node);
                node = node.lchild;
            } else {
    
    
                node = stack.pop();
                System.out.println(node.data);
                node = node.rchild;
            }
        }
    }

Post sequence

    // 后序遍历
    public void postOrderTraversal(Node node) {
    
    
        if (node == null) return;

        Stack<Node> stack1 = new Stack<>();
        Stack<Node> stack2 = new Stack<>();

        stack1.push(node);
        while (!stack1.isEmpty()) {
    
    
            node = stack1.pop();
            stack2.push(node);
            if (node.lchild != null) {
    
    
                stack1.push(node.lchild);
            }
            if (node.rchild != null) {
    
    
                stack1.push(node.rchild);
            }
        }
        while (!stack2.isEmpty()) {
    
    
            System.out.println(stack2.pop().data);
        }
    }

Sequence traversal

// 层序遍历
public void levelOrder(Node node) {
    
    
    if (node == null) return;

    Queue<Node> queue = new LinkedList<>();
    queue.offer(node);

    while (!queue.isEmpty()) {
    
    
        node = queue.poll();
        System.out.println(node.data);
        if (node.lchild != null) {
    
    
            queue.offer(node.lchild);
        }
        if (node.rchild != null) {
    
    
            queue.offer(node.rchild);
        }
    }
}

Guess you like

Origin blog.csdn.net/qq_46122005/article/details/110895892