二叉查找树 BST

版权声明:转载请写明出处,谢谢! https://blog.csdn.net/wilson1068/article/details/88429190

二叉查找树 BST

二叉查找树:二叉查找树(Binary Search Tree)又称二叉搜索树、二叉排序树(Binary Sort Tree)或有序二叉树(ordered binary tree)。

具有以下特性:

  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  3. 左、右子树也分别为二叉排序树;
  4. 没有键值相等的节点。

性质:对二叉查找树进行中序遍历,可以得到有序的数列。

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。

二叉查找树时间复杂度

算法 平均 最差 说明
空间 O ( n ) O(n) O ( n ) O(n)
搜索 O ( log n ) O(\log{n}) O ( n ) O(n) 数列有序,树退化成线性表时。效率最低。
插入 O ( log n ) O(\log{n}) O ( n ) O(n) 数列有序,树退化成线性表时。效率最低。
删除 O ( log n ) O(\log{n}) O ( n ) O(n) 数列有序,树退化成线性表时。效率最低。

二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、多重集、关联数组等。

虽然二叉查找树的最坏效率是 O ( n ) O(n) ,但它支持动态查询,且有很多改进版的二叉查找树可以使树高为 O ( log n ) O(\log{n}) ,从而将最坏效率降至 O ( log n ) O(\log{n}) ,如 AVL 树、红黑树等。

二叉查找树建立,插入,删除,查找

基本符合二分查找的规则。

比较复杂的就是删除操作。

如果删除的节点有左右子树,那么需要保证删除后的左右子树依然满足:左子树所有节点的值 < 新节点,新节点 < 右子树所有节点的值。

那么,删除这种节点时,需要选择左子树最大的值,或者右子树最小的值。

那么其实只要找到左子树最大的值,或者右子树最小的值替换到当前节点的值即可。

void createBinarySearchTree(stBinaryTreeNode * root, void ** datas, const int datas_len) {
    for (int i = 0; i < datas_len; ++ i) {
        insertBinarySearchTree(root, datas[i]);
    }
}

int insertBinarySearchTree(stBinaryTreeNode * root, void * data) {
    stBinaryTreeNode * node = (stBinaryTreeNode *) malloc(sizeof(stBinaryTreeNode));
    node->data = data;
    node->lchild = node->rchild = NULL;
    if (root == NULL) {
        root = node;
        return 1;
    }
    stBinaryTreeNode * head = root;
    // 类似于二分查找
    for ( ; ; ) {
        if ((int)data < (int)head->data) {          // 查找左子树
            if (head->lchild) {
                head = head->lchild;
            } else {
                head->lchild = node;
                break;
            }
        } else if ((int)data > (int)head->data) {   // 查找右子树
            if (head->rchild) {
                head = head->rchild;
            } else {
                head->rchild = node;
                break;
            }
        } else {
            return 0;
        }
    }
    return 1;
}

int removeBinarySearchTree(stBinaryTreeNode ** proot, void * data) {
    stBinaryTreeNode * node = *proot;
    stBinaryTreeNode * parent_node = root;
    int find = 0;
    while (node != NULL) {
        if ((int)data < (int)node->data) {          // 查找左子树
            parent_node = node;
            node = node->lchild;
        } else if ((int)data > (int)node->data) {   // 查找右子树
            parent_node = node;
            node = node->rchild;
        } else /* if ((int)data == (int)node->data) */ {
            break;
        }
    }
    if (node == NULL) { // 未找到
        return 0;
    }

#define NODE_IS_ROOT        0x10000
#define NODE_IS_L_NULL      0x01000
#define NODE_IS_R_NULL      0x00100
#define NODE_IN_L_PNODE     0x00010
#define NODE_IN_R_PNODE     0x00001

    int node_pnode_status = 0;
    if (node == *proot)                 node_pnode_status |= NODE_IS_ROOT;
    if (node->lchild == NULL)           node_pnode_status |= NODE_IS_L_NULL;
    if (node->rchild == NULL)           node_pnode_status |= NODE_IS_R_NULL;
    if (parent_node->lchild == node)    node_pnode_status |= NODE_IN_L_PNODE;
    if (parent_node->rchild == node)    node_pnode_status |= NODE_IN_R_PNODE;

    switch(node_pnode_status) {
        case (NODE_IS_ROOT | NODE_IS_L_NULL | NODE_IS_R_NULL | 0):          // 叶子节点(node是根节点)
            *proot = NULL;
            break;

        case (0 | NODE_IS_L_NULL | NODE_IS_R_NULL | NODE_IN_L_PNODE | 0):   // 叶子节点(node是左节点)
            parent_node->lchild = NULL;
            break;

        case (0 | NODE_IS_L_NULL | NODE_IS_R_NULL | 0 | NODE_IN_R_PNODE):   // 叶子节点(node是右节点)
            parent_node->rchild = NULL;
            break;

        case (NODE_IS_ROOT | 0 | NODE_IS_R_NULL | 0 | 0):                   // 左单只子树(node是根节点)
            *proot = node->rchild;
            break;

        case (NODE_IS_ROOT | NODE_IS_L_NULL | 0 | 0 | 0):                   // 右单只子树(node是根节点)
            *proot = node->rchild;
            break;

        case (NODE_IS_ROOT | 0 | NODE_IS_R_NULL | NODE_IN_L_PNODE | 0):     // 左单只子树(node是左节点)
            parent_node->lchild = node->lchild;
            break;

        case (NODE_IS_ROOT | NODE_IS_L_NULL | 0 | NODE_IN_L_PNODE | 0):     // 右单只子树(node是左节点)
            parent_node->rchild = node->lchild;
            break;

        case (NODE_IS_ROOT | 0 | NODE_IS_R_NULL | 0 | NODE_IN_R_PNODE):     // 右单只子树(node是左节点)
            parent_node->lchild = node->rchild;
            break;

        case (NODE_IS_ROOT | NODE_IS_L_NULL | 0 | 0 | NODE_IN_R_PNODE):     // 右单只子树(node是右节点)
            parent_node->rchild = node->rchild;
            break;

        case (NODE_IS_ROOT | 0 | 0 | 0 | 0):                                // 左右子树非空(node是根节点)
        case (NODE_IS_ROOT | 0 | 0 | NODE_IN_L_PNODE | 0):                  // 左右子树非空(node是左节点)
        case (NODE_IS_ROOT | 0 | 0 | 0 | NODE_IN_R_PNODE):                  // 左右子树非空(node是左节点)
            {
                stBinaryTreeNode * tmp = node;
                stBinaryTreeNode * s = node->lchild;
                while (s->rchild) {
                    tmp = s;
                    s = s->rchild;
                }
                node->data = s->data;
                if (tmp == node) {
                    node->lchild = s->lchild;
                } else {
                    node->rchild = s->lchild;
                }
                node = s;
            }
            break;
    }
    free(node);
    return 1;
}

stBinaryTreeNode * searchBinarySearchTree(stBinaryTreeNode * root, void * data) {
    stBinaryTreeNode * node = root;
    while (node) {
        if ((int)data < (int)node->data) {
            node = node->lchild;
        } else if ((int)data > (int)node->data) {
            node = node->rchild;
        } else {
            return node;
        }
    }
    return NULL;
}

猜你喜欢

转载自blog.csdn.net/wilson1068/article/details/88429190