[C++] 数据结构

本文介绍了树的两种存储结构——顺序存储结构和链式存储结构,并详细阐述了如何将双亲存储结构转换为孩子存储结构。在顺序存储结构中,讨论了双亲和孩子存储结构的特点,而在链式存储结构中,同样讨论了孩子链表的构建。此外,还提供了深度优先遍历孩子存储结构的实现方法,包括C++代码示例。
摘要由CSDN通过智能技术生成

1、顺序存储结构

(1)双亲存储结构

用一个整型数组存储一棵树的信息,数组下标表示树中的结点,数组元素表示该结点的父结点。根结点的父结点为-1。
在这里插入图片描述

(2)孩子存储结构

用二维数组表示一棵树的信息,每一行的首个元素表示树中结点,后续元素表示该结点的孩子结点。
上图中的树的孩子存储结构如下:
在这里插入图片描述

双亲存储结构转变成孩子存储结构:

#include<vector>
#include<iostream>

using namespace std;

int main()
{
	//树中结点总数
	int n = 7;

	//双亲存储结构
	vector<int> node = { -1,-1,1,1,1,3,3,3 };

	//孩子存储结构
	vector< vector<int> >edge;
	//一共有n个结点,但索引从0开始,而结点编号从1开始
	edge.resize(n + 1);
	//双亲结构中,根结点为1号结点,没有父结点。从2号结点开始,可以在双亲结构中寻找他们的父结点
	for (int i = 2; i < node.size(); i++)
	{
		edge[ node[i] ].push_back(i);
	}

	//打印孩子存储结构
	for (int i = 0; i < edge.size(); i++)
	{
		cout << i << ":";
		for (auto e : edge[i])
		{
			cout << e << " ";
		}
		cout << endl;
	}


	return 0;
}

深度优先遍历孩子存储结构:

//深度优先遍历
void dfs(int cur)
{
	//该结点的孩子结点
	for (auto e : edge[cur])
	{
		//深度优先遍历以孩子结点为根结点的子树
		dfs(e);
	}
	//auto e 如果vector为空或到了结尾,会自动退出,不进入for循环
	//自动退出意味着该结点没有孩子结点了
	//访问该结点
	cout << cur<<" ";
}
//从根结点开始深度优先遍历
dfs(1);

在这里插入图片描述

2、链式存储结构

(1)孩子存储结构

与顺序存储结构中的孩子存储结构类似,用数组表示树中每一个结点,但每个结点的内容是一个链表,连接该结点的每一个孩子结点。
在这里插入图片描述

#include<vector>

using namespace std;

//树中的结点的总数
int n = 7;

//树中的结点
typedef struct TreeNode
{
	//结点中的数据,这里是结点的编号
	int data;
	//指向孩子链表的头指针
	ChildNode * first;
}TreeNode;

//孩子链表中的结点
typedef struct ChildNode
{
	//该孩子结点在树中结点组成的数组中的索引
	int index;
	//指向下一个孩子结点的指针
	ChildNode * next;
}ChildNode;

//树
vector<TreeNode> Tree(n + 1);

双亲存储结构转变成孩子存储结构:

#include<vector>

using namespace std;

//树中的结点的总数
int n = 7;

//孩子链表中的结点
typedef struct ChildNode
{
	//该孩子结点在树中结点组成的数组中的索引
	int index;
	//指向下一个孩子结点的指针
	ChildNode * next;
}ChildNode;

//树中的结点
typedef struct TreeNode
{
	//结点中的数据,这里是结点的编号
	int data;
	//指向孩子链表的头指针
	ChildNode * first;
}TreeNode;

//树
vector<TreeNode> Tree(n + 1);

int main()
{

	//双亲存储结构
	vector<int> node = { -1,-1,1,1,1,3,3,3 };

	//录入一下树的数据
	for (int i = 0; i < Tree.size(); i++)
	{
		Tree[i].data = i;
	}

	//双亲结构中,根结点为1号结点,没有父结点。
	//从2号结点开始,可以在双亲结构中寻找他们的父结点
	for (int i = 2; i < node.size(); i++)
	{
		//新申请内存存放孩子结点
		ChildNode* temp = (ChildNode*)malloc(sizeof(ChildNode));
		//结点i在树中的索引
		temp->index = i;
		temp->next = nullptr;

		//指向结点i的父结点的指针
		TreeNode * p = &Tree[ node[i] ];

		//如果结点i的父结点没有孩子结点
		if (p->first == nullptr)
		{
			//把建立的孩子结点i链接上去
			p->first = temp;
		}
		//如果结点i的父结点有孩子结点
		else
		{
			//指针c指向第一个孩子结点
			ChildNode * c = p->first;
			//如果c指向的不是最后一个孩子结点
			while (c->next != nullptr)
			{
				//c一路指到最后一个孩子结点
				c = c->next;
			}
			//把建立的孩子结点i链接上去
			c->next = temp;
		}
	}

	return 0;
}

遍历孩子存储结构:

void dfs(vector<TreeNode> & Tree, int cur)
{
	//访问cur结点
	cout << Tree[cur].data << " ";
	//指针p指向cur结点的第一个孩子结点
	ChildNode * p = Tree[cur].first;

	//如果cur结点有孩子
	while(p)
	{
		//递归cur结点的孩子结点
		dfs(Tree, p->index);
		//如果递归完孩子结点后,p指向下一个孩子结点
		p = p->next;
	}
	//如果cur结点没有孩子了
	//回到上一层递归
}
//从根结点开始
dfs(1);

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值