当前位置:首页 > C++目录 > 正文内容

树的存储与遍历—链式存储

亿万年的星光5个月前 (10-18)C++目录517

一、定义

链式存储是表示树结构最直观、最常用的一种方法。它的核心思想是:

用链表中的节点来表示树中的每个元素。每个节点不仅包含数据本身,还包含指向其子节点的指针。


二、基本结构

对于一个普通的树(不一定是二叉树),一个典型的链式存储节点结构如下:

// C语言示例
typedef struct TreeNode {
    int data;                   // 节点中存储的数据
    struct TreeNode *firstChild; // 指向第一个孩子节点的指针
    struct TreeNode *nextSibling; // 指向下一个兄弟节点的指针
} Node;

这种结构通常被称为 “孩子-兄弟表示法”“左孩子右兄弟表示法”


三、基本原理


假设我们有这样一棵树:

        A
      / | \
     B  C  D
    / \    |
   E   F   G


用“孩子-兄弟表示法”的链式存储后,它在内存中的逻辑结构会变成一棵二叉树的样子:


      A
     /
    B ——— C ——— D
   /                 /
  E ——— F        G


解释:

  • firstChild 指针(纵向):指向该节点的第一个子节点

    • 节点 A 的 firstChild 指向 B。

    • 节点 B 的 firstChild 指向 E。

    • 节点 D 的 firstChild 指向 G。

  • nextSibling 指针(横向):指向该节点的下一个兄弟节点

    • 节点 B 的 nextSibling 指向 C。

    • 节点 C 的 nextSibling 指向 D。

    • 节点 E 的 nextSibling 指向 F


四、对于二叉树的链式存储


二叉树是一种特殊的树,每个节点最多有两个子节点(左孩子和右孩子)。它的链式存储结构更为简单:

// 二叉树的链式存储节点
typedef struct BiTNode {
    int data;                // 数据域
    struct BiTNode *lchild;  // 指向左子节点的指针
    struct BiTNode *rchild;  // 指向右子节点的指针
} BiTNode;

对于二叉树:

      A
     / \
    B   C
   / \   \
  D   E   F

其链式存储的逻辑关系非常直观:

  • A 的 lchild 指向 B,rchild 指向 C。

  • B 的 lchild 指向 D,rchild 指向 E。

  • C 的 lchild 为空,rchild 指向 F



二叉树的存储和遍历


(1)使用递归构建方式

#include <iostream>
#include <vector>
using namespace std;

// 二叉树节点(链式存储)
struct TreeNode {
    int data;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};

// 核心:递归构建二叉树(根据层序遍历数组)
// 参数:nums-层序数组(-1表示空节点),index-当前节点在数组中的索引
TreeNode* buildTreeRecursive(const vector<int>& nums, int index) {
    // 递归终止条件:索引越界 或 该位置为空节点(-1)
    if (index >= nums.size() || nums[index] == -1) {
        return nullptr;
    }

    // 1. 创建当前节点
    TreeNode* node = new TreeNode(nums[index]);

    // 2. 递归构建左子树(左子节点索引:2*index + 1)
    node->left = buildTreeRecursive(nums, 2 * index + 1);

    // 3. 递归构建右子树(右子节点索引:2*index + 2)
    node->right = buildTreeRecursive(nums, 2 * index + 2);

    return node;
}

// 先序遍历
void preOrder(TreeNode* node) {
    if (node == nullptr) return;
    cout << node->data << " ";
    preOrder(node->left);
    preOrder(node->right);
}

// 中序遍历
void inOrder(TreeNode* node) {
    if (node == nullptr) return;
    inOrder(node->left);
    cout << node->data << " ";
    inOrder(node->right);
}

// 后序遍历
void postOrder(TreeNode* node) {
    if (node == nullptr) return;
    postOrder(node->left);
    postOrder(node->right);
    cout << node->data << " ";
}

// 可视化打印树结构(直观展示层级)
void printTree(TreeNode* node, string prefix = "", bool isLeft = true) {
    if (node == nullptr) return;
    cout << prefix << (isLeft ? "├── " : "└── ") << node->data << endl;
    printTree(node->left, prefix + (isLeft ? "│   " : "    "), true);
    printTree(node->right, prefix + (isLeft ? "│   " : "    "), false);
}

// 释放树内存(后序遍历释放)
void deleteTree(TreeNode* node) {
    if (node == nullptr) return;
    deleteTree(node->left);
    deleteTree(node->right);
    delete node;
}

int main() {
    // 层序遍历数组:表示一个4层二叉树
    // 结构:
    //        1
    //       / \
    //      2   3
    //     / \ / \
    //    4  5 6  7
    //   /
    //  8
    // 注:数组中-1表示对应位置为空节点(示例中无空节点,仅展示格式)
    vector<int> levelOrderNums = {1, 2, 3, 4, 5, 6, 7, 8};

    // 递归构建树(从根节点索引0开始)
    TreeNode* root = buildTreeRecursive(levelOrderNums, 0);

    // 打印构建结果
    cout << "递归构建的4层二叉树结构:" << endl;
    printTree(root);
    cout << endl;

    // 遍历验证
    cout << "先序遍历:";
    preOrder(root);  // 输出:1 2 4 8 5 3 6 7
    cout << endl;

    cout << "中序遍历:";
    inOrder(root);   // 输出:8 4 2 5 1 6 3 7
    cout << endl;

    cout << "后序遍历:";
    postOrder(root); // 输出:8 4 5 2 6 7 3 1
    cout << endl;

    // 释放内存
    deleteTree(root);
    return 0;
}



运行结果:

二叉树链式存储结构:
├── 1
│   ├── 2
│   │   ├── 4
│   │   └── 5
│   └── 3
│       └── 6
先序遍历(根→左→右):1 2 4 5 3 6 
中序遍历(左→根→右):4 2 5 1 3 6 
后序遍历(左→右→根):4 5 2 6 3 1 
非递归后序遍历:4 5 2 6 3 1


    扫描二维码推送至手机访问。

    版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

    分享给朋友:

    相关文章

    【题解】采药的最短路径

    【题目描述】少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有...

    【数论】快速乘

    【数论】快速乘

    上一篇文章简单说了龟速乘的问题,有人觉得龟速乘还是太慢了,有没有什么办法再快一点,实际是有的,就是我们今天介绍的 快速乘。快速乘的原理和龟速乘不同,快速乘并不是基于二进制和位运算,严格来说,快速乘是利...

    【数据结构】栈—表达式括号匹配

    【数据结构】栈—表达式括号匹配

    【题目描述】假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”;否则...

    CSP复赛必备,时间与空间估算

    CSP复赛必备,时间与空间估算

    一、时间估算       在竞赛环境中,一般运行程序的时间是1s。这要求我们尽量不要循环太多次数,一般情况下,建议将时间复杂度控制在10^8以内。 ...

    C++中的位宽与保留小数

    C++中的位宽与保留小数

    一、setw函数C++ setw() 函数用于设置字段的宽度,语法格式如下setw(n)比如:#include <bits/stdc++.h> using names...

    【算法】前缀和与差分(3)二维数组前缀和

    【算法】前缀和与差分(3)二维数组前缀和

    0.前言前面的一篇文章,介绍了一维数组的前缀和,这篇文章中,介绍一下二维数组的前缀和1.定义二维数组的前缀和就是按照二维数组求和。公式如下:那二维前缀和中一个f[i][j]表示的意思就是以(1,1)为...