C++二叉排序树

前言

二叉排序树又叫二叉搜索树, 二叉查找树, 二叉树数据结构中相对简单的一种,一般情况下查询效率比链表高,二叉排序树在集合实际应用比较少,但它衍生出的AVL树和红黑树比较常用也比较难, 因此需要先掌握二叉排序树的结构

一:定义

二叉排序树可以是一棵空树,或者是具有下列性质的二叉树
1. 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3. 它的左右子树也分别为二叉排序树
补充:前驱与后继
前驱:节点的左子树不为空时,前驱为左子树中最大的节点(即左子树中最右节点)
后继:节点的右子树不为空时,后继为右子树中最小的节点(即右子树中最左节点)

二:插入节点

二叉排序树添加.png

三:删除节点(写法重点)

1:删除叶子节点(左右子节点都为空)时,不影响整体树结构,直接删除即可
2:删除的节点只有左子节点或只有右子节点(即右子节点为空或左子节点为空)时,只需要将其左子节点或右子节点代替删除的节点位置即可
删除只有左或右子节点.jpg
3:删除节点的左右子节点都不为空时,找到删除节点的前驱或者后继为替代删除的节点, 然后删除前驱或者后继点节即可,前驱节点为最右节点不存在右子节点,后继节点为最左节点不存在左子节点,因此删除前驱或后继节点又相当到第1,或第2步了
删除有左和右子节点.jpg

四:代码实现

struct BinarySortTreeNode {
    int data;
    BinarySortTreeNode *left = NULL;
    BinarySortTreeNode *right = NULL;
    BinarySortTreeNode(int data) {
        this->data = data;
    }
};

//二叉排序树
class BinarySortTree {
private:
    BinarySortTreeNode *root = NULL;
    int len = 0;
    //添加新节点
    BinarySortTreeNode* addNode(BinarySortTreeNode *node, int data);
    //移除节点
    BinarySortTreeNode* removeNode(BinarySortTreeNode *node, int data);
    //移除节点中最小的节点
    BinarySortTreeNode* removeLeftMinNode(BinarySortTreeNode *node, BinarySortTreeNode **successor);
    //释放节点及其所有子节点
    void freeNode(BinarySortTreeNode *node);
public:
    ~BinarySortTree();
    int size();
    void add(int data);
    void remove(int data);
    //层级打印
    void levelShow();
};

BinarySortTree::~BinarySortTree() {
    freeNode(root);
    root = NULL;
}

void BinarySortTree::freeNode(BinarySortTreeNode *node) {
    if (node) {
        freeNode(node->left);
        freeNode(node->right);
        delete node;
    }
}

BinarySortTreeNode* BinarySortTree::addNode(BinarySortTreeNode *node, int data) {
    if (!node) {
        len++;
        return new BinarySortTreeNode(data);
    }
    if (node->data > data) {
        node->left = addNode(node->left, data);
    } else {
        node->right = addNode(node->right, data);
    }
    return node;
}

BinarySortTreeNode* BinarySortTree::removeLeftMinNode(BinarySortTreeNode *node, BinarySortTreeNode **successor) {
    if (node->left) {
        node->left = removeLeftMinNode(node->left, successor);
        return node;
    } else {
        *successor = node;
        return node->right;
    }
}

BinarySortTreeNode* BinarySortTree::removeNode(BinarySortTreeNode *node, int data) {
    if (!node) return NULL;
    if (node->data > data) {
        node->left = removeNode(node->left, data);
    } else if (node->data < data) {
        node->right = removeNode(node->right, data);
    } else {  //相等
        len--;
        if (!node->left && !node->right) {
            delete node;
            return NULL;
        }
        if (!node->left) {
            BinarySortTreeNode *right = node->right;
            delete node;
            return right;//right not null
        }
        if (!node->right) {
            BinarySortTreeNode *left = node->left;
            delete node;
            return left; //left not null
        }
        //node right left都不为空
        BinarySortTreeNode *successor;
        //遍历查找后继节点时就直接断开后继节点
        node->right = removeLeftMinNode(node->right, &successor);
        node->data = successor->data;
        delete successor;
    }
    return node;
}

int BinarySortTree::size() {
    return this->len;
}

void BinarySortTree::add(int data) {
    root = addNode(root, data);
}

void BinarySortTree::remove(int data) {
    root = removeNode(root, data);
}

void BinarySortTree::levelShow() {
    std::string str;
    if (root) {
        ArrayDeque nodeDeque;
        nodeDeque.push(root);
        while (!nodeDeque.isEmpty()) {
            BinarySortTreeNode *node = nodeDeque.pop();
            str += std::to_string(node->data);
            str += "(L:";
            if (node->left) {
                nodeDeque.push(node->left);
                str += to_string(node->left->data);
            } else {
                str +="#";
            }
            str += ",R:";
            if (node->right) {
                nodeDeque.push(node->right);
                str += to_string(node->right->data);
            } else {
                str +="#";
            }
            str += ')';
        }
    }
    LOGD("levelTree: %s", str.c_str());
}
当插入的节点相对有序时,此时的二叉树就是一棵斜树,此时的结构就类似于单链表结构,查找的时间复杂度又成O(n)如图, 为了解决此问题又衍生出AVL树与红黑树
斜树单链表.png
最后附上源码https://github.com/youxiaochen/DataStructTree
数据结构看10次都不如自己动手敲一次印象深,代码中如有错误欢迎指教

更多文章请关注:http://www.jianshu.com/u/b1cff340957c

你可能感兴趣的:(C++二叉排序树)