数据结构不懂二叉树,就来看这里吧

217 阅读6分钟

前言

二叉树(Binary Tree)相信大家不陌生吧,不管在面试还是平时开发中,都会经常用到,其定义为每个节点最多两个子节点的有序树。本文将对二叉树进行全面而深入的讲解,涵盖其基本概念、存储结构、遍历方法以及相关操作的实现细节,帮助大家更好地理解和应用这一数据结构。

image.png

一、二叉树的基本概念

首先先简单介绍一下二叉树的一些基本概念,主要与下面5点

  1. 节点:构成二叉树的基本单元,包含数据域和两个指向子节点的指针(通常称为左孩子指针和右孩子指针)。
  2. 根节点:二叉树的起始节点,没有父节点,位于树的最顶层。
  3. 叶子节点:没有子节点的节点,位于树的末端,通常用于表示数据的最终状态。
  4. :节点所拥有的子树数量。在二叉树中,节点的度数只能是0(叶子节点)、1(只有一个子节点)或2(有两个子节点)。
  5. 深度与高度:节点的深度是从根节点到该节点的路径长度;树的高度是从根节点到最远叶子节点的最长路径长度。

二、二叉树的存储结构

接下来是二叉树的存储结构主要有两种:链式存储和顺序存储。

链式存储

链式存储通过指针将各个节点连接起来,每个节点包含数据域和两个指针域(分别指向左孩子和右孩子)。这种存储方式灵活且易于插入和删除操作,但需要额外的内存空间来存储指针。

顺序存储

顺序存储利用数组下标来表示节点之间的关系。对于完全二叉树,可以通过数组下标快速计算出父子节点的位置。顺序存储节省内存空间,但插入和删除操作相对复杂。

本文主要探讨链式存储结构,后面用具体代码案例进行演示实现。

三、二叉树的遍历

另外一个重要的知识点就是,二叉树的遍历,遍历是指访问二叉树的所有节点的过程。常见的遍历方法有前序遍历、中序遍历和后序遍历。

  1. 前序遍历:先访问根节点,然后遍历左子树,最后遍历右子树。
  2. 中序遍历:先遍历左子树,然后访问根节点,最后遍历右子树。
  3. 后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。

四、二叉树的操作实现

上述介绍了二叉树的基本概念,接下来进入实操部分,以下是基于链式存储结构的二叉树操作实现,包括创建二叉树、遍历二叉树、求深度、统计节点个数和查找节点等。

1. 创建二叉树

首先通过先序序列创建二叉树的链式存储结构。先序序列中,空节点用#表示,具体代码如下:

void CreateBiTree(BiTree &T) {
    TElemType ch;
    cin >> ch;
    if (ch == '#') {
        T = NULL;
    } else {
        T = new BiTNode;
        T->data = ch;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);
    }
}

2. 遍历二叉树

前序遍历

用递归算法实现前序遍历二叉树,输出遍历序列,代码如下:

void PreOrderTraverse(BiTree T) {
    if (T != NULL) {
        cout << T->data << " ";
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}
中序遍历

用递归算法实现中序遍历二叉树,输出遍历序列:

void InOrderTraverse(BiTree T) {
    if (T != NULL) {
        InOrderTraverse(T->lchild);
        cout << T->data << " ";
        InOrderTraverse(T->rchild);
    }
}
后序遍历

用递归算法实现后序遍历二叉树,输出遍历序万

void PostOrderTraverse(BiTree T) {
    if (T != NULL) {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        cout << T->data << " ";
    }
}

3. 非递归中序遍历

接下来使用栈实现非递归的中序遍历。

void InOrderTraverseNon(BiTree T) {
    stack<BiTree> S;
    BiTree p = T;
    while (p != NULL || !S.empty()) {
        while (p != NULL) {
            S.push(p);
            p = p->lchild;
        }
        if (!S.empty()) {
            p = S.top();
            S.pop();
            cout << p->data << " ";
            p = p->rchild;
        }
    }
}

4. 求二叉树深度

另一个重要的查询方法,查询二叉树深度,返回深度值

int Depth(BiTree T) {
    if (T == NULL) return 0;
    int leftDepth = Depth(T->lchild);
    int rightDepth = Depth(T->rchild);
    return max(leftDepth, rightDepth) + 1;
}

5. 统计二叉树节点个数

常见功能还有统计二叉树结点个数,返回二叉树结点个数

int Count(BiTree T) {
    if (T == NULL) return 0;
    return Count(T->lchild) + Count(T->rchild) + 1;
}

6. 查找节点

查找二叉树结点,在根指针为T的二叉树中查找值为x的结点,查找成功,p赋值为该结点指针,返回true;查找失败,p--NULL,返回false

bool Search(BiTree T, TElemType x, BiTree &p) {
    if (T == NULL) return false;
    if (T->data == x) {
        p = T;
        return true;
    }
    if (Search(T->lchild, x, p) || Search(T->rchild, x, p)) {
        return true;
    }
    return false;
}

五、运行结果示例

通过上述代码,可以实现二叉树的创建、遍历、求深度、统计节点个数和查找节点等功能,增加main函数,并且通过命令窗口相关命令完成上述相关二叉树功能操作,完整代码如下:

int main(void) {

    BiTree T = NULL;

    int c = 0;

    int d = 0;

    int num = 0;

    TElemType elem;

    BiTree p = NULL;

    while (c != 9) {

        cout << endl << "1. 建立二叉树的二叉链表";

        cout << endl << "2. 前序遍历二叉树";

        cout << endl << "3. 中序遍历二叉树";

        cout << endl << "4. 后序遍历二叉树";

        cout << endl << "5. 非递归中序遍历二叉树";

        cout << endl << "6. 求二叉树深度";

        cout << endl << "7. 求二叉树结点个数";

        cout << endl << "8. 查找结点";

        cout << endl << "9. 退出";

        cout << endl << "选择功能(1~9):";

        cin >> c;

        switch (c) {

            case 1:

                CreateBiTree(T);

                break;

            case 2:

                PreOrderTraverse(T);

                cout << endl;

                break;

            case 3:

                InOrderTraverse(T);

                cout << endl;

                break;

            case 4:

                PostOrderTraverse(T);

                cout << endl;

                break;

            case 5:

                InOrderTraverseNon(T);

                cout << endl;

                break;

            case 6:

                d = Depth(T);

                cout << "二叉树深度为:"<< d << endl;

                break;

            case 7:

                num = Count(T);

                cout << "二叉树结点个数为:" << num << endl;

                break;

            case 8:

                cout << "请输入要查找的结点值:";

                cin >> elem;

                if (Search(T, elem, p))

                    cout << "结点查找成功!结点左孩子为:" << p->lchild << " 结点右孩子为:" << p->rchild << endl;

                else

                    cout << "查找失败!" << endl;

                break;

            case 9:

                cout << "结束操作" << endl;

                break;

        }

    }

    return 0;

}

运行结果,如图所示:

image.png

总结

本文全面且深入地剖析了二叉树,涵盖其基本概念,如节点、根节点、叶子节点和度的定义,存储结构,重点探讨了链式存储,遍历方法,包括前序、中序和后序遍历的详细步骤及代码实现;还介绍了操作实现,如创建、深度计算、节点统计和节点查找。此外,结合实际应用案例,展示了二叉树在数据库索引和编译原理等领域的重要作用,欢迎大家在评论区指导讨论。