二叉排序树(二叉搜索树)BST增删改查操作

news2025/1/15 16:44:16

一、定义

二叉搜索树(Binary Search Tree,BST)是一种常用的二叉树数据结构,具有以下特点:

1. **排序性质**:对于树中的每个节点,其左子树中的所有节点值都小于该节点的值,而右子树中的所有节点值都大于该节点的值。

2. **唯一性质**:二叉搜索树中不存在相同值的节点。

3. **递归性质**:二叉搜索树的左子树和右子树也分别是二叉搜索树。

这些性质使得二叉搜索树成为一种非常高效的数据结构,可以支持快速的搜索、插入和删除操作。在二叉搜索树中,搜索操作的时间复杂度为 O(log n),其中 n 是树中节点的数量(在最坏情况下可能会退化为 O(n))。

除了搜索操作,二叉搜索树还支持以下操作:

- **插入**:将新节点按照排序性质插入到树中的合适位置。

- **删除**:从树中删除指定值的节点,并保持树的排序性质不变。

- **中序遍历**:按照左根右的顺序遍历树中的所有节点,可以得到一个有序序列。

二叉搜索树的实现可以使用递归或迭代的方式,常见的实现包括普通二叉树节点的定义和相关操作,以及平衡二叉搜索树(如AVL树、红黑树)等。

二、BST的先序创建

BST的节点结构如下: 

// 定义二叉树的节点结构
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} // 构造函数
};

 我们要建立一个 左子树 < 节点 < 右子树的二叉树(例如下图)

 

我们使用前序创建上述树结构,前序创建树函数如下所示: 

// 前序创建二叉树
TreeNode* createPreOrder() {
    int val;
    std::cin >> val;
    if (val == 0) {
        return nullptr;
    }
    TreeNode* root = new TreeNode(val);
    root->left = createPreOrder();
    root->right = createPreOrder();
    return root;
}

主函数如下:

int main() {
    
    // 前序创建二叉树
    std::cout << "Enter the elements of the tree in pre-order traversal (0 for null):\n";
    TreeNode* root = createPreOrder();
    // std::cout << root->val; // 输出1【测试代码】
    
    // 前序遍历二叉树
    std::cout << "Pre-order traversal of the created tree: ";
    preOrderTraversal(root);
    std::cout << std::endl; // 换行


    // 释放内存,防止内存泄漏
    delete root;

    return 0;
}

        运行上述代码,输入4 2 1 0 0 3 0 0 8 7 5 0 0 0 9 0 10 0 0,即可创建上述BST,该树的前序遍历结果为:4 2 1 3 8 7 5 9 10

三、BST的插入操作

 例如我们要将6添加到前面的二叉树之中

比较 6 > 4 因此 ,接右子树
比较 6 < 8 ,接左子树
比较 6 < 7 接左子树
比较 6 > 5 ,且 5 的右子树为空,将 6 作为 5 的右子
结束
图解如下图所示:

// 二叉搜索树(binary search tree, BST)中添入新的元素
bool BST_InsertItem(TreeNode* T, int num) { // num表示要插入的元素
    
    TreeNode* node = new TreeNode(num); // 定义要插入的新节点
    
    // 第一个插入的元素为根节点
    if (T == nullptr) { // 说明该二叉树为空
        T = node;
    }

    // 二叉树不为空
    while (T != nullptr) {
        // 小的node插入到左子树中
        if (node->val < T->val) {
            // 叶子节点就插入
            if (T->left == nullptr) {
                T->left = node;
                return true;
            }
            else {
                // 不是叶子节点就继续,直到叶子节点
                T = T->left;
            }
        }
        
        // 大的node插入到右子树中
        if (node->val > T->val) {
            // 叶子节点就插入
            if (T->right == nullptr) {
                T->right = node;
                return true;
            }
            else {
                // 不是叶子节点就继续,直到叶子节点
                T = T->right;
            }
        }  

        // 插入的元素与二叉树中的元素相等
        if (node->val == T->val) {
            return false;
        }   
    }  
}

四、BST的查询操作

查询的本质类似,一个小游戏:“在100以内猜一个数,我会告诉你结果是大了还是小了。”

例如我们查询值为 6 的节点

6 > 4 ,继续右子树
6 < 8 ,继续左子树
6 < 7 ,继续左子树
6 > 5 ,继续右子树
6 == 6 , 找到节点,返回结果 .
// 二叉搜索树(binary search tree, BST)元素查询操作
TreeNode* BST_queryItem(TreeNode* T, int num) { // num表示要查询的元素
    if (T == nullptr) {
        std::cout << "二叉搜索树为空!" << std::endl;
    }

    while (T != nullptr) { // BST不为空
        if (num > T->val) { // 大的节点继续右子树
            T = T->right;
        }
        else if (num < T->val) { // 小的节点继续左子树
            T = T->left;
        }
        else if (num == T->val) { // 相等就返回结果
            return T;
        }
    }
    // 查无此素
    std::cout << "查无此素!" << std::endl;
}

四、BST的改操作

- 修改二叉树的值

使用查 - 搜索二叉树找到二叉树需要修改的节点, 然后改变这个节点值即可。
// 二叉搜索树(binary search tree, BST)元素改操作
void BST_modifyItem(TreeNode* T, int num, int modify_num) { // num表示要修改的元素,modify_num表示修改值
    TreeNode* BST_node = BST_queryItem(T, num);
    BST_node->val = modify_num;
}

五、BST的删除操作

5.1 删除的节点为叶子节点

第一种 删除方法最简单

设立要删除的节点current;

找到要删除的节点的父节点parent;

判断删除的节点父节点的左子树还是右子

根据节点删除方法:parent->left = nullptr;parent->right = nullptr

5.2 删除的节点只有左子树或者只有右子树

第二种 删除方法稍微有点复杂

找到要删除的节点current;

找到要删除的节点的父节点parent;

判断current子节点是左子树还是右子树

判断current父节点的左子树还是右子树;

如果 current下面是左子节点,且

如果currentparent的左子节点-----parent.left = current.left;

如果currentparent的右子节点-----parent.right = current.left;

如果 current下面是右子节点,且:

如果currentparent的左子节点-----parent.left = current.right;

如果currentparent的右子节点-----parent.right = current.right;

5.3 删除的节点既有左子树又有右子树

第三删除一个有两个子树的节点后,需要将其左子树或右子树的节点提升到删除节点的位置,以保持二叉树的结构。通常选择将右子树中的最小节点(或者左子树中的最大节点)提升到删除节点的位置,因为这样可以保持二叉搜索树的性质。

具体步骤如下:

1. 找到要删除节点的右子树中的最小节点(或者左子树中的最大节点)。
2. 将该最小节点的值复制到要删除节点的位置上。
3. 删除该最小节点(或者最大节点)。

5.4 上述三种情况的代码

// 二叉排序树元素删除操作
TreeNode* BST_deleteItem(TreeNode* root, int num) { // num表示要删除的元素
    
    TreeNode* current = BST_queryItem(root, num); // 找到要删除的节点
    TreeNode* parent = findParent(root, num); // 找到要删除的节点的父节点

    if (root == nullptr) { // 说明二叉树为空,此时需要构建一颗二叉树才可进行删除操作
        std::cout << "二叉树为空, 删除失败!" << std::endl;
    }
    // 二叉树只有一个节点时,直接删除
    if (root->left == nullptr && root->right == nullptr) {
        root = nullptr;
        return root;
    }

    // 第一种情况:要删除的节点为叶子节点,此时直接删除即可
    if (current->left == nullptr && current->right == nullptr) { // 条件成立,说明删除的节点为叶子节点
        // 判断要删除的节点是父节点的左子节点还是右子节点
        if (parent->left != nullptr && parent->left->val == num) { // 是左子节点
            parent->left = nullptr;
        }
        else if (parent->right != nullptr && parent->right->val == num) { // 是右子节点
            parent->right = nullptr;
        }
    }

    // 第二种情况:删除有两颗子树的节点
    else if (current->left != nullptr && current->right != nullptr) {
        TreeNode* minRightNode = findMin(current->right); // 找到右子树中的最小节点
        current->val = minRightNode->val; // 用右子树中的最小节点替换要删除的节点
        current->right = BST_deleteItem(current->right, minRightNode->val); // 删除右子树中的最小节点
    }

    // 第三种情况:删除只有一颗子树(左子树或者右子树)的节点
    else if (current->left == nullptr && current->right != nullptr) { // 删除的节点只有右子树
        if (parent != nullptr) {
            if (parent->left->val == num) { // 情况1:是左子节点(删除的节点相对于其父节点是左子节点)
                parent->left = current->right;
            }
            else { // 情况2:是右子节点(删除的节点相对于其父节点是右子节点)
                parent->right = current->right;
            }
        }
        else {
            root = current->right; // 情况3
        }
    }
    else if (current->left != nullptr && current->right == nullptr) { // 删除的节点只有左子树
        if (parent != nullptr) {
            if (parent->left->val == num) { // 情况1:是左子节点
                parent->left = current->left;
            }
            else { // 情况2:是右子节点
                parent->right = current->left;
            }
        }
        else {
            root = current->left; // 情况3
        }
    }

    return root;
}

5.5 找寻删除节点的父节点

// 找到删除节点的父节点
TreeNode* findParent(TreeNode* root, int toDelete) { // root表示根节点,toDelete表示要删掉的元素
    if (root == nullptr) return nullptr;

    if (root->left != nullptr && root->left->val == toDelete) return root;
    if (root->right != nullptr && root->right->val == toDelete) return root;

    TreeNode* parent = findParent(root->left, toDelete);
    if (parent != nullptr) return parent;
    return findParent(root->right, toDelete);
}

5.5 找寻最小节点

注意:BST中最左边的值最小。

// 找到以root为根的子树中最小节点
TreeNode* findMin(TreeNode* root) {
    while (root->left != nullptr) {
        root = root->left;
    }
    return root;
}

 六、总代码

注意,这个代码中还含有统计二叉树的性质相关部分代码。

#include <iostream>
#include <queue>
#include <cmath>

// 定义二叉树的节点结构
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} // 构造函数
};

// 前序创建二叉树
TreeNode* createPreOrder() {
    int val;
    std::cin >> val;
    if (val == 0) {
        return nullptr;
    }
    TreeNode* root = new TreeNode(val);
    root->left = createPreOrder();
    root->right = createPreOrder();
    return root;
}


// 前序遍历打印二叉树
void preOrderTraversal(TreeNode* root) {
    if (root) {
        std::cout << root->val << " ";
        preOrderTraversal(root->left);
        preOrderTraversal(root->right);
    }
}

// 中序遍历打印二叉树
void InOrderTraversal(TreeNode* root) {
    if (root) {
        InOrderTraversal(root->left);
        std::cout << root->val << " ";
        InOrderTraversal(root->right);
    }
}

// 统计度为0的节点个数
int count_Node_0(TreeNode* T) {
    if (T == nullptr) { // 二叉树为空
        return 0;
    }
    if ((T->left == nullptr) && (T->right == nullptr)) { // 找到叶子节点
        return count_Node_0(T->left) + count_Node_0(T->right) + 1;
    }
    else {
        return count_Node_0(T->left) + count_Node_0(T->right);
    }
}

// 统计度为1的节点个数
int count_Node_1(TreeNode* T) {
    if (T == nullptr) {
        return 0;
    }
    if (((T->left == nullptr)&&(T->right != nullptr)) || ((T->left != nullptr) && (T->right == nullptr))) { // 找到度为1的节点
        return count_Node_1(T->left) + count_Node_1(T->right) + 1;
    }
    else {
        return count_Node_1(T->left) + count_Node_1(T->right);
    }
}

// 统计度为2的节点个数
int count_Node_2(TreeNode* T) {
    if (T == nullptr) {
        return 0;
    }
    if ((T->left != nullptr) && (T->right != nullptr)) { // 找到度为2的节点
        return count_Node_2(T->left) + count_Node_2(T->right) + 1;
    }
    else {
        return count_Node_2(T->left) + count_Node_2(T->right);
    }
}

// 统计二叉树节点个数
int count_Node(TreeNode* T) {
    if (T == nullptr) {
        return 0;
    }

    return count_Node(T->left) + count_Node(T->right) + 1; // 总节点个数=左子树节点数+右子树节点数+根结点数(1)
}

// 计算二叉树的深度
int Depth(TreeNode* T) {
    if (T == nullptr) { // 二叉树为空,则深度为0
        return 0;
    }
    else {
        int m = Depth(T->left);
        int n = Depth(T->right);
        if (m > n) {
            return m + 1;
        }
        else {
            return n + 1;
        }
    }
}

// 层序遍历
void level_order_tras(TreeNode* T) {
    if (T == nullptr) { // 代码若改为if (T = nullptr) 则会引出下面两个错误
        return;
    }

    // 创建队列,用于存放待访问的节点
    std::queue<TreeNode*> q;
    // 将根节点入队
    q.push(T);
    // std::cout << T->val; // 报错【测试代码】
    // std::cout << q.front()->val; // 报错【测试代码】

    //开始层序遍历
    while (!q.empty()) {
        // 确定当前层节点个数
        int levelSize = q.size();

        //遍历当前层的所有节点
        for (int i = 0; i < levelSize; ++i) {
            // 取出队首节点
            TreeNode* node = q.front();
            q.pop();
            // 输出节点值
            std::cout << node->val << " ";
            
            // 将当前节点的左右子节点入队
            if (node->left != nullptr) {
                q.push(node->left);
            }
            if (node->right != nullptr) {
                q.push(node->right);
            }
        }
    }
}

// 层序遍历(每层输出)
void level_print(TreeNode* T) {
    if (T == nullptr) {
        return;
    }

    // 创建队列,用于存放待访问的节点
    std::queue<TreeNode*> q;
    // 将根节点入队
    q.push(T);

    int j = 1; // j表示层数
    //开始层序遍历
    while (!q.empty()) {
        std::cout << "第" << j << "层的数据为:";
        // 确定当前层节点个数
        int levelSize = q.size();

        //遍历当前层的所有节点
        for (int i = 0; i < levelSize; i++) {
            // 取出队首节点
            TreeNode* node = q.front();
            q.pop();
            std::cout << node->val << " ";

            // 将当前节点的左右子节点入队
            if (node->left != nullptr) {
                q.push(node->left);
            }
            if (node->right != nullptr) {
                q.push(node->right);
            }
        }
        j++;
        std::cout << std::endl; // 换行
    }

}

/*
// 判断一个二叉树是否为完全二叉树
void Complete_binary_tree(TreeNode* T) { // 【错误代码】
    // 思路:具有n个节点的完全二叉树的深度为{log2n}+1(2为底数,{}表示向下取整 )
    if (T == nullptr) {
        std::cout << "该二叉树是一颗空二叉树!" << std::endl;
    }
    int h = Depth(T); // 获取二叉树的深度,即层数
    int node = count_Node(T); // 获取二叉树的节点总数

    // 使用换底公式定义以2为底数的对数函数
    double log_2_node = log(node) / log(2);// 计算以e为底的对数,即ln(x)
    std::cout << "log_2_node:" << log_2_node;
    if (h == (floor(log_2_node) + 1)) {
        std::cout << "这颗二叉树是一颗完全二叉树!" << std::endl;
    }
    std::cout << "这颗二叉树不是一颗完全二叉树!" << std::endl;
}
*/





// 判断是否为完全二叉树

/*
基本思路:使用队列按层次遍历二叉树,遍历过程中将二叉树的所有结点依次入队。
当出队遇见一个NULL结点时,若遍历其后结点都为NULL则为完全二叉树,否则不是完全二叉树。
因为层次遍历完全二叉树时,当遍历到空结点时前面所有非空结点已经被遍历完了,若空结点之后还有非空结点则不是完全二叉树。
*/
bool Complete_binary_tree(TreeNode* T) {
    if (T == nullptr) { 
        std::cout << "该二叉树是一颗空二叉树!" << std::endl;
    }

    // 创建队列,用于存放待访问的节点
    std::queue<TreeNode*> q;
    // 将根节点入队
    q.push(T);
    bool encounteredNull = false; // 是否遇到过空节点

    //开始层序遍历
    while (!q.empty()) { // 队列不为空
        
        // 取出队首节点
        TreeNode* current = q.front();
        q.pop();

        if (current == nullptr) {
            encounteredNull = true;
            continue;
        }

        if (encounteredNull && current != nullptr) {
            // 遇到空节点后面还有非空节点,则说明不是完全二叉树
            return false;
        }
        q.push(current->left);
        q.push(current->right);  
    } 
    return true;
}

// 判断一个二叉树是否为满二叉树
void Full_binary_tree(TreeNode* T) {
    if (T == nullptr) {
        std::cout << "该二叉树是一颗空二叉树!" << std::endl;
    }
    int h = Depth(T); // 获取二叉树的深度,即层数
    int node = count_Node(T); // 获取二叉树的节点总数
    if (node == (2 ^ h) - 1) { // 说明二叉树为满二叉树
        std::cout << "该二叉树是一颗满二叉树!" << std::endl;
        std::cout << "深度为:" << h << "," << "节点总数为:" << node << std::endl;
    }
    else {
        std::cout << "这颗二叉树不是满二叉树!" << std::endl;
        std::cout << "深度为:" << h << "," << "节点总数为:" << node << std::endl;
    }
   
}


// 二叉搜索树(binary search tree, BST)中添入新的元素
bool BST_InsertItem(TreeNode* T, int num) { // num表示要插入的元素
    
    TreeNode* node = new TreeNode(num); // 定义要插入的新节点
    
    // 第一个插入的元素为根节点
    if (T == nullptr) { // 说明该二叉树为空
        T = node;
    }

    // 二叉树不为空
    while (T != nullptr) {
        // 小的node插入到左子树中
        if (node->val < T->val) {
            // 叶子节点就插入
            if (T->left == nullptr) {
                T->left = node;
                return true;
            }
            else {
                // 不是叶子节点就继续,直到叶子节点
                T = T->left;
            }
        }
        
        // 大的node插入到右子树中
        if (node->val > T->val) {
            // 叶子节点就插入
            if (T->right == nullptr) {
                T->right = node;
                return true;
            }
            else {
                // 不是叶子节点就继续,直到叶子节点
                T = T->right;
            }
        }  

        // 插入的元素与二叉树中的元素相等
        if (node->val == T->val) {
            return false;
        }   
    }  
}

// 二叉搜索树(binary search tree, BST)元素查询操作
TreeNode* BST_queryItem(TreeNode* T, int num) { // num表示要查询的元素
    if (T == nullptr) {
        std::cout << "二叉搜索树为空!" << std::endl;
    }

    while (T != nullptr) { // BST不为空
        if (num > T->val) { // 大的节点继续右子树
            T = T->right;
        }
        else if (num < T->val) { // 小的节点继续左子树
            T = T->left;
        }
        else if (num == T->val) { // 相等就返回结果
            return T;
        }
    }
    // 查无此素
    std::cout << "查无此素!" << std::endl;
}

// 二叉搜索树(binary search tree, BST)元素改操作
void BST_modifyItem(TreeNode* T, int num, int modify_num) { // num表示要修改的元素,modify_num表示修改值
    TreeNode* BST_node = BST_queryItem(T, num);
    BST_node->val = modify_num;
}


// 找到删除节点的父节点
TreeNode* findParent(TreeNode* root, int toDelete) { // root表示根节点,toDelete表示要删掉的元素
    if (root == nullptr) return nullptr;

    if (root->left != nullptr && root->left->val == toDelete) return root;
    if (root->right != nullptr && root->right->val == toDelete) return root;

    TreeNode* parent = findParent(root->left, toDelete);
    if (parent != nullptr) return parent;
    return findParent(root->right, toDelete);
}

// 找到以root为根的子树中最小节点
TreeNode* findMin(TreeNode* root) {
    while (root->left != nullptr) {
        root = root->left;
    }
    return root;
}


// 二叉排序树元素删除操作
TreeNode* BST_deleteItem(TreeNode* root, int num) { // num表示要删除的元素
    
    TreeNode* current = BST_queryItem(root, num); // 找到要删除的节点
    TreeNode* parent = findParent(root, num); // 找到要删除的节点的父节点

    if (root == nullptr) { // 说明二叉树为空,此时需要构建一颗二叉树才可进行删除操作
        std::cout << "二叉树为空, 删除失败!" << std::endl;
    }
    // 二叉树只有一个节点时,直接删除
    if (root->left == nullptr && root->right == nullptr) {
        root = nullptr;
        return root;
    }

    // 第一种情况:要删除的节点为叶子节点,此时直接删除即可
    if (current->left == nullptr && current->right == nullptr) { // 条件成立,说明删除的节点为叶子节点
        // 判断要删除的节点是父节点的左子节点还是右子节点
        if (parent->left != nullptr && parent->left->val == num) { // 是左子节点
            parent->left = nullptr;
        }
        else if (parent->right != nullptr && parent->right->val == num) { // 是右子节点
            parent->right = nullptr;
        }
    }

    // 第二种情况:删除有两颗子树的节点
    else if (current->left != nullptr && current->right != nullptr) {
        TreeNode* minRightNode = findMin(current->right); // 找到右子树中的最小节点
        current->val = minRightNode->val; // 用右子树中的最小节点替换要删除的节点
        current->right = BST_deleteItem(current->right, minRightNode->val); // 删除右子树中的最小节点
    }

    // 第三种情况:删除只有一颗子树(左子树或者右子树)的节点
    else if (current->left == nullptr && current->right != nullptr) { // 删除的节点只有右子树
        if (parent != nullptr) {
            if (parent->left->val == num) { // 情况1:是左子节点(删除的节点相对于其父节点是左子节点)
                parent->left = current->right;
            }
            else { // 情况2:是右子节点(删除的节点相对于其父节点是右子节点)
                parent->right = current->right;
            }
        }
        else {
            root = current->right; // 情况3
        }
    }
    else if (current->left != nullptr && current->right == nullptr) { // 删除的节点只有左子树
        if (parent != nullptr) {
            if (parent->left->val == num) { // 情况1:是左子节点
                parent->left = current->left;
            }
            else { // 情况2:是右子节点
                parent->right = current->left;
            }
        }
        else {
            root = current->left; // 情况3
        }
    }

    return root;
}

// 平衡二叉树


int main() {
    
    // 前序创建二叉树
    std::cout << "Enter the elements of the tree in pre-order traversal (0 for null):\n";
    TreeNode* root = createPreOrder();
    // std::cout << root->val; // 输出1【测试代码】
    
     前序遍历二叉树
    //std::cout << "Pre-order traversal of the created tree: ";
    //preOrderTraversal(root);
    //std::cout << std::endl; // 换行

     二叉搜索树中添入新的元素6
    //if (BST_InsertItem(root, 6)) {
    //    std::cout << "二叉搜索树插入元素成功!" << std::endl;
    //}
    //else {
    //    std::cout << "二叉搜索树插入元素失败!" << std::endl;
    //}

     前序遍历二叉树
    //std::cout << "Pre-order traversal of the created tree: ";
    //preOrderTraversal(root);
    //std::cout << std::endl; // 换行

     二叉搜索树查询操作
    //TreeNode * query_T = BST_queryItem(root, 6);
    //std::cout << "查询的节点情况如下:" << std::endl;
    //std::cout << "节点值:" << query_T->val << std::endl;

     二叉搜索树改操作
    //std::cout << "二叉树修改操作如下,将10修改为11:" << std::endl;
    //BST_modifyItem(root, 10, 11);

    std::cout << "删除操作前二叉树的前序遍历:" << std::endl;
    // 前序遍历二叉树
    std::cout << "Pre-order traversal of the created tree: ";
    preOrderTraversal(root);
    std::cout << std::endl; // 换行
    
    // 二叉树的删除操作
    BST_deleteItem(root, 2);

    std::cout << "删除操作后二叉树的前序遍历:" << std::endl;
    // 前序遍历二叉树
    std::cout << "Pre-order traversal of the created tree: ";
    preOrderTraversal(root);
    std::cout << std::endl; // 换行

     中序遍历二叉树
    //std::cout << "In-order traversal of the created tree: ";
    //InOrderTraversal(root);
    //std::cout << std::endl; // 换行
    //
     统计度为0的节点个数 
    //int Node0_n = count_Node_0(root);
    //std::cout << "度为0的节点个数为:" << Node0_n << std::endl;
    //
     统计度为1的节点个数
    //int Node1_n = count_Node_1(root);
    //std::cout << "度为1的节点个数为:" << Node1_n << std::endl;

     统计度为2的节点个数
    //int Node2_n = count_Node_2(root);
    //std::cout << "度为2的节点个数为:" << Node2_n << std::endl;

     统计二叉树的节点个数
    //int Node = count_Node(root);
    //std::cout << "节点个数为:" << Node << std::endl;
    //
     计算二叉树的深度
    //int depth = Depth(root);
    //std::cout << "二叉树的深度为:" << depth << std::endl;

     二叉树的层序遍历(一次性输出)
    //std::cout << "二叉树的层序遍历结果如下:" << std::endl;
    //level_order_tras(root);
    //std::cout << std::endl;

     二叉树的层序打印(每层输出)
    //std::cout << "二叉树的每层输出结果如下:" << std::endl;
    //level_print(root);
    //std::cout << std::endl; // 换行

     判断二叉树是否为满二叉树
    //Full_binary_tree(root);

    判断二叉树是否为完全二叉树
    //if (Complete_binary_tree(root)) {
    //    std::cout << "这颗二叉树是一颗完全二叉树!" << std::endl;
    //}
    //else {
    //    std::cout << "这颗二叉树不是一颗完全二叉树!" << std::endl;
    //}

    // 释放内存,防止内存泄漏
    delete root;

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1653960.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

类和对象(中篇)(未完结)

文章目录 类的6个默认成员函数构造函数析构函数 类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 class Date {};空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默…

《QT实用小工具·六十一》带动画的三角形指示箭头

1、概述 源码放在文章末尾 该项目实现了一个带动画效果的三角形指示箭头&#xff0c;项目demo演示如下所示&#xff1a; 用法 interestingindicate.h interestingindicate.cpp 放到工程中&#xff0c;直接使用即可。 注意&#xff1a;建议绝对布局&#xff0c;手动指定 wid…

分红76.39亿,分红率再创新高,成长活力无限的伊利带来丰厚回报

伊利47万股东&#xff0c;又等来了一个好消息。 4月29日&#xff0c;伊利股份发布2023年报&#xff0c;实现营业总收入1261.79亿元&#xff0c;归母净利润104.29亿元&#xff0c;双创历史新高&#xff0c;实现连续31年稳健增长。 在递交亮眼成绩单的同时&#xff0c;乳业巨头伊…

Linux系统编程--网络编程

一、OSI网络七层模型 OSI模型将整个网络通信过程分解为七个层次&#xff0c;每个层次都为网络通信提供了特定的功能。以下是OSI模型的七个层次&#xff0c;从上到下依次是&#xff1a; 应用层&#xff08;Application Layer&#xff09;&#xff1a;为应用软件提供网络服务&am…

MySQL部署系列-centos离线安装MySQL

MySQL部署系列-centos离线安装MySQL 文章目录 MySQL部署系列-centos离线安装MySQL1. 查看是否已经安装 Mysql3. 下载官方 Mysql 包3. 下载之后上传到服务器4. 创建用户组5. 创建数据目录并赋予权限6. 修改配置文件 vim /etc/my.cnf7. 初始化数据库(数据库安装)8. 加入到系统服务…

多个开源的js补环境框架测试

原文链接&#xff1a;https://mp.weixin.qq.com/s/uEMFGpE5bqmTvzSgX2twvA 前言 在做js逆向时肯定会遇到补环境的情况&#xff0c;看到github开源了好几个补环境用的框架&#xff0c;这篇文章做个测试&#xff0c;看看哪个比较好用。 https://github.com/pysunday/sdenvhttp…

word格式技巧

文章目录 论文格式技巧论文交叉引用怎么弄论文的页码怎么弄 论文格式技巧 论文交叉引用怎么弄 1.取消文献原有的编号 2.定义新编号 3.具体编号设置 4.在引用的地方插入&#xff0c;具体引用选项卡–>交叉引用–>选择后插入 2. 4. 论文的页码怎么弄 假设我们有这样一…

探索DeepSeek平台:新一代MoE模型的深度体验

简介 DeepSeek是一个创新的人工智能平台&#xff0c;它最近推出了其最新版本的模型——DeepSeek-V2 MoE&#xff08;Mixture of Experts&#xff09;。这个平台不仅提供了一个交互式的聊天界面&#xff0c;还提供了API接口&#xff0c;让用户可以更深入地体验和利用这一先进的…

scala速通(精简版)

1.变量和常量 var name [:VariableType] value // variable val name [:ConstantType] value // constant1.声明变量时&#xff0c;类型可以省略 2.类型定义后就不能修改言 3.变量声明必须有初始值 4.变量&#xff0c;常量分别用var&#xff0c;val声明修饰 2.标识符命名…

构建自己的docker镜像node.js

学习资源&#xff1a; 构建自己的 Docker 镜像_哔哩哔哩_bilibili 针对其中的一些比较困难的点写篇文章。 以下是对app.js的注释&#xff1a; // 使用 Koa 框架搭建 Node.js 应用的示例代码// 这两行代码引入了 koa 模块&#xff0c;并创建了一个新的 Koa 应用实例&#xf…

vue2项目升级到vue3经历分享4

后端重构&#xff0c;如果接口做好抽象封装&#xff0c;只需要考虑jar之间的兼容性问题&#xff0c;jdk版本不变&#xff0c;基本不用做太大的调整&#xff0c;但是前端就不一样&#xff0c;除了vue框架本身&#xff0c;css的调整&#xff0c;改起来更是让人头疼。前面写了vue2…

如何让vim支持python3

首先删除旧的vim。 sudo apt-get remove vim //输入re按下tab直接显示remove sudo apt-get remove vim-runtime sudo apt-get remove vim -tiny sudo apt-get remove vim-common 然后下载vim8源码&#xff1a; git clone https://github.com/vim/vim.git 进行编译安装…

一键剪辑1000条视频的矩阵系统小魔推到底有多牛?

小魔推是一款短视频营销工具&#xff0c;主要针对想做短视频营销的实体商家与企业。通过BGC、PGC、UGC流量的打造&#xff0c;帮助更多实体行业实现流量裂变与转化。通过小魔推不需要做额外的拍摄剪辑创作动作&#xff0c;只需要通过小魔推宣传码&#xff0c;就能一键发布带有门…

20240508请问GTX2080TI的300和300A核心的差异?

20240508请问GTX2080TI的300和300A核心的差异&#xff1f; 在拼多多/淘宝上&#xff0c;GTX2080TI的300A核心的会比300核心的贵100&#xffe5;左右。 但是怎么区分呢&#xff1f; 300a核心和300请问怎么区分呢&#xff1f;[嘻嘻] devicr ID diviceid 1e07是300a 1e04是300 Gp…

2024 GESP6级 编程第一题 游戏

题目描述 你有四个正整数 &#xff0c;并准备用它们玩一个简单的小游戏。 在一轮游戏操作中&#xff0c;你可以选择将 减去 &#xff0c;或是将 减去 。游戏将会进行多轮操作&#xff0c;直到当 时游戏结束。 你想知道游戏结束时有多少种不同的游戏操作序列。两种游戏操作…

docker-compose部署gitlab

需要提前安装docker和docker-compose环境 参考&#xff1a;部署docker-ce_安装部署docker-ce-CSDN博客 参考&#xff1a;docker-compose部署_docker compose部署本地tar-CSDN博客 创建gitlab的数据存放目录 mkdir /opt/gitlab && cd mkdir /opt/gitlab mkdir {conf…

Python深度学习基于Tensorflow(6)神经网络基础

文章目录 使用Tensorflow解决XOR问题激活函数正向传播和反向传播解决过拟合权重正则化Dropout正则化批量正则化 BatchNormal权重初始化残差连接 选择优化算法传统梯度更新算法动量算法NAG算法AdaGrad算法RMSProp算法Adam算法如何选择优化算法 使用tf.keras构建神经网络使用Sequ…

【C++】二叉搜索树(手撕插入、删除、寻找)

一、什么是二叉搜索树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左…

【Linux】25. 网络基础(一)

网络基础(一) 计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 其实本质上一台计算机内部也是一个小型网络结构(如果我们将计算机内部某个硬件不存放在电脑中&#xff0c;而是拉根长长的线进行连接。这其实也就是网…

【Arduino IDE 2】Windows平台安装ESP8266 NodeMCU LittleFS Uploader(文件上传插件)

在Arduino IDE 2&#xff08;2.2.1或更高版本&#xff09;上&#xff0c;如何安装基于ESP8266 NodeMCU的LittleFS文件系统上传插件&#xff0c;以及如何将文件上传到ESP8266 NodeMCU板文件系统。 一、LittleFS简介 LittleFS是一个为微控制器创建的轻量级文件系统&#xff0c;可…