已知一棵以二叉链表存储的二叉树,按从右到左的次序,利用叶子结点建立一个带头结点的双向链表。
(1)从键盘输入扩展的先序结点数据,建立二叉树。
(2)找叶子结点,找到后从二叉树中删除,然后插入到双向链表中。
(3)要求程序通过一个主菜单进行控制,通过选择菜单项序号调用各功能函数。
[提示]
前序、中序、后序遍历二叉树,访问叶子结点的相对次序都是从左至右。因此,可以采用头插法建立双向链表。
树的二叉链表的结点与双向链表的结点结构相同,只是对两个指针域的解释不同。
typedef struct tree {
char data;
struct tree *Llink;//左儿子 前驱节点
struct tree *Rlink;//右儿子 后继节点
struct tree *Parent;//父节点
} BTNode,*BinTree,DNode,*DoubleList;
测试数据,其扩展的先序遍历序列为ABC..DE.G..F..H..,建立二叉树的遍历叶子结点的次序为:C G F H。 所建立的双向链表为:
L-> <=>H<=>F<=>G<=>C
代码实现
#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#define TRUE 1
#define FALSE 0
#define MAXSIZE 50
#define scanf_s scanf
//二叉树节点
typedef struct tree {
char data;
struct tree *Llink;//左儿子 前驱节点
struct tree *Rlink;//右儿子 后继节点
struct tree *Parent;//父节点
} BTNode,*BinTree,DNode,*DoubleList;
int Select_menu() {
int sn;
printf(" 二叉树打印\n");
printf("-------------------------------------------\n");
printf("1.利用扩展的先序序列建立二叉树\n");
printf("2 找叶子结点,找到后从二叉树中删除,然后插入到双向链表中并打印 。\n");
printf("0.退出系统\n");
printf("===============================\n");
printf(" 请输入0--2: \n");
for (;;) {
scanf_s("%d", &sn);
getchar();
if (sn > 2 || sn < 0)
printf("输入错误,请重新输入:\n");
else
break;
}
return sn;
}
//按照层打印二叉树
void PrintBinTree(BinTree bt) {
if(bt==NULL){
printf("树为空\n");
return;
}
printf("按照层打印二叉树为:");
BinTree p;
BinTree *q[MAXSIZE];
int head = 0, tail = 0;
if (bt) {
tail = (tail + 1) % MAXSIZE;
q[tail] = bt;
}
while (head != tail) {
head = (head + 1) % MAXSIZE;
p = q[head];
printf("%c ", p->data);
if (p->Llink != NULL) {
tail = (tail + 1) % MAXSIZE;
q[tail] = p->Llink;
}
if (p->Rlink != NULL) {
tail = (tail + 1) % MAXSIZE;
q[tail] = p->Rlink;
}
}
printf("\n");
return;
}
//打印循双向链表
void PrintDoubleList(DoubleList dl) {
if(dl==NULL || dl->Rlink==NULL){
printf("双向链表为空\n");
return;
}
printf("双向环链为:");
//遍历链表,表头不存值
while (dl->Rlink) {
dl = dl->Rlink;
printf("%c ", dl->data);
}
printf("\n");
return;
}
//按照层打印二叉树后打印循双向链表
void printAll(BinTree bt,DoubleList dl){
PrintBinTree(bt);
PrintDoubleList(dl);
}
//叶子节点个数
int LeafCount(BTNode* pnode)
{
static int count;
if (pnode != NULL)
{
if (pnode->Llink == NULL && pnode->Rlink == NULL)
{
count++;
}
LeafCount(pnode->Llink);
LeafCount(pnode->Rlink);
}
return count;
}
//计算二叉树深度
int treeDepth(BTNode *t) {
int deep = 0;
int left = 0;
int right = 0;
if (t == NULL) {
return deep;
}
left = treeDepth(t->Llink);
right = treeDepth(t->Rlink);
deep = right > left ? right : left;
deep++;
return deep;
}
/*
TODO: 从键盘输入扩展的先序结点数据,建立二叉树。
功能描述:从键盘输入扩展的先序结点数据,建立二叉树,空节点用.表示输入
参数说明:bt-BinTree指针 表示树根
返回值说明:无
比如输入:ACE.F...D.B.G..
对应的树结构为
A
C D
E B
F G
*/
void CreateTree(BinTree *bt) {
char ch;
ch=getchar();
if(ch=='.') *bt=NULL;
else
{
*bt=(BinTree)malloc(sizeof(BTNode));
if(*bt==NULL) return 0;
(*bt)->data=ch;
CreateTree(&(*bt)->Llink);
CreateTree(&(*bt)->Rlink);
}
return;
}
/*
TODO: 设置二叉树父亲节点。
功能描述:给各个结点的parent赋值,设置成父亲节点。
参数说明:p-BinTree指针 表示当前节点
q-BinTree指针 表示当前节点的父节点
返回值说明:无
*/
void setParent(BinTree p,BinTree q)
{
if(p==NULL) return ;
else{
if(p->Llink!=NULL) p->Llink->Parent=p;
if(p->Rlink!=NULL) p->Rlink->Parent=p;
}
setParent(p->Llink,q);
setParent(p->Rlink,q);
}
/*
已知一棵以二叉链表存储的二叉树,按从右到左的次序,利用叶子结点建立一个带头结点的双向链表。
功能描述:建立双向链表,调用LeafTraversal遍历二叉树,删除叶子节点,用头插法插入到双向链表中,调用printAll打印二叉树和双向链表
参数说明:bt-BinTree指针 表示树根
dl-DoubleList指针 表示链表
返回值说明:无
比如输入:其扩展的先序遍历序列为ABC..DE.G..F..H..,建立二叉树的遍历叶子结点的次序为:C G F H。 所建立的双向链表为:
L-> <=>H<=>F<=>G<=>C
*/
void CreateDListFromLeaves(BinTree bt,DoubleList dl){
//新建带头结点的双向链表
dl = (DoubleList)malloc(sizeof(DNode));
dl->data=0;
dl->Llink=NULL;
dl->Rlink=NULL;
//查出叶子节点个数
int leaves = LeafCount(bt);
int depth = treeDepth(bt);
if(leaves == 0 || depth==1){
printAll(bt,dl);
return;
}
//从二叉树中删除,然后用头插法插入到双向链表中
LeafTraversal(bt,dl,2);
//遍历二叉树叶子节点,用头插法插入到双向链表中
printAll(bt,dl);
}
/*
TODO: 遍历二叉树,删除叶子节点,并插入到双向链表
功能描述:找叶子结点,找到后从二叉树中删除(删除是通过该节点的父指针找到父节点,然后根据是左子树还是右子树设置父节点的左或右儿子为NULL),
然后用头插法插入到双向链表中。
参数说明:pnode-BTNode指针 表示树根
dl-DoubleList指针 表示链表
LeftOrRight-int 0 表示遍历左子树 1 表示遍历右子树 2 表示根
返回值说明:无
比如输入:其扩展的先序遍历序列为ABC..DE.G..F..H..,建立二叉树的遍历叶子结点的次序为:C G F H。 所建立的双向链表为:
L-> <=>H<=>F<=>G<=>C
*/
void LeafTraversal(BTNode* pnode,DoubleList dl,int LeftOrRight)
{
if(NULL==pnode) return;
LeafTraversal(pnode->Llink,dl,0);
if(pnode->Llink==NULL&&pnode->Rlink==NULL&&pnode->data!='P')
{
if(LeftOrRight==0) pnode->Parent->Llink=NULL;
else if(LeftOrRight==1) pnode->Parent->Rlink=NULL;
DoubleList s;
s = (DoubleList)malloc(sizeof(DNode));
s->data=pnode->data;
s->Rlink=dl->Rlink;
dl->Rlink=s;
}
LeafTraversal(pnode->Rlink,dl,1);
return;
}
int main(void) {
BinTree bt = NULL;
DoubleList dl = NULL;
BinTree *btnull = NULL;
for (;;) {
switch (Select_menu()) {
case 1:
printf("请使用前序遍历的方式输入字符串,用.代替空值\n");
CreateTree(&bt);
setParent(bt,btnull);
break;
case 2:
CreateDListFromLeaves(bt,dl);
break;
case 0:
printf("再见!\n");
free(bt);
free(dl);
return 0;
}
}
}