首页 > 编程语言 >二叉树入门学习 优势对比 以及 完全二叉树c++代码的实现

二叉树入门学习 优势对比 以及 完全二叉树c++代码的实现

时间:2024-08-21 16:51:17浏览次数:10  
标签:std 入门 tree c++ Traversal 二叉树 节点 cout

二叉树介绍文档

一、概述

二叉树是一种常见的数据结构,它是一种树形结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树的基本概念如下:

  • 节点(Node):二叉树的基本单元,包含一个值以及指向左右子节点的引用。
  • 根节点(Root):树的顶端节点,没有父节点。
  • 叶子节点(Leaf):没有子节点的节点。
  • 子节点(Children):一个节点的直接下一级节点,包括左子节点和右子节点。
  • 父节点(Parent):一个节点的直接上一级节点。
  • 子树(Subtree):以某个节点为根节点的子树结构。

二、二叉树的种类

  1. 完全二叉树(Complete Binary Tree)

    • 除了最后一层外,所有层都被完全填满。
    • 最后一层的节点尽可能靠左。
  2. 满二叉树(Full Binary Tree)

    • 每个节点要么是叶子节点,要么有两个子节点。
  3. 平衡二叉树(Balanced Binary Tree)

    • 各子树的高度差不超过一定的值,如AVL树和红黑树。
  4. 二叉搜索树(Binary Search Tree, BST)

    • 左子树的所有节点的值小于根节点的值。
    • 右子树的所有节点的值大于根节点的值。
    • 查找、插入和删除操作在平均情况下具有较高的效率。
  5. 二叉堆(Binary Heap)

    • 一种特殊的完全二叉树,常用于实现优先队列。
    • 最大堆中的每个节点都大于等于其子节点,最小堆则相反。

三、二叉树的基本操作

  • 插入(Insertion):在树中添加一个新节点。

  • 删除(Deletion):从树中删除一个节点。

  • 查找(Search):查找具有特定值的节点。

  • 遍历(Traversal):访问树中所有节点的过程。

    遍历方式包括:

    • 前序遍历(Pre-order Traversal):根节点 → 左子树 → 右子树
    • 中序遍历(In-order Traversal):左子树 → 根节点 → 右子树
    • 后序遍历(Post-order Traversal):左子树 → 右子树 → 根节点
    • 层序遍历(Level-order Traversal):按层次从上到下访问节点

四、完全二叉树的实现

1. 完全二叉树概述

完全二叉树是二叉树的一种特殊类型,它除了最后一层外,所有层都被完全填满,且最后一层的节点尽可能靠左。完全二叉树常用于实现堆等数据结构。

2. 完全二叉树的基本功能实现

以下是完全二叉树的基本功能实现,包括插入、删除、查找和遍历操作。我们使用 Python 语言来实现这些功能。

#include <iostream>
#include <vector>
#include <queue>

class CompleteBinaryTree {
public:
    CompleteBinaryTree() : tree() {}

    // 插入一个值到完全二叉树中
    void insert(int value) {
        tree.push_back(value);
    }

    // 查找一个值是否存在于完全二叉树中
    bool search(int value) {
        for (int i : tree) {
            if (i == value) return true;
        }
        return false;
    }

    // 删除一个值
    void remove(int value) {
        auto it = std::find(tree.begin(), tree.end(), value);
        if (it != tree.end()) {
            std::swap(*it, tree.back());
            tree.pop_back();
        }
    }

    // 前序遍历
    void preOrderTraversal() {
        preOrderTraversal(0);
        std::cout << std::endl;
    }

    // 中序遍历
    void inOrderTraversal() {
        inOrderTraversal(0);
        std::cout << std::endl;
    }

    // 后序遍历
    void postOrderTraversal() {
        postOrderTraversal(0);
        std::cout << std::endl;
    }

    // 层序遍历
    void levelOrderTraversal() {
        if (tree.empty()) return;
        std::queue<int> q;
        q.push(0);
        while (!q.empty()) {
            int index = q.front();
            q.pop();
            std::cout << tree[index] << " ";
            int leftChild = 2 * index + 1;
            int rightChild = 2 * index + 2;
            if (leftChild < tree.size()) q.push(leftChild);
            if (rightChild < tree.size()) q.push(rightChild);
        }
        std::cout << std::endl;
    }

private:
    std::vector<int> tree;

    void preOrderTraversal(int index) {
        if (index >= tree.size()) return;
        std::cout << tree[index] << " ";
        preOrderTraversal(2 * index + 1);
        preOrderTraversal(2 * index + 2);
    }

    void inOrderTraversal(int index) {
        if (index >= tree.size()) return;
        inOrderTraversal(2 * index + 1);
        std::cout << tree[index] << " ";
        inOrderTraversal(2 * index + 2);
    }

    void postOrderTraversal(int index) {
        if (index >= tree.size()) return;
        postOrderTraversal(2 * index + 1);
        postOrderTraversal(2 * index + 2);
        std::cout << tree[index] << " ";
    }
};

int main() {
    CompleteBinaryTree tree;

    // 插入值
    tree.insert(10);
    tree.insert(20);
    tree.insert(30);
    tree.insert(40);
    tree.insert(50);

    std::cout << "Level Order Traversal: ";
    tree.levelOrderTraversal();

    std::cout << "Pre Order Traversal: ";
    tree.preOrderTraversal();

    std::cout << "In Order Traversal: ";
    tree.inOrderTraversal();

    std::cout << "Post Order Traversal: ";
    tree.postOrderTraversal();

    // 查找
    std::cout << "Search 30: " << (tree.search(30) ? "Found" : "Not Found") << std::endl;

    // 删除
    tree.remove(30);
    std::cout << "After removing 30:" << std::endl;

    std::cout << "Level Order Traversal: ";
    tree.levelOrderTraversal();

    return 0;
}

使用步骤

  1. 编写代码:将上面的代码保存为 CompleteBinaryTree.cpp 文件。
  2. 编译代码
    g++ -o CompleteBinaryTree CompleteBinaryTree.cpp
    
  3. 运行程序
    ./CompleteBinaryTree
    

测试结果

程序的输出结果应如下所示:

Level Order Traversal: 10 20 30 40 50 
Pre Order Traversal: 10 20 40 50 30 
In Order Traversal: 40 20 50 10 30 
Post Order Traversal: 40 50 20 30 10 
Search 30: Found
After removing 30:
Level Order Traversal: 10 20 50 40 

五、完全二叉树与其他数据结构的对比

  1. 与链表对比

    • 完全二叉树:支持高效的查找、插入和删除操作(尤其在实现堆时),其时间复杂度通常为 O(log n)。
    • 链表:插入和删除操作比较灵活,但查找操作时间复杂度为 O(n),不适合频繁的查找操作。
  2. 与数组对比

    • 完全二叉树:适合动态数据集,支持高效的动态插入和删除操作。
    • 数组:对静态数据集高效,支持快速的随机访问,但插入和删除操作复杂度较高。
  3. 与哈希表对比

    • 完全二叉树:提供有序的数据存储和高效的范围查询。
    • 哈希表:提供常数时间的查找和插入操作,但不支持范围查询和排序操作。
  4. 与 AVL 树和红黑树对比

    • 完全二叉树:结构较为简单,不一定平衡,可能导致操作性能不稳定。
    • AVL 树和红黑树:自平衡二叉搜索树,操作性能稳定且复杂度较低,适用于需要保证高效操作的场景。

六、总结

完全二叉树是一种结构简单但功能强大的数据结构,广泛应用于堆的实现等领域。它的结构特点使其在动态数据操作中表现出色,但在特定场景下,其他数据结构如哈希表、AVL 树等可能会提供更优化的性能。了解各种数据结构的优缺点,可以帮助在实际应用中选择最合适的方案。

标签:std,入门,tree,c++,Traversal,二叉树,节点,cout
From: https://blog.csdn.net/weixin_44251074/article/details/141392654

相关文章

  • CAN学习笔记(一)CAN入门
    CAN学习笔记(一)CAN入门参考链接:https://blog.csdn.net/2301_77952570/article/details/131114941CAN收发器的作用发:将TTL电平转换为CAN专用电压的差分信号收:将CAN的差分信号转换为TTL电平高低电平的定义CAN_High-CAN_Low<0.5V时候为隐性的,逻辑信号表现为"逻辑1",即高......
  • 【C语言入门】如何使用动态内存分配来模拟“大小未知”的数组
    如何使用动态内存分配来模拟“大小未知”的数组引子举例应用结语引子在C语言中,定义一个“大小未知”的数组直接是不可行的,因为数组在声明时必须有确定的大小,要么是在编译时确定的常量表达式,要么是在C99或更高标准下,允许运行时确定大小的变长数组(VLA)。变长数组(Varia......
  • 头歌 第4关:层次遍历二叉树
    任务描述本关任务:给定一棵二叉树,借助队列实现层次遍历二叉树。相关知识为了完成本关任务,你需要掌握:1.队列的类型定义及基本操作,2.二叉树层次遍历。队列的类型定义及基本操作队列的类型定义:#define MAXSIZE100  //最大长度typedefBiTNode*QElemType;//队列中......
  • Docker快速入门 01 安装、部署环境
    1.简介和安装1.1简介Docker是一个应用打包、分发、部署的工具。打包:需要的环境变成一个“安装包”。分发:将“安装包”上传到云端,供他人获取。部署:将“安装包”下载下来后直接快速搭建运行环境。通俗讲就是轻量级的虚拟机,只虚拟需要的运行环境。1.2安装这里以Docker......
  • Docker快速入门 02 构建镜像
    本文以PythonWeb(Flask)小项目构建Docker镜像1.准备项目确保PythonWeb项目已准备好项目目录结构my-python-app/│├──app.py├──requirements.txt└──Dockerfileapp.py:Flask应用的主文件。fromflaskimportFlaskapp=Flask(__name__)@app.ro......
  • 【卡码网C++基础课 3.A+B问题3】
    目录题目描述与分析一、if语句二、关系运算符三、逻辑运算符四、break退出循环五、延伸题目描述与分析题目描述:你的任务依然是计算a+b。输入描述:输入中每行是一对a和b。其中会有一对是0和0标志着输入结束,且这一对不要计算。输出描述:对于输入的每对a和b,你需要在......
  • 从零开始学习C++(1-1)
    本篇帖子学习C++输入输出。C++目前最常用的两种输入输出方法,cin/cout和scanf/printf。cin/cout这是C++入门必学且最最最基础的输入输出方式,在<iostream>头文件,std命名空间下。基本格式如下:cin>>x;cout<<x<<"\n";//"\n"为换行符注:很多教材会教你换行输出......
  • VUEX基础入门Store使用详解
    【1】vuex是什么github站点:https://github.com/vuejs/vuex,在线文档:https://vuex.vuejs.org/zh-cn/Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。每一个Vuex应用的......
  • 【源码解析】C/C++开源代码解析引擎
    1. 背景说明针对Simulink或其他MBD环境的模型生成代码,及其他的外部C/C++代码工程,做相应的后端代码优化处理工作,例如如下场景,统计代码内的全局变量声明及其内存占用情况;提取代码内的逻辑判断条件结合Z3Prover定理证明器进行形式化验证;...因此需要对C/C++代码进行语法......
  • C++ 函数指针
    C++中函数指针表示指向函数的指针,其作用相当于函数的别名,通过函数指针可以直接调用对应的函数。函数指针有两种表示方式,一种通过typedef进行声明,一种通过新的方式using来进行声明。函数指针所指向的函数,其对应的形参个数、类型与返回值,都应该相同。//FuncPtr1为函数指针,表示一......