![1d003767b0b8288cd1ad4765921472fa.png](https://img-blog.csdnimg.cn/img_convert/1d003767b0b8288cd1ad4765921472fa.png)
最近叨叨Chen遇到了个算法题,还挺有意思。我们知道存储二叉树的形式有很多,通常遇到的是广义表形式/用户输入先序遍历和中序遍历/其他,今天给大家分享的是如何根据用户输入的三元组数列来建立二叉树,叨叨Chen在设计算法的时候结合了队列的思想,感兴趣的同学一起来“游玩”吧!
It's show time!
Punchline-------------------------------------------------------------------
Task:假设以三元组(F,C,L/R)
的形式输入一棵二叉树的诸边(其中F
表示双亲结点的标识,C
标识孩子结点的标识,L/R
标识C
为F
的左孩子或右孩子),且在输入的三元组序列中,C
是按层次顺序出现的。设结点的标识是字符类型。F=^
时C
为根节点标识,若C
也为^
,则标识输入结束。请根据输入的三元组序列建立二叉树的二叉链表,并输出二叉树的广义表形式。
Input:输入为若干行三元组。
Output:输出一行,为二叉树的广义表形式。
Realize:
- 创建二叉树(create):非递归算法,算法设计的思路如下,
- 首先是要考虑到用户未输入有效的三元组,i.e.此时的len<1,那么直接返回NULL;
- 如果有有效三元组序列输入,则先声明一个树结点存储根结点a[0],并将根结点的左右孩子赋为NULL;
- 声明两个树节点指针,innode,outnode,分别指向入队列的结点和出队列的结点;
- 声明队列并初始化,将根结点入队,进入循环;
- 根据三元组序列的特点,需要每次创立新结点将a[i].c存储并入队列;
- 出队列是要根据情况进行,读者可以根据各式各样的三元组序列找到规律,当a[i].f==a[i-1].f时是不需要继续出队列的,注意,此时出来的结点不一定为当前结点的父结点,因为这不一定是完全二叉树,例如:{{^AL},{ABL},{ACR},{CDL},{^^L}},读者可以不难发现第二次出队列的结点为B,而B是没有孩子的,此时的孩子结点是D其父结点为C,需要再出一次队列。当然读者可能想着再用while循环判断出队列的结点是不是当前结点的父结点,其实不必,实质上出队列<=2次必然会出现当前结点的父结点,因此,只需要再添加一个if语句即可;
- 通过当前结点a[i].edge来判断当前结点是outnode的左孩子还是右孩子,相应将outnode的左孩子指针or右孩子指针指向innode,进入下一次循环,直至遍历完三元组序列。
----------------------------------------------------------------------Time---
//加载库;
#include<iostream>;
#include<string>;
#include<cstring>;
using namespace std;
//定义三元组结构体(unite),树结点结构体(Node),队列的结构体(QNode,Queue)。
typedef struct unite
{
char f;//父结点
char c;//孩子
char edge;//左孩子or右孩子
};
typedef struct Node
{
char data;
Node* lc, * rc;
}*BiTree;
typedef struct QNode
{
Node* elem;
QNode* next;
}*QueuePtr;
typedef struct Queue
{
QueuePtr front, rear;
};
note:加载的库和定义的结构题可以统一放在头文件(xxx.h)里,在源文件里直接加载头文件即可(#include"xxx.h";),这样便于程序的管理。
//实现Task的主要功能
//初始化队列
void InitQueue(Queue& Q)
{
Q.front = (QNode*)malloc(sizeof(QNode));
Q.front->next = NULL;
Q.rear = Q.front;
}
//入队
void EnQueue(Queue& Q, Node* node)
{
QueuePtr temp = (QNode*)malloc(sizeof(QNode));
temp->elem = node;
temp->next = NULL;
Q.rear->next = temp;
Q.rear = temp;
}
//判断队列是否为空
bool QueueEmpty(Queue Q)
{
if (Q.front == Q.rear) { return true; }
return false;
}
//出队
void DeQueue(Queue& Q, BiTree& node)
{
if (Q.front == Q.rear) { return; }
QueuePtr temp = Q.front;
Q.front = temp->next;
node = Q.front->elem;
free(temp);
return;
}
//根据三元组序列创建二叉树
BiTree create(unite* a,int len)
{
if (len < 1) { return NULL; }
BiTree T = (Node*)malloc(sizeof(Node));
T->data = a[0].c; T->lc = NULL; T->rc = NULL;
if (len == 1) { return T; }
Node* innode, *outnode = T;
Queue Q;
InitQueue(Q);
EnQueue(Q, outnode);
for (int i = 1; i < len; i++)
{
innode= (Node*)malloc(sizeof(Node));
innode->data = a[i].c; innode->lc = NULL; innode->rc = NULL;
EnQueue(Q,innode);
if (a[i].f == a[i - 1].c || (a[i].f!=a[i-1].f && a[i].f!=a[i-1].c))
{
DeQueue(Q, outnode);
}
if(a[i].f!=outnode->data){DeQueue(Q,outnode);}
if (a[i].edge == 'L') { outnode->lc = innode; }
else { outnode->rc = innode; }
}
return T;
}
//广义表输出二叉树
void print(BiTree T)
{
if (T == NULL) { return; }
cout << T->data;
if (T->lc) { cout << "("; print(T->lc); }
if (!T->lc && T->rc) { cout << "("; }
if (T->rc) { cout << ","; print(T->rc); cout << ")"; }
if (!T->rc && T->lc) { cout << ")"; }
return;
}
//主函数
int main()
{
unite a[100];
int i = 0;
while (1)
{
cin >> a[i].f >> a[i].c >> a[i].edge;
if (a[i].f == '^' && a[i].c == '^') { break; }
i++;
}
BiTree T=create(a,i);
print(T);
return 0;
}
note:考虑到用户在输入“^^L/R”时候,表示输入截止,因此叨叨Chen在设计main函数的时候未将表示停止输入的三元组输入给下一步二叉树的创建中。读者设计其他输入方法时,也请相应调整create(...)函数。
读者们对叨叨Chen设计的算法感觉如何,欢迎大家提出批评和建议喔,叨叨Chen会采取好的建议追加在文章后面。
2020.10.09------------------------------------------------------------------It still comes---