数据结构—二叉树

#include "StdAfx.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


//定义链式存储的二叉树类型
struct TreeNode
{
	char data;//数据域
	struct TreeNode *left;//左域
	struct TreeNode *right;//右域
};
typedef TreeNode *BinTree;



//导入链队列相关
struct Node
{
	BinTree data;//数据域
	struct Node *next;//指针域
};
typedef struct Node *PNode;
struct Queue
{
	PNode f;//f指向头结点
	PNode r;//r指向尾结点
};
typedef struct Queue *LinkQueue;

LinkQueue SetNullQueue()
{
	LinkQueue lqueue;
	lqueue=(LinkQueue)malloc(sizeof(struct Queue));//为队列lqueue分配队列结构体那么大空间
	if(lqueue!=NULL)//分配成功则使f,r指空
	{
		lqueue->f=NULL;
		lqueue->r=NULL;
	}
	else
		printf("alloc failure!");
	return lqueue;
}

int IsNullQueue(LinkQueue lqueue)
{
	return(lqueue->f==NULL);//若头指针指空则为空
}

void InQueue(LinkQueue lqueue,BinTree x)//x入队
{
	PNode p;
	p=(PNode)malloc(sizeof(struct Node));//申请一个结点空间p用于存放输入数据,由p指向
	if(p!=NULL)
	{
		p->data=x;//放入数据至p
		p->next=NULL;
		if(IsNullQueue(lqueue))//若空队列则特殊处理
		{
			lqueue->f=p;
			lqueue->r=p;
		}
		else//不是空队列则按以下操作
		{
			lqueue->r->next=p;//队尾结点指针指向p
			lqueue->r=p;//使队尾指针指向p指向的结点空间p
		}
	}
	else
		printf("alloc failure!");
}

void OutQueue(LinkQueue lqueue)
{
	PNode p;
	if(IsNullQueue(lqueue))//判空
		printf("empty!");
	else
	{
		p=lqueue->f;//使p指向头结点
		lqueue->f=lqueue->f->next;//头指针指向头结点的next所指
		free(p);//释放头结点
	}
}

BinTree FrontQueue(LinkQueue lqueue)
{
	if(lqueue->f==NULL)//判空
	{
		printf("empty!");
		return 0;
	}
	else
		return (lqueue->f->data);//返回头结点数据域
}



//导入链栈相关
typedef int DataType;
typedef struct Node *top;//Node刚才链队列那里已经定义过了所以这里不重复定义了
typedef struct Node *LinkStack;

LinkStack SetNullStack()
{
	LinkStack top=(LinkStack)malloc(sizeof(struct Node));//申请栈顶空间,top指向
	if(top!=NULL)
		top->next =NULL;
	else
		printf("alloc failure");
	return top;//返回栈顶指针
}

int IsNullStack(LinkStack top)
{
	return(top->next == NULL);
}

void Push(LinkStack top,BinTree x)//x进栈
{
	PNode p=(PNode)malloc(sizeof(struct Node));//结点p,用于存放新进栈数据
	if(p!=NULL)
	{
		p->data =x;
		p->next =top->next ;//使p指针域为NULL
		top->next =p;
	}
	else
		printf("alloc failure!\n");
}

void Pop(LinkStack top)
{
	PNode p;
	if(IsNullStack(top))
		printf("empty!\n");
	else
	{
		p=top->next ;//孤立p然后删除
		top->next =p->next ;
		free(p);
	}
}

BinTree top_seq(LinkStack top)
{
	if(IsNullStack(top))
		printf("empty!\n");
	else
		return top->next ->data ;
}



//递归建立二叉树
BinTree create1()
{	
	BinTree bt;
	char ch;
	scanf(" %c",&ch);//输入想放入二叉树根节点的字符,若想让某一个为空则输入@去填充(%前加空格避免将回车字符也作为输入数据)
	if(ch=='@')
		bt=NULL;
	else
	{
		bt=(BinTree)malloc(sizeof(struct TreeNode));
	    bt->data=ch;
	    bt->left=create1();//递归构造左子树
	    bt->right=create1();//递归构造右子树
	}
	return bt;
}



//非递归建立二叉树(要补充成完全二叉树,即除最后一层外其余各层都满的,且最后一层结点从左到右要挨着不能留空隙)
BinTree create2()
{
	LinkQueue queue=SetNullQueue();//建立空队列
	BinTree s,p,bt;
	int count=-1;//设置计数器
	char ch;
	scanf(" %c",&ch);//输入根节点数据
	bt=NULL;
	while(ch!='#')//输入#则结束
	{
		if(ch=='@')//若输入的是@则为虚结点,s指空,计数器加一
		{
			s=NULL;
			count++;
		}
		else//若输入不为虚结点,将ch放入s空间的数据域内,s不指空,计数器加一
		{
			s=(BinTree)malloc(sizeof(struct TreeNode));
			s->data=ch;
			s->left=NULL;
			s->right=NULL;
			count++;		
		}			
		InQueue(queue,s);//将虚结点和新结点入队
		if(count==0)//若计数器为0则s为根节点,bt指向(之后会有很多结点加进去构成树)
			bt=s;
		else
		{
			p=FrontQueue(queue);//p指队头(父节点)
			if(s!=NULL && p!=NULL)//若s及其父节点都不是虚结点
				if(count%2==1)//cout为奇,新结点作为左儿子插入父节点
					p->left=s;
				else
					p->right=s;//为偶则作为右儿子插入父节点
			if(count%2==0)//count为0说明已经处理到右儿子了,即左右两儿子已经处理完成,头结点出队
				OutQueue(queue);
		}
		scanf(" %c",&ch);
	}
	return bt;
}



//深度优先遍历(递归先序遍历)
void preOrder1(BinTree bt)
{
	if(bt)
	{
	    printf("%c",bt->data);//若数不为空则按上左右依次遍历
	    preOrder1(bt->left);
        preOrder1(bt->right);
	}
}



//深度优先遍历(非递归先序遍历)
void preOrder2(BinTree bt)
{
	LinkStack lstack=SetNullStack();//建立空链栈
	BinTree p=bt;
	if(bt)//bt不为空则将其根节点压入链栈
		Push(lstack,bt);
	while(!IsNullStack(lstack))//若连栈不为空
	{
		p=top_seq(lstack);//p取链栈顶元素
		Pop(lstack);//顶元素出栈
		while(p)//当p不为空
		{
			printf("%c",p->data);//输出其数据
			if(p->right)//若右儿子不为空则右进栈
				Push(lstack,p->right);
			p=p->left;//p取其左儿子再次判断
		}
	}
}



//深度优先遍历(递归中序遍历)
void inOrder1(BinTree bt)
{
	if(bt)//若数不为空则按左上右依次遍历
	{
		inOrder1(bt->left);
		printf("%c",bt->data);
		inOrder1(bt->right);
	}
}



//深度优先遍历(非递归中序遍历)
void inOrder2(BinTree bt)
{
    LinkStack lstack=SetNullStack();//建立空链栈
	BinTree p=bt;
	if(bt)//bt不为空则将其根节点压入链栈
		Push(lstack,bt);
	p=p->left;//进入左子树
	while(p||!IsNullStack(lstack))//若栈不为空或者左儿子不为空
	{
		while(p)//进入左子树的左子树
		{
			Push(lstack,p);//左儿子进栈
			p=p->left;
		}
		p=top_seq(lstack);//p取栈顶元素
		Pop(lstack);//栈顶元素出栈
		printf("%c",p->data);//输出栈顶元素
		p=p->right;//判断右子树
	}
}



//深度优先遍历(递归后序遍历)
void postOrder1(BinTree bt)
{
	if(bt)//若数不为空则按左右上依次遍历
	{
		postOrder1(bt->left);
		postOrder1(bt->right);
		printf("%c",bt->data);
	}
}



//深度优先遍历(非递归后序遍历)
void postOrder2(BinTree bt)
{
	LinkStack lstack=SetNullStack();//建立空链栈
	BinTree p=bt;
	while(p||!IsNullStack(lstack))//若栈不为空或者根节点不为空
	{
		while(p)
		{
			Push(lstack,p);//根节点进栈
			p=p->left?p->left:p->right;//若有左儿子则p为左儿子否则为右儿子
		}
		p=top_seq(lstack);//p取栈顶元素
		Pop(lstack);//栈顶元素出栈
		printf("%c",p->data);//输出栈顶元素
		if(!IsNullStack(lstack)&&(top_seq(lstack)->left==p))//从左子树退回进入右子树
			p=top_seq(lstack)->right;
		else
			p=NULL;//从右子树退回上一级
	}
}



//广度优先遍历(层序遍历),根节点开始一层一层往下遍历,同一层按从左到右遍历(使用链队列)
void levelOrder(BinTree bt)
{
	BinTree p;
	LinkQueue queue=SetNullQueue();//创建空队列queue
	if(bt)//bt非空则...
	{
		p=bt;
		InQueue(queue,bt);//根节点入队
		while(!IsNullQueue(queue))//队列不空时执行循环
		{
			p=FrontQueue(queue);
			OutQueue(queue);//根节点出队
			printf("%c",p->data);//打印出队的所存放数据
			if(p->left!=NULL)//左儿子进队
				InQueue(queue,p->left);
			if(p->right!=NULL)//右儿子进队
				InQueue(queue,p->right);
		}
	}
}






//统计二叉树叶子节点数
int LeafNode(BinTree bt)
{
	if(bt==NULL)//若二叉树为空,则叶子结点数为0
		return 0;
	else//若二叉树不为空
	{
		if(bt->left==NULL && bt->right==NULL)//左右儿子为空,则为叶子结点
			return 1;
		else
			return( LeafNode(bt->left) + LeafNode(bt->right) );//遍历左右子树叶子结点数
	}
}



//统计二叉树深度(左右子树深度更高的那个+1)
int deep(BinTree bt)
{
	if(bt==NULL)
		return 0;
	else
	{
		int i=deep(bt->left);//递归计算左子树深度
		int j=deep(bt->right);//递归计算右子树深度
		int max=i>j?i:j;//判断两子树深度更高的那个
		return max+1;//+1
	}
}



//复制一颗二叉树(先复制左子树再复制右子树,最后复制结点数据)
BinTree copy(BinTree bt1)
{
	BinTree bt2;
	if(bt1)
	{
		bt2=(BinTree)malloc(sizeof(struct TreeNode));
		if(bt2)
		{
			bt2->left=copy(bt1->left);//递归复制左子树
			bt2->right=copy(bt1->right);//递归复制右子树
			bt2->data=bt1->data;
			return bt2;
		}
		else
			printf("alloc failure");
	}
	else
		return 0;
}



//主函数
int main()
{
	BinTree bt1=create1();//递归构建一颗二叉树bt1
	preOrder1(bt1);//递归先序遍历
	printf("\n");
	preOrder2(bt1);//非递归先序遍历
	printf("\n");
	inOrder1(bt1);//递归中序遍历
	printf("\n");
	inOrder2(bt1);//非递归中序遍历
	printf("\n");
	postOrder1(bt1);//递归后序遍历
	printf("\n");
	postOrder2(bt1);//非递归后序遍历
	printf("\n");
	levelOrder(bt1);//层序遍历
	printf("\n");
	int i=LeafNode(bt1);//求叶子结点
	printf(" %d",i);
	printf("\n");
	int j=deep(bt1);//求深度
	printf(" %d",j);
	printf("\n");
	BinTree bt2=copy(bt1);//复制二叉树
	preOrder1(bt2);
	printf("\n");
	BinTree bt3=create2();//非递归构建一颗二叉树bt2
	preOrder1(bt3);//递归先序遍历
	printf("\n");
	system("pause");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值