C、C++常用数据结构:树

定义与性质

  1. 树是指由 n(n≥0)个结点组成的有穷集合 D 与 D 上的关系的集合 R构成的结构,通常我们用 T 表示。
  2. 树需要满足以下三个条件:
    1. 当n=0时,该结点集合为空,该树被称为空树
    2. 在任意的非空树中,有且仅有一个根结点root
    3. 当 n>1 时 ,除根结点以外的其余结点可以分为 m(m>0)个不相交的子集D1,D2,D3,...,Dm, 其中每一个这样的子集 Di(i≤m)本身又是一棵树, 称为根结点 root的子树
  3. 树的几个重要术语:
    1. 结点的度:结点拥有的直接子树数目。
    2. 数的度:书中各结点度的最大值。
    3. 分支结点:也是非叶子结点,度不为0的结点。
    4. 叶子结点:也叫做终端结点,度为0的结点。
    5. 树的深度:树中结点的最大层次数。
    6. 森林:n(n≥0)棵不相交的树的集合称为森林。
  4. 常用性质:(针对二叉树)
    1. 具有n个结点的非空二叉树有且仅有n-1个分支。
    2. 非空二叉树第i层最多有 2 i − 1 2^{i-1} 2i−1个结点。
    3. 深度为k的二叉树最多有 2 k − 1 2^k-1 2k−1个结点。
  5. 存储方式:
    1. 顺序存储:顺序存储将二叉树的每一个节点和数组的编号一一对应,根据这个编号,可以找到该结点的父结点和孩子结点。
    2. 链式存储:二叉树的节点一般定义为:数据部分、左子树指针和右子树指针,用指针将节点串起来。
  6. 两种存储方式的优缺点对比:
    1. 顺序存储结构:
      1. 优点:访问速度快 ,可以通过下标索引直接访问目标元素,访问时间复杂度为O(1)节省内存空间(适用于完全二叉树),对于完全二叉树,顺序存储可以非常高效且节省内存空间,树中每个结点在内存中都可以紧密排布
      2. 缺点:不适合非完全二叉树 ,非完全二叉树进行顺序存储可能会造成大量的空间浪费,因为数组中可能有大量的空位来表示不存在的节点。难以动态扩容 ,树的顺序存储需要固定大小的数组。插入和删除操作不方便 ,效率较低。如果树结点比较多,可能内存空间有限找不到一整片连续的内存来顺序存储树的结点。
    2. 链式存储结构:
      1. 优点:适合非完全二叉树,插入和删除操作方便,动态扩容方便。
      2. 缺点:访问速度较慢,空间开销大,因为链式存储还需要额外存储指针数据
  7. 完全二叉树:一种特殊的二叉树
    1. 除了最后一层外,其他每一层都要被节点完全填满。
    2. 最后一层的结点都尽可能的靠左排列。
    3. 完全二叉树适合用顺序存储结构来存储。

代码实现

以下代码实现都是基于二叉树的。

二叉树结点类

这里基于链式存储。

cpp 复制代码
/**
 * 二叉树结点类
 */
class BinaryTreeNode
{
private:
    int *data;

public:
    BinaryTreeNode *lchild;
    BinaryTreeNode *rchild;

    BinaryTreeNode()
    {
        data = NULL;
        lchild = NULL;
        rchild = NULL;
    }
    BinaryTreeNode(int n)
    {
        data = new int;
        *data = n;
        lchild = NULL;
        rchild = NULL;
    }
    int getData()
    {
        return *data;
    }
};

创建二叉树:

cpp 复制代码
// 递归创建二叉树(层序)
BinaryTreeNode *createBinaryTree(vector<int> &nums, int index, int size)
{
    if (index >= size)
    {
        return NULL;
    }

    BinaryTreeNode *node = new BinaryTreeNode(nums[index]);

    node->lchild = createBinaryTree(nums, 2 * index + 1, size);
    node->rchild = createBinaryTree(nums, 2 * index + 2, size);

    return node;
}

四种遍历方法(前序、中序、后序、层序)

这里的前序、中序、后序遍历都是基于递归实现的,当然也有非递归的方法,可以参考:二叉树的前中后和层序遍历详细图解(递归和非递归写法)_二叉树前序列为abcdefg的图-CSDN博客

cpp 复制代码
/**
 * 前序遍历
 */
void preOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    cout << root->getData() << " ";
    preOrder(root->lchild);
    preOrder(root->rchild);
}

/**
 * 中序遍历
 */
void inOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    inOrder(root->lchild);
    cout << root->getData() << " ";
    inOrder(root->rchild);
}

/**
 * 后序遍历
 */
void postOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    postOrder(root->lchild);
    postOrder(root->rchild);
    cout << root->getData() << " ";
}

/**
 * 层序遍历
 */
void levelOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    // 层序遍历借助队列实现
    queue<BinaryTreeNode *> q;
    BinaryTreeNode *front;
    q.push(root);
    while (!q.empty())
    {
        front = q.front();
        q.pop();
        if (front->lchild)
        {
            q.push(front->lchild);
        }
        if (front->rchild)
        {
            q.push(front->rchild);
        }
        cout << front->getData() << " ";
    }
}

测试用例

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

/**
 * 二叉树结点类
 */
class BinaryTreeNode
{
private:
    int *data;

public:
    BinaryTreeNode *lchild;
    BinaryTreeNode *rchild;

    BinaryTreeNode()
    {
        data = NULL;
        lchild = NULL;
        rchild = NULL;
    }
    BinaryTreeNode(int n)
    {
        data = new int;
        *data = n;
        lchild = NULL;
        rchild = NULL;
    }
    int getData()
    {
        return *data;
    }
};

// 递归创建二叉树(层序)
BinaryTreeNode *createBinaryTree(vector<int> &nums, int index, int size)
{
    if (index >= size)
    {
        return NULL;
    }

    BinaryTreeNode *node = new BinaryTreeNode(nums[index]);

    node->lchild = createBinaryTree(nums, 2 * index + 1, size);
    node->rchild = createBinaryTree(nums, 2 * index + 2, size);

    return node;
}

/**
 * 前序遍历
 */
void preOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    cout << root->getData() << " ";
    preOrder(root->lchild);
    preOrder(root->rchild);
}

/**
 * 中序遍历
 */
void inOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    inOrder(root->lchild);
    cout << root->getData() << " ";
    inOrder(root->rchild);
}

/**
 * 后序遍历
 */
void postOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    postOrder(root->lchild);
    postOrder(root->rchild);
    cout << root->getData() << " ";
}

/**
 * 层序遍历
 */
void levelOrder(BinaryTreeNode *root)
{
    if (root == NULL)
    {
        return;
    }
    // 层序遍历借助队列实现
    queue<BinaryTreeNode *> q;
    BinaryTreeNode *front;
    q.push(root);
    while (!q.empty())
    {
        front = q.front();
        q.pop();
        if (front->lchild)
        {
            q.push(front->lchild);
        }
        if (front->rchild)
        {
            q.push(front->rchild);
        }
        cout << front->getData() << " ";
    }
}

int main(int argc, char const *argv[])
{
    vector<int> nums = {1, 2, 3, 4, 5, 6, 7}; // 完全二叉树的层次遍历序列
    // 使用数组递归创建二叉树
    BinaryTreeNode *root = createBinaryTree(nums, 0, nums.size());

    cout << "前序遍历: ";
    preOrder(root); // 前序遍历
    cout << endl;
    cout << "中序遍历: ";
    inOrder(root); // 中序遍历
    cout << endl;
    cout << "后序遍历: ";
    postOrder(root); // 后序遍历
    cout << endl;
    cout << "层序遍历: ";
    levelOrder(root); // 层序遍历
    cout << endl;
    return 0;
}
相关推荐
??tobenewyorker12 分钟前
力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树
数据结构·c++·算法·leetcode
蓝澈112120 分钟前
迪杰斯特拉算法之解决单源最短路径问题
java·数据结构
oioihoii1 小时前
C++11 forward_list 从基础到精通:原理、实践与性能优化
c++·性能优化·list
m0_687399841 小时前
写一个Ununtu C++ 程序,调用ffmpeg API, 来判断一个数字电影的视频文件mxf 是不是Jpeg2000?
开发语言·c++·ffmpeg
Natsume17101 小时前
嵌入式开发:GPIO、UART、SPI、I2C 驱动开发详解与实战案例
c语言·驱动开发·stm32·嵌入式硬件·mcu·架构·github
shaun20012 小时前
华为c编程规范
c语言
MeshddY2 小时前
(超详细)数据库项目初体验:使用C语言连接数据库完成短地址服务(本地运行版)
c语言·数据库·单片机
森焱森2 小时前
无人机三轴稳定化控制(1)____飞机的稳定控制逻辑
c语言·单片机·算法·无人机
呆瑜nuage3 小时前
数据结构——堆
数据结构
Ronin3053 小时前
【C++】类型转换
开发语言·c++