数据结构笔记16:树的基本数据类型结构(AI解释生成,了解即可)

这段代码的核心思想是使用链表来表示多叉树中每个节点的子节点关系,从而构建出一棵灵活的树结构。

为了帮助你理解,我将分为以下几个部分进行解释:

  1. 数据结构的设计
  2. 核心函数的功能和实现
  3. 举例分析运行流程

1️⃣ 数据结构的设计

这段代码中的树的设计如下:

  • TreeNode(树的节点):表示树的一个节点,包含两个信息:

    • data:节点的数据,类型为 eleType,这里用 char 表示树节点存储的字符数据。
    • childrenHead:一个链表指针,表示所有子节点的链表头,每个子节点通过一个ListNode节点连接到这棵树上。
  • ListNode(链表的节点):用于表示一个子节点,每个 ListNode 中存储:

    • data:指向子节点的树节点的指针TreeNode*)。
    • next:指向下一个子节点,从而将多个子节点串联成一个单链表
  • Tree(树):表示一棵完整的树,包含:

    • nodes:用来存储树的所有节点,类型是 TreeNode*
    • root:指向树的根节点,是树的入口。

2️⃣ 核心函数的功能和实现

1. void Add_TreeChild(TreeNode* parent, TreeNode* child)

这个函数的功能是将 child 作为 parent 的子节点,并将其加入到 parent 的子节点链表中。

实现思路:

  • 创建一个 ListNode,将 child 节点的指针存储在 ListNode 中。
  • 如果 parent 没有任何子节点,则将 child 作为链表的第一个节点(头节点)。
  • 如果 parent 已有子节点,则使用头插法,将 child 插入链表的最前面。
void Add_TreeChild(TreeNode* parent, TreeNode* child)
{
    ListNode* childNode = (ListNode*)malloc(sizeof(ListNode));  // 创建子节点链表
    childNode->data = child;  // 指向子节点的树节点
    childNode->next = parent->childrenHead; // 头插法
    parent->childrenHead = childNode; // 更新头指针
}

2. void Creat_Tree(Tree* t, int size)

这个函数的功能是创建一棵有 size 个节点的树,并为每个节点分配内存。

void Creat_Tree(Tree* t, int size)
{
    t->nodes = (TreeNode*)malloc(sizeof(TreeNode) * size);  // 申请 size 个 TreeNode
    t->root = NULL; // 暂时不设置根节点
}

3. void SetRoot_Tree(Tree* t, int id)

这个函数将 id 号节点设置为树的根节点。

void SetRoot_Tree(Tree* t, int id)
{
    t->root = &t->nodes[id]; // 获取 id 号节点并设为根节点
}

4. void AssighData_Tree(Tree* t, int id, eleType data)

将树的第 id 号节点的 data 设置为 data,并初始化其 childrenHead

void AssighData_Tree(Tree* t, int id, eleType data)
{
    t->nodes[id].data = data; // 给 id 号节点设置数据
    t->nodes[id].childrenHead = NULL; // 初始化子链表为空
}

5. void SetLine_Tree(Tree* t, int parentId, int childId)

parentId 节点和 childId 节点之间建立父子关系

void SetLine_Tree(Tree* t, int parentId, int childId)
{
    TreeNode* parentNode = &t->nodes[parentId]; // 获取父节点
    TreeNode* childNode = &t->nodes[childId]; // 获取子节点
    Add_TreeChild(parentNode, childNode); // 调用上面的 Add_TreeChild 函数
}

6. void Print_Tree(Tree* t, TreeNode* node)

采用先序遍历打印树的内容。

void Print_Tree(Tree* t, TreeNode* node)
{
    if (node == NULL) node = t->root; // 如果 node 为空,则从根节点开始
    printf("%c", node->data); // 打印当前节点的数据
    ListNode* temp = node->childrenHead; // 遍历当前节点的子节点链表
    while (temp) 
    {
        Print_Tree(t, temp->data); // 递归打印子节点
        temp = temp->next; // 继续下一个子节点
    }
}

3️⃣ 运行流程举例

1. 构建一棵树

       a
      / \
     b   c
    /   / \
   d   e   f

操作代码

SetRoot_Tree(&T, 0);  // 根节点为 a
AssighData_Tree(&T, 0, 'a');
AssighData_Tree(&T, 1, 'b');
AssighData_Tree(&T, 2, 'c');
AssighData_Tree(&T, 3, 'd');
AssighData_Tree(&T, 4, 'e');
AssighData_Tree(&T, 5, 'f');
SetLine_Tree(&T, 0, 1); // a -> b
SetLine_Tree(&T, 0, 2); // a -> c
SetLine_Tree(&T, 1, 3); // b -> d
SetLine_Tree(&T, 2, 4); // c -> e
SetLine_Tree(&T, 2, 5); // c -> f

结构分析

  • a 有 2 个子节点:bc
  • b 有 1 个子节点:d
  • c 有 2 个子节点:ef

2. 先序遍历的过程

打印顺序为:

a b d c e f

4️⃣ 小结

  1. 树的父子关系

    • 使用链表 ListNode 来存储每个节点的子节点列表,每个 TreeNodechildrenHead 维护一个子节点的链表。
  2. 函数的操作

    • Add_TreeChild:将子节点添加到父节点的子链表中。
    • Print_Tree:先序遍历树的节点。
    • SetLine_Tree:设置父子关系。

5️⃣ 图示帮助理解

如果要可视化树的结构,TreeNodeListNode 的关系如下:

TreeNode (a)
    |
    +--> ListNode (指向b) --> ListNode (指向c)
                      |                |
                  TreeNode (b)     TreeNode (c)
                      |                |
               ListNode (指向d)   ListNode (指向e) --> ListNode (指向f)
                      |
                  TreeNode (d)

每个 TreeNodechildrenHead 指向链表的头节点,链表中的每个 ListNode 都指向一个子节点 TreeNode


如果有任何部分不理解的,或需要更详细的解释,请告诉我!我会为您补充细节! 😊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值