树的孩子兄弟表示法(二叉树表示法、二叉链表表示法)(先序、后序、层次遍历树)
树的存储结构
实现:用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向其第一个孩子结点和下一个兄弟结点。
树和二叉树的转换
树的遍历
树没有中序遍历(树有多个孩子,放在哪个地方算是中序呢对吧?),一般来说只有先序和后序。
实现
#include <iostream>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
typedef char CSTElemType;
using namespace std;
//树的孩子兄弟表示法
typedef struct CSNode {
CSTElemType data;//数据域
CSNode* firstChild, * nextsibling;
//用两个指针分别指向树的第一个孩子和它相邻的兄弟结点
}CSNode, * CSTree;
//创建一个队列为层次遍历做准备啦
typedef CSTree QElemType;
typedef struct {
QElemType data[MAXSIZE];
int front, rear;
}SqQueue;
//初始化一个队列
void InitQueue(SqQueue *q) {
q->front = q->rear = 0;
}
//入队
/*
入队需要将尾指针往后移,注意循环链表的往后移是mod运算,因为是循环的嘛
然后还有一点要注意的是:
当rear+1模maxsize就达到front头指针的时候就是代表队满了,不能再入队了
*/
Status EnQueue(SqQueue *q, QElemType e) {
if ((q->rear + 1) % MAXSIZE == q->front) {
return ERROR;
}
q->data[q->rear] = e;
q->rear = (q->rear + 1) % MAXSIZE;
return OK;
}
//出队
Status Dequeue(SqQueue* q, QElemType& e) {
if (q->front == q->rear) {
return ERROR;//队列为空不能再弹出元素
}
e = q->data[q->front];
q->front = (q->front + 1) % MAXSIZE;
return OK;
}
//判断队空
bool IsEmpty(SqQueue* q) {
if (q->front == q->rear) {
return TRUE;
}
return FALSE;
}
//树的创建,这里还是用二叉链表法表示树,所以这里树的创建和二叉树是一样的
void CreateCSTree(CSTree& T) {
CSTElemType ch;
cin >> ch;
//注意啦注意啦!!
//递归操作的返回值代表啥东西,你要懂喔,不然又像这里,写成return NULL就败家伙了
//这里链表的连接是靠传递的参数进行链接的,而不是返回值,
//你写了返回值的话,说明你返回了一个null但是但是,和生成的CSTree T半毛钱关系都没有
if (ch == '#') {
T=NULL;
}
else
{
T = new CSNode;//新建一个结点
T->data = ch;
CreateCSTree(T->firstChild);
CreateCSTree(T->nextsibling);
}
}
//先序遍历查看该树
void preTransever(CSTree T) {
if (T!= NULL) {
cout << T->data << " ";
preTransever(T->firstChild);
preTransever(T->nextsibling);
}
}
//层次遍历孩子兄弟表示法的树
void levelTransever(CSTree T) {
SqQueue* q=new SqQueue;
CSTree p;
InitQueue(q);
EnQueue(q, T);
while (!IsEmpty(q)) {
Dequeue(q, p);
printf("%c ", p->data);
p = p->firstChild;
if (p) {
EnQueue(q,p);
p = p->nextsibling;
while (p) {
EnQueue(q, p);
p = p->nextsibling;
}
}
}
}
//这是树的后序遍历,似乎就等于二叉树的中序遍历
void afterTransever(CSTree T) {
if (T != NULL) {
afterTransever(T->firstChild);
cout << T->data << " ";
afterTransever(T->nextsibling);
}
}
int main() {
CSTree T;
CreateCSTree(T);
preTransever(T);
printf("\n树的后序遍历而不是二叉链表的后序遍历:\n");
afterTransever(T);
printf("\n树的层次遍历如下:\n");
levelTransever(T);
return 0;
}
先序遍历测试用例:
这棵树的存储结构是啥样的呢?:
这样的~
这棵树长啥样呢?
然后按照先序遍历遍历如上二叉链表表示的森林应该得到的是:
ABCDEFG
看一下结果是不是
后序遍历测试用例:
存储结构:
那个上面输入的时候不小心在后面多了个#,虽然可以正常,但是吧,为了严谨,要说明一下的!
树真实的样子(应该长这样):
为啥树的后序会等于二叉链表的中序遍历呢?
你仔细想想,树的后序遍历是不是要先输出左子树的全部,然后输出自己再然后遍历兄弟,那不就是了吗?左子树就是左孩子嘛,自己不就是当前的结点吗,然后兄弟不就是当前结点的nextsibling吗。不就是相当于中序吗?
然后就是层次遍历啦~,是树的层次遍历喔,不是之前的二叉树即这里的二叉链表的层次遍历喔,是不一样的,区分开哦
就是需要用到队列,但是啥时候入队啥时候出队,这种东西我也不知道咋讲?凭感觉?
层次遍历测试用例: 不能再用新树了,再画我真要有强迫症了
我也是按照自己的理解来写的哈,有可能会有bug,欢迎指整,共同进步~