中国大学MOOC-陈越、何钦铭-数据结构-习题解答-03 树(上)

1. 03-树1 树的同构 (25 分)

【题目描述】

题目链接

【题解】

本题利用了老师讲解的思路,主要包括两个点:

  • 静态链表:用链表的逻辑思维和数组的存储结构来建立一个树,这称为静态链表,这种方式既有链表的灵活性,又有数组存储的简单性,在一些题目中很实用;
  • 递归思想:因为树是递归定义得到的,所以用递归思想来解决树的问题很对口。在判断树的同构时就是用递归来实现的,免去了交换左右树的繁琐,用其他方法不容易解决。

代码如下:

#include <stdio.h>
#include <stdbool.h>
#define ElementType char
#define Tree int
#define MaxSize 10
#define Null -1
struct TreeNode {
	ElementType Data;
	Tree Left;
	Tree Right; 
}; 
struct TreeNode T1[MaxSize],T2[MaxSize];
Tree BuildTree(struct TreeNode T[]);
bool Isomorphic ( Tree R1, Tree R2 );

int main(void)
{
	Tree R1,R2;
	R1=BuildTree(T1);
	R2=BuildTree(T2);
	if (Isomorphic(R1,R2))
		printf("Yes\n");
	else
		printf("No\n");
	
	return 0;
}
Tree BuildTree(struct TreeNode T[])
{
	Tree Root=Null;
	int N,tag[MaxSize];
	char cl,cr;
	for (int i=0;i<MaxSize;i++) {
		tag[i]=0;
	}
	scanf("%d\n",&N);
	for (int i=0;i<N;i++) {
		scanf("%c %c %c\n",&T[i].Data,&cl,&cr);
		if (cl!='-') {
			T[i].Left=cl-'0';
			tag[T[i].Left]=1;
		}
		else 
			T[i].Left=Null;
		if (cr!='-') {
			T[i].Right=cr-'0';
			tag[T[i].Right]=1;
		}
		else 
			T[i].Right=Null;
	}
	for (int i=0;i<N;i++) {
		if (tag[i]==0) {
			Root=i;
			break;
		}
	}
	return Root;
}
bool Isomorphic(Tree R1,Tree R2)
{
	/*先判断根结点*/
	if (R1==Null && R2==Null)		//根结点均为空 
		return true;
	if ((R1==Null && R2!=Null) || (R1!=Null && R2==Null)) //根结点一个为空,一个不空 
		return false;
	if (T1[R1].Data != T2[R2].Data)		//根结点均不为空但元素不相等 
		return false;
	/*递归判断根结点的左右子树(此时根结点必然相等)*/ 
	if (T1[R1].Left==Null && T2[R2].Left==Null)			//左子树均为空 
		return Isomorphic(T1[R1].Right,T2[R2].Right);
	if ((T1[R1].Left!=Null && T2[R2].Left!=Null) && (T1[T1[R1].Left].Data==T2[T2[R2].Left].Data))	       //不用交换左右子树 
		return (Isomorphic(T1[R1].Left,T2[R2].Left) && Isomorphic(T1[R1].Right,T2[R2].Right));
	else											   //需要交换左右子树 
		return (Isomorphic(T1[R1].Left,T2[R2].Right) && Isomorphic(T1[R1].Right,T2[R2].Left));
}

2. 03-树2 List Leaves (25 分)

【题目描述】

题目链接

【题解】

主要考查了树的层序创建和层序遍历、叶子结点的判断。树的层序创建和层序遍历需要借助队列。

解题步骤是:

  • 读入数据并找到根结点(FindHead函数);
  • 层序创建一个树(CreateBinTree函数);
  • 层序遍历输出叶结点(LevelorderTravelsal函数).
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> 
#define NoInfo -1
struct Node {
	int left;
	int right;
};
int FindHead(struct Node a[],int N);
/*树*/ 
#define ElementType_Tree int
typedef struct TreeNode* BinTree;
struct TreeNode {
	ElementType_Tree Data;
	BinTree Left;
	BinTree Right;
};
BinTree CreateBinTree(struct Node a[],ElementType_Tree head,int N);
void LevelorderTravelsal(BinTree BT);
/*队列*/ 
#define ElementType_Queue BinTree
typedef struct QueueNode* PtrtoQNode;
struct QueueNode {
	ElementType_Queue Data;
	PtrtoQNode Next;
};
typedef struct QNode* Queue;
struct QNode {
	PtrtoQNode Front,Rear;		//队列的头尾指针 
};
Queue CreateQueue();
bool IsEmPty(Queue Q);
bool AddQ(Queue Q,ElementType_Queue X);
ElementType_Queue DeleteQ(Queue Q);
/*主函数*/ 
int main(void)
{
	int N;
	scanf("%d",&N);
	getchar();                      	//读入换行符,否则不能正确输入 
	struct Node a[N];
	int head;
	head=FindHead(a,N);
	BinTree BT=CreateBinTree(a,head,N);
	LevelorderTravelsal(BT); 
	
	return 0;
}
int FindHead(struct Node a[],int N)		/*找到根节点*/ 
{
	int head,tag[N];
	char Data1,Data2;
	for (int i=0;i<N;i++) {
		tag[i]=1;
	}
	for (int i=0;i<N;i++) {
		scanf("%c %c",&Data1,&Data2);
		getchar();						//读入换行符,否则不能正确输入 
		if (Data1!='-') {
			a[i].left=Data1-'0';
			tag[a[i].left]=0;
		}	
		else
			a[i].left=-1;
		if (Data2!='-') {
			a[i].right=Data2-'0';
			tag[a[i].right]=0;
		}	
		else
			a[i].right=-1;
	}
	for (int i=0;i<N;i++) {
		if (tag[i]==1) 
			head=i;
	}
	return head;
}
/*二叉树的层序创建*/
BinTree CreateBinTree(struct Node a[],ElementType_Tree head,int N)
{
	ElementType_Tree Data;
	BinTree BT,T;
	Queue Q=CreateQueue();
	
	Data=head;
	if (Data!=NoInfo) {
		BT=(BinTree)malloc(sizeof(struct TreeNode));
		BT->Data=Data;
		BT->Left=BT->Right=NULL;
		AddQ(Q,BT);
	} else
		return NULL;
	while (!IsEmPty(Q)) {
		T=DeleteQ(Q);
		Data=a[T->Data].left;
		if (Data!=NoInfo) {
			T->Left=(BinTree)malloc(sizeof(struct TreeNode));
			T->Left->Data=Data;
			T->Left->Left=T->Left->Right=NULL;
			AddQ(Q,T->Left);
		} else 
			T->Left=NULL;
		Data=a[T->Data].right;
		if (Data!=NoInfo) {
			T->Right=(BinTree)malloc(sizeof(struct TreeNode));
			T->Right->Data=Data;
			T->Right->Left=T->Right->Right=NULL;
			AddQ(Q,T->Right);
		} else 
			T->Right=NULL;
	}
	return BT;
}
void LevelorderTravelsal(BinTree BT)	/*使用队列的层序遍历 */
{
	Queue Q;
	BinTree T;
	int tag=1;
	
	if (!BT)
		return;
	Q=CreateQueue();
	AddQ(Q,BT);
	while (!IsEmPty(Q)) {
		T=DeleteQ(Q);
		if (!T->Left && !T->Right) {	//叶子的条件
			if (tag) {
				printf("%d",T->Data);
				tag=0;
			} else
				printf(" %d",T->Data);
		}    	 
		if (T->Left)
			AddQ(Q,T->Left);
		if (T->Right)
			AddQ(Q,T->Right);
	}	
}
/*队列函数*/ 
Queue CreateQueue()
{
	Queue Q;
	Q=(Queue)malloc(sizeof(struct QueueNode));
	Q->Front=Q->Rear=NULL;
	
	return Q;
}
bool IsEmPty(Queue Q)
{
	return (Q->Front==NULL);
}
bool AddQ(Queue Q,ElementType_Queue X)
{
	PtrtoQNode temp=(PtrtoQNode)malloc(sizeof(struct QueueNode));
	temp->Data=X;
	temp->Next=NULL;
	if (Q->Front==NULL && Q->Rear==NULL)
		Q->Front=Q->Rear=temp;
	else {
		Q->Rear->Next=temp;
		Q->Rear=temp;
	}	
	return true;
}
#define ERROR NULL
ElementType_Queue DeleteQ(Queue Q)
{
	PtrtoQNode FrontCell;
	ElementType_Queue FrontElem;
	
	if (IsEmPty(Q)) {
		return ERROR;
	} else {
		FrontCell=Q->Front;
		if (Q->Front==Q->Rear)
			Q->Front=Q->Rear=NULL;
		else 
			Q->Front=Q->Front->Next;
		FrontElem=FrontCell->Data;
		free(FrontCell);
		return FrontElem;
	}
}

3. 03-树3 Tree Traversals Again (25 分)

【题目描述】

题目链接

【题解】

这道题既有树也有堆栈,解题思路用的是:模拟实现。建立一个堆栈,模拟输入给出的push和pop操作,按照此顺序去中序建立一个树,之后按照后序遍历的方式访问这颗树即可。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#define ElementType_Tree int  
typedef struct TreeNode* BinTree;
struct TreeNode {
	ElementType_Tree Data;
	BinTree Left;
	BinTree Right;
};
BinTree BuildTree();
void PostorderTravelsal(BinTree BT);
int cnt=1;
/*堆栈代码块*/
#include <stdbool.h>
#define ElementType_Stack BinTree
#define ERROR NULL
typedef struct StackNode* Stack;
struct StackNode {
	ElementType_Stack Data;
	Stack Next;
}; 
Stack CreateStack();
bool IsEmpty(Stack S);
bool Push(Stack S,ElementType_Stack X);
ElementType_Stack Pop(Stack S);
/*主函数*/
#define size 5
#include <string.h>
int main(void)
{
	BinTree BT;
	//Stack S=CreateStack();
	BT=BuildTree();
	PostorderTravelsal(BT);
	
	return 0;
}
BinTree BuildTree()
{
	int N,i,Data;
	BinTree BT,T;
	char str[size];
	Stack S=CreateStack();
	
	scanf("%d",&N);
	for (i=0;i<2*N;i++) {
		scanf("%s",str);
		if (strcmp(str,"Push")==0) {
			scanf("%d",&Data);
			if (i==0) {
				BT=(BinTree)malloc(sizeof(struct TreeNode));
				BT->Data=Data;
				BT->Left=BT->Right=NULL;
				Push(S,BT);
				T=BT;
			} else {
				if (T->Left==NULL) {
					T->Left=(BinTree)malloc(sizeof(struct TreeNode));
					T->Left->Data=Data;
					T->Left->Left=T->Left->Right=NULL;
					T=T->Left;
					Push(S,T);
				} else if (T->Right==NULL) {
					T->Right=(BinTree)malloc(sizeof(struct TreeNode));
					T->Right->Data=Data;
					T->Right->Left=T->Right->Right=NULL;
					T=T->Right;
					Push(S,T);
				}
			}
		} else if (strcmp(str,"Pop")==0) {
			T=Pop(S);
		}
	}
	return BT;
}
void PostorderTravelsal(BinTree BT)		/*后序遍历*/ 
{
	if (BT) {
		PostorderTravelsal(BT->Left);
		PostorderTravelsal(BT->Right);
		if (cnt==1) {
			printf("%d",BT->Data);
			cnt=0;
		} else
			printf(" %d",BT->Data);
	}
}

Stack CreateStack()
{
	Stack S;
	S=(Stack)malloc(sizeof(struct StackNode));
	S->Next=NULL;             //带头结点的链表,头结点数据域置空 
	
	return S;
}
bool IsEmpty(Stack S)
{
	return (S->Next==NULL);
}
bool Push(Stack S,ElementType_Stack X)
{
	Stack temp;
	temp=(Stack)malloc(sizeof(struct StackNode));
	temp->Data=X;
	temp->Next=NULL;
	
	temp->Next=S->Next;
	S->Next=temp;
	return true;
}
ElementType_Stack Pop(Stack S)
{
	Stack temp;
	ElementType_Stack Top_data;
	if (IsEmpty(S)) {
		return ERROR;
	} else {
		temp=S->Next;
		Top_data=temp->Data;
		S->Next=temp->Next;
		free(temp);
		return Top_data;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值