二叉树的链式存储结构 前序 后序 中序 层序遍历操作实现 判断是否完全二叉树

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0
#define YES 1
#define NO 0

typedef int Status;
typedef char ElemType;

typedef struct BiTreeNode{
	ElemType data;
	struct BiTreeNode *lchild, *rchild; 
}BiTreeNode, *BiTree;

typedef struct QueueNode{
	BiTreeNode* binary_tree_node;		//存放的"数据"是二叉树的节点的指针
	struct QueueNode* next;
}QueueNode, *QueueNodePtr;
typedef struct LinkQueue{
	QueueNodePtr front;
	QueueNodePtr rear;
}LinkQueue, *Queue; 


//创建头结点,初始化
Status InitQueue(Queue q){	//注意这里的参数不是Queue *q,因为不是要为q分配空间
				//而是为了q中的front和rear
	q->front = (QueueNode*)malloc(sizeof(struct QueueNode));
	if( !q->front )
		return ERROR;
	q->rear = q->front;
	q->front->next = NULL;
	return OK;
}
//入队
Status EnterQueue(Queue q, BiTreeNode* binaryTreeNode){
	QueueNode* new = (QueueNode*)malloc(sizeof(struct QueueNode));
	if( !new )
		return ERROR;
	new->binary_tree_node = binaryTreeNode;
	new->next = q->rear->next;
	q->rear->next = new;
	q->rear = new;
	return OK;
}
//出队
Status DeleteQueue(Queue q, BiTreeNode** binaryTreeNode){
	if( q->front == q->rear ){
		printf("Queue Empty!\n");
		return ERROR;
	}
	QueueNodePtr t;
	t = q->front->next;
	*binaryTreeNode = t->binary_tree_node;
	q->front->next = t->next;
	free(t);
	if( t == q->rear )
		q->rear = q->front;
	return OK;
}
Status IsQueueEmpty(Queue q){
	return q->front == q->rear ? OK : ERROR;
}

//test Queue
//int main(){
/*					测试  1
 * 如何为指针分配空间,都是4?
 * 下面的测试中出现了结构对齐的问题。
	printf("%d\n",sizeof(ElemType));
	printf("%d\n",sizeof(struct QueueNode*));
	printf("%d\n",sizeof(QueueNode));
	printf("%d\n",sizeof(QueueNodePtr));

	printf("%d\n",sizeof(LinkQueue));
	printf("%d\n",sizeof(Queue));

	int *p;
	printf("%d\n",sizeof(p));
*/

/*             				测试   2 √
 * 原来没有写下面这个函数,导致出错:
			使用指针之前请保证它有合法值。
			main里的三个指针都没有合法值。(from 优快云)
    
		————————————————————————————————————————————————————————————
		Status InitBinaryTreeNode(BiTree *T){
			*T = (BiTreeNode*)malloc(sizeof(struct BiTreeNode));
			if( !*T )
				return ERROR;
			return OK;
		}
		————————————————————————————————————————————————————————————
	LinkQueue* q;
	InitQueue(q);
	BiTree p;
	InitBinaryTreeNode(&p);
	p->data = 'a';
	printf("%c ",p->data);
	BiTree t;
	InitBinaryTreeNode(&t);
	t->data = 'c';
	printf("%c ",t->data);
*/				
/*					测试  3
	LinkQueue* q;
	InitQueue(q);
	BiTreeNode *p,*r;
	InitBinaryTreeNode(&p);
	InitBinaryTreeNode(&r);
	p->data = 'a';
	printf("%c \n",p->data);
	EnterQueue(q,p);
	DeleteQueue(q,&r);
	printf("%c  \n",r->data);

//	return OK;
}
//test Queue end
*/


//初始化二叉树,在要创建二叉树之前调用
Status InitBiTree(BiTree *T){
	*T = NULL;
	return OK;
}
//初始化二叉树节点。单个节点使用的时候调用此函数,不然指针会成为野指针
Status InitBinaryTreeNode(BiTree *T){
	*T = (BiTreeNode*)malloc(sizeof(struct BiTreeNode));
	if( !*T )
		return ERROR;
	return OK;
}
//使用前序遍历的结构进行二叉树的创建
Status CreateBiTree_PreOrder(BiTree* T){
	ElemType c;
	scanf("%c", &c);
	if( ' ' == c ){
		*T = NULL;
	}
	else{
		*T = (BiTree)malloc(sizeof(struct BiTreeNode));
		if( !*T )
			return ERROR;
		(*T)->data = c;
		CreateBiTree_PreOrder(&(*T)->lchild);
		CreateBiTree_PreOrder(&(*T)->rchild);
	}
	return OK;
}
void visit(ElemType c,int level){
	printf("  %c  level is:%d\n", c, level);
}
void visit_2(ElemType c){
	printf("%c  ", c);
}
		//递归的前序遍历二叉树
Status PreOrderTraverse(BiTree T,int level){
	if( T ){
		visit(T->data,level);
		PreOrderTraverse(T->lchild,level + 1);
		PreOrderTraverse(T->rchild,level + 1);
	}
	return OK;
}
		//递归的中序遍历二叉树
Status InOrderTraverse(BiTree T,int level){
	if( T ){
		InOrderTraverse(T->lchild,level + 1);
		visit(T->data,level);
		InOrderTraverse(T->rchild,level + 1);
	}
	return OK;
}
		//递归的后序遍历二叉树
Status PostOrderTraverse(BiTree T,int level){
	if( T ){
		PostOrderTraverse(T->lchild,level + 1);
		PostOrderTraverse(T->rchild,level + 1);
		visit(T->data,level);
	}
	return OK;
}
		//层序遍历二叉树<<非递归>>
//要进行层序遍历需要借助于队列的辅助:先将二叉树的根入队列,然后将其
//出队列,visit。如果该根有左孩子,则入队;如果该根有右孩子,则入队。
//然后出队,对该出队的节点进行以上的相同的访问。直到对空
Status LevelOrderTraverse(BiTree T){
	LinkQueue *q = (LinkQueue*)malloc(sizeof(LinkQueue));    /*有几次代码出错都是
								   因为这个,指针q没有
								   指向。
								  */
	InitQueue(q);
	BiTreeNode* nodePtr;
	InitBinaryTreeNode(&nodePtr);
	EnterQueue(q,T);
	while( !IsQueueEmpty(q) ){
		DeleteQueue(q, &nodePtr);
		visit_2(nodePtr->data);
		if( nodePtr->lchild != NULL ){
			EnterQueue(q,nodePtr->lchild);
		}
		if( nodePtr->rchild != NULL ){
			EnterQueue(q,nodePtr->rchild);
		}
	}
	return OK;
}
//判断二叉树是否为空
Status IsTreeEmpty(BiTree T){
	return T == NULL ? OK : ERROR;
}
//计算二叉树的深度
int BiTreeDepth(BiTree T){
	int i = 0,j = 0;
	if( !T )
		return 0;
	if( T->lchild )
		i = BiTreeDepth(T->lchild);
	else
		i = 0;
	if( T->rchild )
		j = BiTreeDepth(T->rchild);
	else
		j = 0;
	return i>j ? i+1 : j+1;
}
/* 			判断一棵二叉树是否是完全二叉树:
 * 思路: 借助于队列,先将root入队,当队列不为空的时候,出队一个元素。如果节点不为空,
 * 	 则将该节点的左孩子和右孩子入队;如果节点为空,则查找后序出队的元素中是否全
 * 	 是NULL,否则就不是完全二叉树
 * */
Status IsCompleteBinaryTree(BiTree T){
	Queue q = (Queue)malloc(sizeof(struct QueueNode));
	if( !q )
		return ERROR;
	InitQueue(q);
	BiTree node;
	InitBinaryTreeNode(&node);
	EnterQueue(q, T);
	while( IsQueueEmpty(q) != OK ){
		DeleteQueue(q, &node);
		if( node != NULL ){
			EnterQueue(q, node->lchild);
			EnterQueue(q, node->rchild);
		}
		else{
			while( IsQueueEmpty(q) != OK ){
				DeleteQueue(q, &node);
				if( node != NULL )
					return NO;
			}
		}
	}
	return YES;
}
int main(){
	int level = 1;
	BiTree BT;
	InitBiTree(&BT);
	if(IsTreeEmpty(BT))
		printf("Binary is Empty!\n");
	else
		printf("Exist Element in Tree\n");
	printf("Create Binary Tree by PreOrder: ");
	CreateBiTree_PreOrder(&BT);
	printf("PreOrder Traverse: \n");
	PreOrderTraverse(BT,level);
	printf("InOrder Traverse: \n");
	InOrderTraverse(BT,level);
	printf("PostOrder Traverse: \n");
	PostOrderTraverse(BT,level);
	printf("LevelOrder Traverse:  \n");
	LevelOrderTraverse(BT);
	printf("\nthe Depth of Binary is %d\n",BiTreeDepth(BT));

	if(IsCompleteBinaryTree(BT) == YES )
		printf("Complete Binary Tree!\n");
	else
		printf("no-Complete Binary Tree!\n");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值