树
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);