Algorithmic Knowledge Combing (10) - Binary Find Tree

Posted by amorphous on Sun, 19 May 2019 08:22:12 +0200

Interview algorithm code knowledge combing series

Algorithmic knowledge combing (1) - sorting algorithm
Algorithmic Knowledge Combing (2) - String Algorithms Part 1
Algorithmic Knowledge Combing (3) - String Algorithms Part 2
Combing Algorithmic Knowledge (4) - Array Part 1
Algorithmic Knowledge Combing (5) - Array Part 2
Combing Algorithmic Knowledge (6) - Array Part 3
Combing Algorithmic Knowledge (7) - Array Part 4
Algorithmic knowledge combing (8) - Binary search algorithm and its variants
Algorithmic Knowledge Combing (9) - Chain List Algorithms Part 1
Algorithmic Knowledge Combing (10) - Binary Find Tree

1. Overview

A binary search tree, also known as a binary search tree, is either an empty tree or a binary tree with the following properties

  • If the left subtree is not empty, the values of all nodes in the left subtree are less than or equal to its nodes.
  • If the right subtree is not empty, the values of all nodes in the right subtree are greater than or equal to the values of its root nodes.
  • Left and right subtrees are also binary lookup trees

Let's comb the knowledge points related to the binary search tree together:

  • Build a Binary Find Tree
  • Delete the specified element in a binary lookup tree
  • Non-recursive traversal of binary lookup trees (first, middle, then)

2. Code implementation

2.1 Building a Binary Find Tree

Representation of a binary search tree

A binary lookup Tree can be represented by a Tree, which contains a root variable to store the root nodes of the Tree, a size to represent the number of elements in the Tree, and each node Node contains the following variables:

  • Parent: points to its parent node
  • Left, right: point to its left and right children, respectively
  • Value: The value stored by the node

code implementation

Next, we enter an array p through which to build a binary lookup tree and print out the elements in the tree by recursive middle-order traversal. As defined by the binary lookup tree, the final output must be incrementally ordered.

class Untitled {
    
    static class Tree {
        int size;
        Node root;
    }
    
    static class Node {
        Node parent;
        Node left;
        Node right;
        int value;
    }
    
    static void insertNode(Tree tree, int value) {
        if (tree == null) {
            return;
        }
        Node tNode = tree.root;
        //If the parent node of the node to be inserted is empty after traversal, then it is an empty tree.
        Node pNode = null;
        //New node.
        Node nNode = new Node();
        nNode.value = value;
        while (tNode != null) {
            pNode = tNode;
            if (tNode.value > value) {
                tNode = tNode.left;
            } else {
                tNode = tNode.right;
            }
        }
        nNode.parent = pNode;
        if (pNode == null) {
            tree.root = nNode;
        } else if (pNode.value > value) {
            pNode.left = nNode;
        } else {
            pNode.right = nNode;
        }
        tree.size++;
    }
    
    static Tree createBinTree(int p[], int len) {
        Tree tree = new Tree();
        for (int i=0; i<len; i++) {
            int value = p[i];
            insertNode(tree, value);
        }
        return tree;
    }
    
    //Binary lookup trees are printed in order in a recursive manner, and the order of the final output must be increasing.
    static void printInOrder(Node node) {
        if (node == null) {
            return;
        }
        printInOrder(node.left);
        System.out.println(node.value);
        printInOrder(node.right);
    }
    
    public static void main(String[] args) {
        int p[] = {4,5,6,1,2,3};
        Tree tree = createBinTree(p, p.length);
        printInOrder(tree.root);
    }
}

Run Results

>> 1
>> 2
>> 3
>> 4
>> 5
>> 6

2.2 Delete the specified element in a binary lookup tree

To delete an element in a binary lookup tree, the core idea is to find the parent node of the node to be deleted and point the left or right of the parent node at the child node of the node to be deleted.

  • If the node to be deleted has only one child node, then the child node can be used to replace the node to be deleted.
  • If the node to be deleted has two child nodes, the following steps are required:
    • Step 1: Find the smallest node of the right subtree of the node to be deleted as the replacement node. If the node is not the root node of the right subtree, then the smallest node needs to be replaced by the right node of the smallest node first
    • Step 2: Replace the node to be deleted with the node found in step 1
    • Step 3: Graft the root node of the left subtree of the node to be deleted onto the replacement node.
class Untitled {

    static class Tree {
        int size;
        Node root;
    }

    static class Node {
        Node parent;
        Node left;
        Node right;
        int value;
    }

    static void insertNode(Tree tree, int value) {
        if (tree == null) {
            return;
        }
        Node tNode = tree.root;
        //If the parent node of the node to be inserted is empty after traversal, then it is an empty tree.
        Node pNode = null;
        //New node.
        Node nNode = new Node();
        nNode.value = value;
        while (tNode != null) {
            pNode = tNode;
            if (tNode.value > value) {
                tNode = tNode.left;
            } else {
                tNode = tNode.right;
            }
        }
        nNode.parent = pNode;
        if (pNode == null) {
            tree.root = nNode;
        } else if (pNode.value > value) {
            pNode.left = nNode;
        } else {
            pNode.right = nNode;
        }
        tree.size++;
    }

    static Tree createBinTree(int p[], int len) {
        Tree tree = new Tree();
        for (int i=0; i<len; i++) {
            int value = p[i];
            insertNode(tree, value);
        }
        return tree;
    }

    static Node searchNode(Tree tree, int value) {
        if (tree == null) {
            return null;
        }
        Node find = null;
        Node node = tree.root;
        while (node != null) {
            if (node.value > value) {
                node = node.left;
            } else if (node.value < value) {
                node = node.right;
            } else {
                find = node;
                break;
            }
        }
        return find;
    }

    static Node minNode(Node node) {
        while (node != null && node.left != null) {
            node = node.left;
        }
        return node;
    }

    static void transPlant(Tree tree, Node deleteNode, Node replaceNode) {
        if (deleteNode.parent == null) {
            tree.root = replaceNode;
        } else if (deleteNode.parent.left == deleteNode) {
            deleteNode.parent.left = replaceNode;
        } else if (deleteNode.parent.right == deleteNode) {
            deleteNode.parent.right = replaceNode;
        }
        if (replaceNode != null) {
            replaceNode.parent = deleteNode.parent;
        }
    }

    static void deleteNode(Tree tree, int value) {
        if (tree == null) {
            return;
        }
        Node deleteNode = searchNode(tree, value);
        if (deleteNode != null) {
            if (deleteNode.left == null) {
                transPlant(tree, deleteNode, deleteNode.right);
            } else if (deleteNode.right == null) {
                transPlant(tree, deleteNode, deleteNode.left);
            } else {
                Node replaceNode = minNode(deleteNode.right);
                if (replaceNode != deleteNode.right) {
                    transPlant(tree, replaceNode, replaceNode.right);
                    deleteNode.right.parent = replaceNode;
                    replaceNode.right = deleteNode.right;
                }
                transPlant(tree, deleteNode, replaceNode);
                deleteNode.left.parent = replaceNode;
                replaceNode.left = deleteNode.left;
            }
        }
    }

    //Binary lookup trees are printed in order in a recursive manner, and the order of the final output must be increasing.
    static void printInOrder(Node node) {
        if (node == null) {
            return;
        }
        printInOrder(node.left);
        System.out.println(node.value);
        printInOrder(node.right);
    }

    public static void main(String[] args) {
        int p[] = {3,5,6,1,2,4};
        Tree tree = createBinTree(p, p.length);
        deleteNode(tree, 3);
        printInOrder(tree.root);
    }
}

Run Results

>> 1
>> 2
>> 4
>> 5
>> 6

2.3 Non-recursive traversal

Solution ideas

For recursive traversal of a binary tree, I'm sure you're already familiar with it. Here's how to achieve a non-recursive traversal of a binary tree through a "stack":

class Untitled {

    static class Tree {
        int size;
        Node root;
    }

    static class Node {
        Node parent;
        Node left;
        Node right;
        int value;
    }

    static void insertNode(Tree tree, int value) {
        if (tree == null) {
            return;
        }
        Node tNode = tree.root;
        //If the parent node of the node to be inserted is empty after traversal, then it is an empty tree.
        Node pNode = null;
        //New node.
        Node nNode = new Node();
        nNode.value = value;
        while (tNode != null) {
            pNode = tNode;
            if (tNode.value > value) {
                tNode = tNode.left;
            } else {
                tNode = tNode.right;
            }
        }
        nNode.parent = pNode;
        if (pNode == null) {
            tree.root = nNode;
        } else if (pNode.value > value) {
            pNode.left = nNode;
        } else {
            pNode.right = nNode;
        }
        tree.size++;
    }

    static Tree createBinTree(int p[], int len) {
        Tree tree = new Tree();
        for (int i=0; i<len; i++) {
            int value = p[i];
            insertNode(tree, value);
        }
        return tree;
    }
    
    //Traverse in order.
    static void printPreOrder(Tree tree) {
        Node p[] = new Node[tree.size];
        int index = -1;
        Node node = tree.root;
        while (node != null || index >= 0) {
            while (node != null) {
                int value = node.value;
                System.out.println(node.value);
                index++;
                p[index] = node;
                node = node.left;
            }
            if (index >= 0) {
                node = p[index];
                p[index] = null;
                index--;
            }
            node = node.right;
        }
    }
    
    //Intermediate traversal.
    static void printInOrder(Tree tree) {
        Node p[] = new Node[tree.size];
        int index = -1;
        Node node = tree.root;
        while (node != null || index >= 0) {
            while (node != null) {
                int value = node.value;
                index++;
                p[index] = node;
                node = node.left;
            }
            if (index >= 0) {
                node = p[index];
                System.out.println(node.value);
                p[index] = null;
                index--;
            
            }
            node = node.right;
        }
    }
    
    //Post-order traversal.
    static void printPostOrder(Tree tree) {
        Node p[] = new Node[tree.size];
        int index = 0;
        Node curNode = tree.root;
        Node preNode = null;
        p[index] = curNode;
        while (index >= 0) {
            curNode = p[index];
            //If there is no child node.
            boolean hasNoChild = (curNode.left == null && curNode.right == null);
            //If its left or right child has been visited.
            boolean hasVisit = preNode == curNode.left || preNode == curNode.right;
            if (hasNoChild || hasVisit) {
                System.out.println(curNode.value);
                p[index] = null;
                index--;
                preNode = curNode;
            } else {
                //The left child will be on the stack first, so that the right child will be visited first.
                if (curNode.left != null) {
                    index++;
                    p[index] = curNode.left;
                } 
                if (curNode.right != null) {
                    index++;
                    p[index] = curNode.right;
                }
            }
        }
    }
    
    //Binary lookup trees are printed in order in a recursive manner, and the order of the final output must be increasing.
    static void printInOrder(Node node) {
        if (node == null) {
            return;
        }
        printInOrder(node.left);
        System.out.println(node.value);
        printInOrder(node.right);
    }

    public static void main(String[] args) {
        int p[] = {3,5,6,1,2,4};
        Tree tree = createBinTree(p, p.length);
        System.out.println("- Preorder traversal - ");
        printPreOrder(tree);
        System.out.println("- Intermediate traversal - ");
        printInOrder(tree);
        System.out.println("- Post-order traversal - ");
        printPostOrder(tree);
    }
}

Run Results

-Sequential traversal- 
3
1
2
5
4
6
 -Medium traversal- 
1
2
3
4
5
6
 -Postorder traversal- 
6
4
5
2
1
3

For more articles, welcome to my Android comb series:

Topics: Android less