Binary sort tree

Keywords: Algorithm data structure

Binary sort tree

1, Definition

Binary Sort Tree, also known as binary search tree. It is either an empty tree or a binary tree with the following properties.

1. If its left subtree is not empty, the values of all nodes on the left subtree are less than the values of its root node.
2. If its right subtree is not empty, the values of all nodes on the right subtree are greater than the values of its root node.
3. Its left and right subtrees are also binary sort trees.

From the definition of binary sort tree, we can know that its premise is binary tree, and then it adopts the recursive definition method. Moreover, its nodes meet a certain order relationship, the left subtree node must be smaller than its parent node, and the right subtree node must be larger than its parent node.

The purpose of constructing a binary sort tree is not to sort, but to improve the speed of finding, inserting and deleting keywords. In any case, the search speed on an ordered data set is always faster than that of an unordered data set, and the nonlinear structure of binary sort tree is also conducive to the implementation of insertion and deletion.

In the case of random binary sort tree, the search time complexity is O (logn)

2, C + + implementation of binary sort tree

1. Node definition

For simplicity, the key value type of the node is set to int.

class BSTNode {
public:
    int key;            //Value of node
    BSTNode* left;        //Left child of node
    BSTNode* right;        //Right child of node
    BSTNode* parent;    //Parents of nodes

    /*Constructor*/
    BSTNode():parent(NULL) {}
    
    BSTNode(int key, BSTNode* left, BSTNode* right, BSTNode* parent) 
           :key(key), left(left), right(right), parent(parent) {}
};

2. Various operations of binary sort tree

class BSTree {
private:
    BSTNode* root;        //Root node
public:
    /*Constructor*/
    BSTree() :root(NULL) {};

    /*Get root node*/
    BSTNode* getRoot() {return root;}

    /*Insert the key value key into the binary tree*/
    void insert(int key);

    /*Insert node into binary tree*/
    void insert(BSTNode*& root, BSTNode* node);

    /*Preorder traversal */
    void preOrder(BSTNode* root);

    /*Medium order traversal*/
    void inOrder(BSTNode* root);

    /*Postorder traversal*/
    void postOrder(BSTNode* root);

    /*Find the node whose key value is key in the binary tree and return*/
    BSTNode* search(BSTNode* node, int key);

    /*Find the node with the smallest key value in the binary tree and return it*/
    BSTNode* minimum(BSTNode* node);

    /*Find the node with the largest key value in the binary tree and return it*/
    BSTNode* maximum(BSTNode* node);

    /*Find the successor node of the binary tree node*/
    BSTNode* successor(BSTNode* node);

    /*Find the precursor node of the binary tree node*/
    BSTNode* predecessor(BSTNode* node);

    /*Remove the node whose key value is key*/
    BSTNode* remove(BSTNode*& root, int key);

    /*Destroy binary sort tree*/
    void destroy(BSTNode* root);
};

3. Insert

When inserting a binary sort tree, each inserted node is a new leaf node on the binary sort tree. Nodes can be inserted into an existing binary sort tree, or a binary sort tree can be constructed by inserting nodes.

/*
* Insert node into binary tree
*
* Parameter Description:
*     root Root node of binary tree
*     node Node to insert
*/
void BSTree::insert(BSTNode*& root, BSTNode* node)
{
    BSTNode* y = NULL;
    BSTNode* x = root;

    /*Find the location to insert*/
    while (x != NULL)
    {
        y = x;
        if (node->key > x->key)
            x = x->right;
        else x = x->left;
    }

    /*Insert Knot */
    node->parent = y;
    if (y == NULL)  //If it is an empty tree
        root = node;
    else if(y->key > node->key)
        y->left = node;
    else y->right = node;
}

void BSTree::insert(int key) {
    BSTNode* node = new BSTNode(key, NULL, NULL, NULL);
    insert(root, node);
}

4. Traversal

The traversal of binary sort tree is the same as that of ordinary binary tree. It is divided into pre order, middle order and post order traversal, and there is no difference in implementation. It should be noted that traversing the binary sort tree in middle order will get an ordered sequence of keywords.

4.1 preorder traversal

/*Preorder traversal */
void BSTree::preOrder(BSTNode* root)
{
    if (root != NULL)
    {
        cout << root->key;
        preOrder(root->left);
        preOrder(root->right);
    }
}

4.2 middle order traversal

Traversing the binary sort tree in middle order will get an ordered sequence of keywords.

/*Medium order traversal*/
void BSTree::inOrder(BSTNode* root)
{
    if (root != NULL)
    {
        inOrder(root->left);
        cout << root->key;
        inOrder(root->right);
    }
}

4.3 post order traversal

/*Postorder traversal*/
void BSTree::postOrder(BSTNode* root)
{
    if (root != NULL)
    {
        postOrder(root->left);
        postOrder(root->right);
        cout << root->key;
    }
}

5. Find

When the binary tree is not empty, first compare the key value to be found with the key value of the root node. If it is greater than the key value of the root node, continue to find the right subtree, otherwise find the left subtree. Repeat the above process until the search is successful and the found node is returned. Otherwise, it returns null.

BSTNode* BSTree::search(BSTNode* node, int key)
{
    if (node == NULL || node->key == key)
        return node;
    if (node->key < key)
        search(node->right, key);
    else search(node->left, key);
}

6. Maximum and minimum values

In a non empty binary sort tree, the minimum node is the lowest left node and the maximum node is the lowest right node.

6.1 obtaining the minimum value node

BSTNode* BSTree::minimum(BSTNode* node)
{
    if (node->left == NULL)
        return node;
    minimum(node->left);
}

6.2 obtaining the maximum node

BSTNode* BSTree::maximum(BSTNode* node)
{
    if (node->right == NULL)
        return node;
    maximum(node->right);
}

7. Predecessor node and successor node

The precursor node of node is the largest node among all nodes whose key value is less than node;
The successor node of node is the smallest node among all nodes whose key value is greater than node.

7.1 precursor node

  1. If a node has a left subtree, its predecessor node is the node with the largest val value in its left subtree (that is, the rightmost node in the left subtree)

  2. If a node has no left subtree

    1) If the node is the right child of its parent node, the precursor node of the node is its parent node.
    2) If the node is the left child of its parent node, you need to look along its parent node to the top of the tree until you find a node P. node P is the right child of its parent node Q, then q is the precursor node of the node.

/*Find the precursor node of node node*/
BSTNode* BSTree::predecessor(BSTNode* node)
{
    /*(1)If the left subtree is not empty, return the maximum node of the left subtree*/
    if (node->left != NULL)
        return maximum(node->left);

    /*(2)*/
    BSTNode* pnode = node->parent;
    while (pnode != NULL&&node == pnode->left)
    {
        node = pnode;
        pnode = pnode->parent;
    }
    return pnode;
}

7.2 successor nodes

  1. If a node has a right subtree, its successor node is the node with the smallest val value in its right subtree (that is, the leftmost node in the right subtree)

  2. If a node has no right subtree
    1) If the node is the left child of its parent node, the successor node of the node is its parent node.
    2) If the node is the right child of its parent node, you need to look along its parent node to the top of the tree until you find a node P. node P is the left child of its parent node Q, then q is the precursor node of the node.

/*Find the successor node of node*/
BSTNode* BSTree::successor(BSTNode* node)
{
    /*(1)If the right subtree is not empty, the minimum value node of the right subtree is returned*/
    if (node->right != NULL)
        return minimum(node->right);

    /*(2)*/
    BSTNode* pnode = node->parent;
    while (pnode != NULL&&node == pnode->right)
    {
        node = pnode;
        pnode = pnode->parent;
    }
    return pnode;
}

8. Delete node

Suppose that the node to be deleted is * P (P is the pointer to the node to be deleted), and its parent node is * f. without losing generality, let * p be the left child of * f.
(1) If * p node is a leaf node, that is, PL and PR are empty, you only need to modify F - > left to be empty;

(2) If * p node has only left subtree PL or only right subtree PR, it only needs to make PL and PR directly become the left child of f;

(3) If both the left subtree and the right subtree of the * p node are not empty, there are two ways to keep the relative position of other elements unchanged after deleting * p:

(3.1) method 1: let * s be the rightmost node of the left subtree PL of * P, then let the left subtree PL of * p be the left subtree of f, and the right subtree PR of p be the right subtree of * s;

(3.2) method 2: make the direct precursor (or direct successor) of * p replace * p, and then delete its direct precursor (or direct successor) from the binary sort tree.

The following code adopts practice 1 when encountering situation (3):

/*Get the node to be deleted and return*/
BSTNode* BSTree::remove(BSTNode*& root, int key)
{
    BSTNode* node = search(root, key);
    printf("%d\n", node->key);
    if (node != NULL)
    {
        if (node->left == NULL && node->right == NULL)    //Node is a leaf node
        {
            if (node->parent == NULL)    //The node to be deleted is the root node
                return node;
            else if (node->parent->left == node)//Determine whether the point to be deleted is on the left or right of the parent node
                node->parent->left = NULL;
            else
                node->parent->right = NULL;
        }
        else if (node->left == NULL)    //node left subtree is empty
        {
            if (node->parent == NULL)  //The node to be deleted is the root node
            {
                this->root = node->right;
                node->right->parent = NULL;
            }
            else if (node->parent->left == node)//Determine whether the point to be deleted is on the left or right of the parent node
                node->parent->left = node->right;
            else
                node->parent->right = node->right;
        }
        else if (node->right == NULL)    //node right subtree is empty
        {
            if (node->parent == NULL)    //The node to be deleted is the root node
            {
                this->root = node->left;
                node->left->parent = NULL;
            }
            else if (node->parent->left == node)//Determine whether the point to be deleted is on the left or right of the parent node
                node->parent->left = node->left;
            else
                node->parent->right = node->left;
        }
        else                            //The left and right subtrees of node are not empty
        {
            BSTNode* lnode = node->left;    //lnode is initially the root node of the left subtree of node
            while (lnode->right)            //Find the rightmost node of the left subtree of node and assign it as lnode
                lnode = lnode->right;
            lnode->right = node->right;        //Turn the right subtree of node into the right subtree of lnode
            node->right->parent = lnode;
            if (node->parent == NULL)   //The node to be deleted is the root node
            {
                this->root = node->right;
                if (node->right->left != NULL)
                {
                    BSTNode* leftDownNode = minimum(node->right);
                    leftDownNode->left = node->left;
                    node->left->parent = leftDownNode;
                }
                else
                {
                    node->right->left = node->left;
                    node->left->parent = node->right;
                }
            }
            else if (node->parent->left == node)    //Replace the left subtree of node with the position of node
            {
                node->parent->left = node->left;
                node->left->parent = node->parent;
            }
            else if (node->parent->right == node)
            {
                node->parent->right = node->left;
                node->left->parent = node->parent;
            }
        }
    }
    return node;
}

9. Destruction

There is no difference between destroying a binary sort tree and destroying an ordinary binary tree. Here, the post order traversal method is used to destroy it.

/*Destroy binary tree*/
void BSTree::destroy(BSTNode* root)
{
    if (root == NULL)
        return;
    destroy(root->left);
    destroy(root->right);
    delete root;
}

Posted by muppet on Thu, 23 Sep 2021 04:43:25 -0700