多叉树的链表实现

目录

  • 一.树的概念
  • 二.树的数据结构表示

一.树的概念

1.树的定义

树是n个节点的有限集合,n=0,时为空树,当n > 0时,满足如下俩个条件

(1)有且仅有一个特定的结点,称为根节点Root;
(2)当n > 1时,其余结点分为m个互不相交的有限集合,T1,T2,T3…T ( (m)),其中每一个T ( (i))又是一棵树,并且为Root的子数;
在这里插入图片描述
2.子树的定义

树的定义用到了递归的思想。即树的定义中,还用到了树的概念。

T (1)和T (2)就是a的子树,结点d,g,h,i组成的树又是结点

b的子树。
在这里插入图片描述
子树的个数没有限制,但是他们一定是互不相交的,如图所示。这样就不是树。

在这里插入图片描述
3.结点的定义

树的结点包含一个数据域和m个指针域,指针域用来指向它的子树。结点的分类为:根结点,叶子结点,内部结点。结点拥有子树的个数,被称为结点的度,树中各个结点度的最大值,被称为 树的度。

1)根结点

一棵树的根结点只有一个,(图中红色结点)。

2)叶子结点

度为0的结点被称为叶子结点,叶子结点不能指向任何子树(图中黄色结点)

3)内部结点

除了根结点和叶子结点以外的结点,都被称为内部结点(图中蓝色结点)

在这里插入图片描述
4.结点间的关系

1)孩子结点

对于某个结点,它的子树的根结点被称为该节点的孩子结点。

在这里插入图片描述
2)父结点

该结点被称为孩子结点的父结点

在这里插入图片描述
3)兄弟结点

同一父结点下的孩子结点互相称为兄弟结点。

在这里插入图片描述
5.树的深度

结点的层次,从根结点开始记为第1层,如果某个结点在第i层,则它的子树的根结点再第i+1层。树中结点的最大层次称为树的深度,如图所示,是一颗深度为4的树。

在这里插入图片描述
6.森林的定义

森林是m颗互不相交的树的集合。对于树的每一个结点而言,其子树结合就是森林,如图所示b和c俩颗子树组成的集合就是一个森林。

在这里插入图片描述

二.树的数据结构表示

1.结点id

为了方便树数据的读取和修改,我们一般用一个数字来表示树的结点,这个数字就是树的id,它是一个唯一的id,每个数结点的结点id不同。如图所示,每个结点都有一个id作为标识。

在这里插入图片描述

2.结点池

在处理数相关的问题是,结点一定是有限的,有时候也一定是确定的,比如一个问题给出的时候,给出一个n个结点的数,这个n必然是有上限的,所以我们可以事先将所有结点存储在一个顺序表,然后通过结点id的索引方式,快速获得对应结点,而这个顺序表就是结点池。

所以,根据结点id获取结点的这步操作,时间复杂度为o(1)的。

3.结点数据

数的结点数据可以是任意的,这样就可以处理任何情况下的问题,如图所示,数结点的数据的类型是字符类型(a,b,c,d,e,f,g,h,i)。

在这里插入图片描述

4.孩子结点列表

每个结点都要保存一个孩子结点列表(叶子结点的孩子结点列表是空的),注意这里所说的列表,不是顺序表,也不是链表,当然也不是Python中的list,而指的就是自然语义上的列表,我们可以用顺序表来实现对孩子结点的存储,也可以通过链表。

5.添加数边

如图所示,俩个绿色的箭头,分别代表的就是添加的俩条边(a->b,a->c)的过程。添加数边的过程,可以通过数的结点id先获取实际的数结点,然后将孩子结点添加到父结点的孩子结点列表来完成。

在这里插入图片描述

6.数的遍历

数的遍历的引入,让我们开始了解递归的概念,而数本身也是一种递归的数据结构。递归可以用来遍历这个数据结构。

三.代码

#include <stdio.h>
#include <stdlib.h>

#define eleType char
struct TreeNode;

typedef struct ListNode{
    struct TreeNode* data;
    struct ListNode* next;
} ListNode;

typedef struct TreeNode{
    eleType data;
    ListNode* childrenHead;
} TreeNode;

void AddTreeChild(TreeNode* parent, TreeNode* child) {
    ListNode* childNode = (ListNode*)malloc(sizeof(ListNode));
    childNode->data = child;
    childNode->next = NULL;
    if (parent->childrenHead == NULL) {
        parent->childrenHead = childNode;
    } else {
        childNode->next = parent->childrenHead;
        parent->childrenHead = childNode;
    }
}

typedef struct Tree {
    TreeNode* nodes;
    TreeNode* root;
} Tree;

void TreeCreate(Tree* t, int size) {
    t->nodes = (TreeNode*)malloc(sizeof(TreeNode) * size);
    t->root = NULL;
    for (int i = 0; i < size; i++) {
        t->nodes[i].childrenHead = NULL; // 初始化子节点链表头指针
    }
}

void FreeList(ListNode* head) {
    ListNode* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

void TreeDestroy(Tree* t) {
    for (int i = 0; t->nodes[i].childrenHead != NULL; i++) {
        FreeList(t->nodes[i].childrenHead);
    }
    free(t->nodes);
    t->nodes = NULL;
    t->root = NULL;
}

TreeNode* TreeGetNode(Tree* t, int id) {
    return &t->nodes[id];
}

void TreeSetRoot(Tree* t, int id) {
    t->root = TreeGetNode(t, id);
}

void TreeAddChild(Tree* t, int parentID, int childID) {
    TreeNode* parentNode = TreeGetNode(t, parentID);
    TreeNode* childNode = TreeGetNode(t, childID);
    AddTreeChild(parentNode, childNode);
}

void TreeAssignData(Tree* t, int id, eleType data) {
    TreeGetNode(t, id)->data = data;
}

void TreePrint(Tree* t, TreeNode* node) {
    if (node == NULL) {
        node = t->root;
    }
    printf("%c ", node->data);
    ListNode* tmp = node->childrenHead;
    while (tmp) {
        TreePrint(t, tmp->data);
        tmp = tmp->next;
    }
}

int main() {
    Tree T;
    TreeCreate(&T, 9);
    TreeSetRoot(&T, 0);
    TreeAssignData(&T, 0, 'a');
    TreeAssignData(&T, 1, 'b');
    TreeAssignData(&T, 2, 'c');
    TreeAssignData(&T, 3, 'd');
    TreeAssignData(&T, 4, 'e');
    TreeAssignData(&T, 5, 'f');
    TreeAssignData(&T, 6, 'g');
    TreeAssignData(&T, 7, 'h');
    TreeAssignData(&T, 8, 'i');

    TreeAddChild(&T, 0, 2);
    TreeAddChild(&T, 0, 1);
    TreeAddChild(&T, 1, 3);
    TreeAddChild(&T, 2, 5);
    TreeAddChild(&T, 2, 4);
    TreeAddChild(&T, 3, 8);
    TreeAddChild(&T, 3, 7);
    TreeAddChild(&T, 3, 6);
    
    TreePrint(&T, T.root);
    printf("\n");
    TreeDestroy(&T);
    return 0;
}

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值