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;
}
相关推荐
小学生的信奥之路7 分钟前
力扣1116题:用C++实现多线程交替输出零、偶数、奇数
c++·leetcode·多线程
老狼主44 分钟前
MFC CChartCtrl编程
c++·mfc
玄月初二丶1 小时前
28. 找出字符串中第一个匹配项的下标
c语言·开发语言·数据结构·算法
小猪扒饭1 小时前
C基础 12_day
c语言·笔记·学习·算法
新青年.1 小时前
cpp实现音频重采样8k->16k及16k->8k
c++
金山几座2 小时前
C++面试5题--6day
c++·面试
筏.k2 小时前
知识随记-----使用现代C++客户端库redis-plus-plus实现redis池缓解高并发
c++·经验分享·redis·microsoft
小指纹3 小时前
图论-最短路 Bellman-Ford算法
c++·算法·objective-c·图论
屁股割了还要学3 小时前
【数据结构入门】时间、空间复杂度的计算
c语言·开发语言·数据结构·c++·算法
一杯科技拿铁4 小时前
go‑cdc‑chunkers:用 CDC 实现智能分块 & 强力去重
c++·mfc