C语言数据结构(12)--链表描述子节点的树

简介: 本文目录1. 数组描述子节点的缺点2. 使用链表描述3. 代码实现4. 执行结果

1. 数组描述子节点的缺点

如果有这么一颗奇葩的树,大多数节点的孩子数为1-2个,但是有一个节点的孩子数是100个。


因为我们使用数组描述子节点,所以描述子节点的数组得定义为struct TreeNode* children[100];。


也就是说,除了有一个充分利用了数组分配的空间,其他的都造成了极大浪费,毫无疑问不合理。


2. 使用链表描述

孩子也是一个一维的集合,特点个数不确定,符合这种特点的数据结构就是链式线性表了(简称链表)。


我们再来仔细观察下树的结构图,来尝试定义节点的数据结构:

image.png

首先一个节点得有一个数据区域,保存节点的数据信息,最简单就是保存一个int数据。

每个节点有多个孩子,这个可以使用一个链表来描述,因为链表指定了头指针,就能把整个链表带出来,所以可以定义节点为。

typedef struct {

int data;//数据区域

TreeNode* node;//保存孩子中的头结点

}TreeNode;


上面的节点数据结构乍一看没啥问题,对于节点1来说,data区域保存1,node的data保存2,node的node指向3。


但是2下面的5和6呢,已经没有地方存储了。


我们再次仔细分析下节点,实际上每个节点除了要通过一个链表保存兄弟节点,还需要一个链表保存孩子节点。


于是结构应该为:


typedef struct {

int data;//数据区域

TreeNode* brother;//保存兄弟节点 如果为NULL表示无

TreeNode* son;//保存孩子节点 如果为NULL表示无

}TreeNode;


也就是说,我们的存储结构实际上是,同样能表达含义一模一样的树。

image.png

3. 代码实现

嗯,这个代码已经有一定理解难度了,我也是写了大概几十分钟才搞定的,C语言真是魅力无穷吭,喷香!

/*
* 使用链表描述子节点的普通树实现
* 作者:熊猫大大
* 时间:2019-10-16
*/
#include <stdio.h>
typedef struct {
  int data;//数据区域
  struct TreeNode* brother;//保存兄弟节点 如果为NULL表示无
  struct TreeNode* son;//保存孩子节点 如果为NULL表示无
}TreeNode;
//为树的当前节点添加子节点
int addChild(TreeNode* curNode, int data)
{
  //分配新节点
  TreeNode* newNode= (TreeNode*)malloc(sizeof(TreeNode));
  newNode->data = data;
  newNode->brother = NULL;
  newNode->son = NULL;
  //找到当前节点的最后一个字节点
  TreeNode* lastSonNode = curNode->son;//指向第一个子节点
  if (lastSonNode == NULL) //第一个子节点即为空
  {
    curNode->son = newNode;
    return 1;
  }
  while (lastSonNode->brother != NULL) //找到最后一个节点
  {
    lastSonNode = lastSonNode->brother;
  }
  lastSonNode->brother = newNode;//将新节点挂在最后一个节点后面
  return 1;
}
//遍历当前节点与子节点
void printTree(TreeNode *node)
{
  printf("父节点:%d",node->data);
  //遍历打印子节点
  printf("----子节点:");
  TreeNode *p = node->son;
  if (p == NULL) //无子节点
  {
    printf("无\n");
    return 1;
  }
  if (p != NULL) 
  {
    printf("%d ",p->data);
  }
  while(p->brother!=NULL)
  {
    p = p->brother;
    printf("%d ", p->data);
  }
  printf("\n");
  //遍历递归子节点
  TreeNode *q = node->son;
  if (q != NULL)
  {
    printTree(q);
  }
  while (q->brother != NULL)
  {
    q = q->brother;
    printTree(q);
  }
}
//----------------------------------------------------------------------------------------------------测试入口区域
int main()
{
  //设定根节点
  TreeNode root;
  root.data = 1;//根节点数据区域
  root.brother = NULL;//根节点无兄弟节点
  root.son = NULL;//一开始也没有子节点
  //为1节点添加2/3/4子节点
  addChild(&root,2);
  addChild(&root, 3);
  addChild(&root, 4);
  //为2号节点添加5/6子节点
  TreeNode *node2 = root.son;
  addChild(node2, 5);
  addChild(node2, 6);
  //为3号节点添加7子节点
  TreeNode *node3 = node2->brother;
  addChild(node3, 7);
  //为4号节点添加8子节点
  TreeNode *node4 = node3->brother;
  addChild(node4, 8);
  printTree(&root);
  return 1;
}

4. 执行结果

毫无疑问,执行结果验证了代码的真实性,但是输出顺序稍微有点乱。

主要是因为现在的输出是顺着一个节点,将其子节点输出完,才输出另外节点的逻辑,如果不好理解下个断点走走就是了。

image.png

相关文章
|
17天前
|
C语言
对链表使用插入排序的C语言实现示例
对链表使用插入排序的C语言实现示例
|
27天前
|
存储 缓存 算法
数据结构-链表(一)
链表(Linked List)是一种常见的数据结构,用于存储和组织数据。与数组不同,链表的元素(节点)在内存中不必连续存储,而是通过指针链接在一起。 链表由多个节点组成,每个节点包含两部分:数据(存储实际的元素值)和指针(指向下一个节点的引用)。链表的第一个节点称为头节点,最后一个节点称为尾节点,尾节点的指针通常指向空值(null)。
31 1
|
29天前
|
存储 C++
数据结构第六弹---带头双向循环链表
数据结构第六弹---带头双向循环链表
|
7天前
|
算法 DataX
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
|
10天前
数据结构—链表(超详细)(山东大学)(数据结构实验三)
数据结构—链表(超详细)(山东大学)(数据结构实验三)
数据结构|双向链表|带头结点|头插|尾插|尾删|头删
数据结构|双向链表|带头结点|头插|尾插|尾删|头删
|
12天前
数据结构--链表刷题(一)快慢指针(上)
数据结构--链表刷题(一)快慢指针
16 0
|
21天前
|
缓存 算法 搜索推荐
【数据结构】链表(单链表与双链表实现+原理+源码)
【数据结构】链表(单链表与双链表实现+原理+源码)
|
25天前
|
存储 编译器 C语言
【数据结构】深入浅出理解链表中二级指针的应用
【数据结构】深入浅出理解链表中二级指针的应用
27 0
|
28天前
|
存储 算法 程序员
【数据结构】【版本2.0】【树形深渊】——二叉树入侵
【数据结构】【版本2.0】【树形深渊】——二叉树入侵