IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> (数据结构)树的Child表示法 -> 正文阅读

[数据结构与算法](数据结构)树的Child表示法

树的孩子表示法

此前介绍过用双亲表示法存储普通树,本篇文章将讲解另一种存储普通树的方法...


另一种方法是孩子表示法!!!

孩子表示法存储普通树采用的是:顺序表和链表的组合结构

其存储过程是:从树的根节点开始,使用顺序表依次存储树中各个节点,需要注意的是,与双亲表示法不同,孩子表示法会给各个节点配备一个链表,用于存储各节点的孩子节点位于顺序表中的位置(而双亲表示法会配置一个整型变量,用来保存双亲的位置)

如果节点没有孩子节点(叶子节点),则该节点的链表为空链表

例如,使用孩子表示法存储下图左侧的普通树,则最终存储状态如下图右侧所示:

通过上图右侧的存储状态,我们就能很容易声明某些节点:

typedef struct CTNode{
	int child;  // 代表孩子结点的索引位置
	struct CTNode *next;  // 指向下一个孩子结点 
} ChildPtr;

typedef struct{
	char data;  // 结点数据域 
	ChildPtr *firstchild;  // 孩子链表的头指针 
} CTBox;

typedef struct{
	CTBox nodes[MAX_SIZE];  // 存储结点的数组 
	int n, r;  // 结点数量和树根位置 
} CTree;

树的孩子表示法的代码实现

#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 20

typedef struct CTNode{
	int child;  // 代表孩子结点的索引位置
	struct CTNode *next;  // 指向下一个孩子结点 
} ChildPtr;

typedef struct{
	char data;  // 结点数据域 
	ChildPtr *firstchild;  // 孩子链表的头指针 
} CTBox;

typedef struct{
	CTBox nodes[MAX_SIZE];  // 存储结点的数组 
	int n, r;  // 结点数量和树根位置 
} CTree;

// 初始化普通树的结点 
CTree initTree(CTree tree){
    printf("输入节点数量:\n");
    scanf("%d", &(tree.n));
    for(int i = 0; i < tree.n; i++){
        printf("输入第 %d 个节点的值:\n", i + 1);
        getchar();
        scanf("%c", &(tree.nodes[i].data));
		// 孩子链表头指针有值,但是在主函数中已经将指针指向 NULL了,此处重新在堆区申请 
        tree.nodes[i].firstchild = (ChildPtr*)malloc(sizeof(ChildPtr));
        tree.nodes[i].firstchild->next = NULL;
        printf("输入节点 %c 的孩子节点数量:\n", tree.nodes[i].data);
        int Num;
        scanf("%d", &Num);
        if (Num != 0) {
            ChildPtr *p = tree.nodes[i].firstchild;
            for(int j = 0; j < Num; j++) {
                ChildPtr *newEle = (ChildPtr*)malloc(sizeof(ChildPtr));
                newEle->next = NULL;
                printf("输入第 %d 个孩子节点在顺序表中的位置:", j + 1);
                scanf("%d", &(newEle->child));
                p->next = newEle;
                p = newEle;
            }
        }
    }
    return tree;
}

// 查找某结点的孩子结点 
void findKids(CTree tree, char a){
    int hasKids = 0;  // 判断该节点是否有孩子结点 
    for(int i = 0; i < tree.n; i++){
        if(tree.nodes[i].data == a){
            ChildPtr *p = tree.nodes[i].firstchild->next;
            while (p){
                hasKids = 1;
                printf("%c ", tree.nodes[p->child].data);
                p = p->next;
            }
            break;
        }
    }
    if(hasKids == 0){
        printf("此节点为叶子节点");
    }
}

int main(void){
	CTree tree;
	for(int i = 0; i < MAX_SIZE; i++){
		tree.nodes[i].firstchild = NULL;
		tree.nodes[i].data = ' ';
	}
	tree = initTree(tree);
	// 默认数根节点位于数组 notes[0]处
    tree.r = 0;
	findKids(tree, 'F');
	return 0;
}

树的孩子和双亲表示法结合的介绍及代码实现(优化)

先谈一下孩子双亲表示法!!!

使用孩子表示法存储的树结构,正好和双亲表示法相反,适用于查找某结点的孩子结点,不适用于查找其父结点,如果可以将双亲表示法和孩子表示法合二为一!!!

例如,使用孩子表示法结合双亲表示法存储此前的普通树,则最终存储状态如下图所示:

?通过上图的存储状态,我们就能很容易声明某些节点:

typedef struct CTNode{
	int child;  // 代表孩子结点的索引位置
	struct CTNode *next;  // 指向下一个孩子结点 
} ChildPtr;

typedef struct{
	char data;  // 结点数据域 
	int parent;  // 保存双亲的位置 
	ChildPtr *firstchild;  // 孩子链表的头指针 
} CTBox;

typedef struct{
	CTBox nodes[MAX_SIZE];  // 存储结点的数组 
	int n, r;  // 结点数量和树根位置 
} CTree;

?再谈其具体代码实现!!!

#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 20

typedef struct CTNode{
	int child;  // 代表孩子结点的索引位置
	struct CTNode *next;  // 指向下一个孩子结点 
} ChildPtr;

typedef struct{
	char data;  // 结点数据域 
	int parent;  // 保存双亲的位置 
	ChildPtr *firstchild;  // 孩子链表的头指针 
} CTBox;

typedef struct{
	CTBox nodes[MAX_SIZE];  // 存储结点的数组 
	int n, r;  // 结点数量和树根位置 
} CTree;

// 初始化普通树的结点 
CTree initTree(CTree tree){
    printf("输入节点数量:\n");
    scanf("%d", &(tree.n));
    for(int i = 0; i < tree.n; i++){
//        printf("输入第 %d 个节点的值:\n", i + 1);
    	printf("请输入第 %d 个结点的值和其双亲位于数组中的位置下标:\n", i+1);
        getchar();
        scanf("%c %d", &(tree.nodes[i].data), &(tree.nodes[i].parent));
		// 孩子链表头指针有值,但是在主函数中已经将指针指向 NULL了,此处重新在堆区申请 
        tree.nodes[i].firstchild = (ChildPtr*)malloc(sizeof(ChildPtr));
        tree.nodes[i].firstchild->next = NULL;
        printf("输入节点 %c 的孩子节点数量:\n", tree.nodes[i].data);
        int Num;
        scanf("%d", &Num);
        if (Num != 0) {
            ChildPtr *p = tree.nodes[i].firstchild;
            for(int j = 0; j < Num; j++) {
                ChildPtr *newEle = (ChildPtr*)malloc(sizeof(ChildPtr));
                newEle->next = NULL;
                printf("输入第 %d 个孩子节点在顺序表中的位置:", j + 1);
                scanf("%d", &(newEle->child));
                p->next = newEle;
                p = newEle;
            }
        }
    }
    return tree;
}

// 查找某结点的孩子结点 
void findKids(CTree tree, char a){
    int hasKids = 0;  // 判断该节点是否有孩子结点 
    for(int i = 0; i < tree.n; i++){
        if(tree.nodes[i].data == a){
            ChildPtr *p = tree.nodes[i].firstchild->next;
            while (p){
                hasKids = 1;
                printf("%c ", tree.nodes[p->child].data);
                p = p->next;
            }
            break;
        }
    }
    if(hasKids == 0){
        printf("此节点为叶子节点");
    }
}

// 查找某结点的双亲结点 
void FindParent(CTree tree){
    char a;
    int isfind = 0;  // 是否找到的标志 
    printf("请输入要查询的结点值:\n");
    getchar();  // 作用: 读取回车符 
    scanf("%c", &a);  // F
    for(int i = 0; i < tree.n; i++){
        if(tree.nodes[i].data == a){
            isfind = 1;
            int ad = tree.nodes[i].parent;
            printf("%c的父节点为 %c,存储位置下标为 %d", a, tree.nodes[ad].data, ad);
            break;
        }
    }
    if(isfind == 0){
        printf("树中无此节点");
    }
}

int main(void){
	CTree tree;
	for(int i = 0; i < MAX_SIZE; i++){
		tree.nodes[i].firstchild = NULL;
		tree.nodes[i].data = ' ';
	}
	tree = initTree(tree);
	// 默认数根节点位于数组 notes[0]处
    tree.r = 0;
	findKids(tree, 'F');
	FindParent(tree);
	return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 23:38:43  更:2022-04-01 23:42:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:36:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码