有关树的基本算法和练习题。

今天我来分享一下有关树的一些简单应用。

首先我们需要三个头文件:tree.h   queue.h   stack.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<Windows.h>

typedef char DataType;
typedef struct TreeNode{
	struct TreeNode *lchild;
	struct TreeNode *rchild;
	DataType data;
} TreeNode;
TreeNode *CreateNode(DataType data)
{
	TreeNode *pRoot=(TreeNode *)malloc(sizeof(TreeNode));
	pRoot->data=data;
	pRoot->lchild=0;
	pRoot->rchild=0;
}

TreeNode *CreatTree(DataType preOrder[], int size, int *pIndex)
{
	TreeNode *pRoot = CreateNode(preOrder[*pIndex]);
	if (*pIndex >= size) {
		return NULL;
	}

	if (preOrder[*pIndex] == '#') {
		*pIndex += 1;
		return NULL;
	}
	
	*pIndex += 1;	// 用了 1 个字符
	pRoot->lchild = CreatTree(preOrder, size, pIndex);
	pRoot->rchild = CreatTree(preOrder, size, pIndex);

	return pRoot;
}


#pragma once

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

typedef TreeNode* DataType3;

typedef struct Node{
	DataType3 data;
	struct Node *Next;
}Node;

typedef struct Queue{
	Node *pFront;
	Node *pRear;
	int size;
}Queue;
//队列初始化。
void QueueInit(Queue *q)
{
	assert(q);
	q->pFront=q->pRear=NULL;
	q->size=0;
}
//队列的入队。
void QueuePush(Queue *pq,TreeNode* data)
{
	Node *pNew=(Node *)malloc(sizeof(Node));
	pq->size++;
	assert(pq);
	pNew->data=data;
	pNew->Next=NULL;

	if(pq->pRear==NULL)
	{
		pq->pRear=pNew;
		pq->pFront=pNew;
	}
	else{
		pq->pRear->Next=pNew;
		pq->pRear=pNew;
	}
}

//出队
void QueuePop(Queue *pq)
{
	Node *p=pq->pFront;
	assert(pq);
	if(pq->pFront==NULL)
	{
		pq->pRear=NULL;
	}
	else{
	pq->size--;
	pq->pFront=p->Next;
	free(p);
	}
}

//取头结点
DataType3 QueuepFront(Queue *pq)
{
	assert(pq);
	assert(pq->size>0);
	return pq->pFront->data;
}
//求是否为空队列。1为空,0不为空。
int QueueIsEmpty(Queue *pq)
{
	assert(pq);
	return pq->size==0?1:0;
}
//求队列元素个数
int QueueSize(Queue *pQ)
{
	return pQ->size;
}



#pragma once
#include"tree.h"
#include<stdio.h>
#include<assert.h>
#include<Windows.h>
typedef TreeNode* DataType2;
typedef struct Stack{
	DataType2 array[10];
	int top;
}Stack;

void StackInit(Stack *s)
{
	assert(s);
	s->top=0;
}

void StackPush(Stack *s,DataType2 x)
{
	assert(s);
	assert(s->top<100);
	s->array[s->top++]=x;
}

void StackPop(Stack *s)
{
	assert(s);
	assert(s->top>0);
	s->top--;
}

DataType2 StackTop(Stack *s)
{
	assert(s);
	return s->array[s->top-1];
}
//1表示空,0表示没空。
int StackIsEmpty(Stack *s)
{
	assert(s);
	return s->top==0?1:0;
}

接下来是基本算法:

#include"stack.h"
#include"tree.h"
#include"queue.h"

//先序递归法。
void PreOrder(TreeNode *pRoot)
{
	if(pRoot==NULL)                 //当根节点为空时,直接返回。
	{
		return;
	}
	printf("%c",pRoot->data);       //前序打印顺序为根、左子树、右子树。
	PreOrder(pRoot->lchild);
	PreOrder(pRoot->rchild);
}
//先序非递归法。
void PreOrderLoop(TreeNode *pRoot)
{
	TreeNode *pCur=pRoot;                      //定义两个变量。
	TreeNode *pTop=NULL;
	Stack s;                                   //定义一个栈。
	StackInit(&s);                             //初始化栈。
	while(pCur!=NULL ||  !(StackIsEmpty(&s)))      
	{
		while(pCur!=NULL)                    //当根节点不为空时,直接打印,然后入栈,并往它的左孩子走。
		{
			printf("%c",pCur->data);
			StackPush(&s,pCur);
			pCur=pCur->lchild;
		}
		pTop=StackTop(&s);                  //出栈。
		StackPop(&s);                       //求栈顶元素。
		pCur=pTop->rchild;                  //在走向右孩子。
	}
}

//中序递归法
void InOrder(TreeNode *pRoot)
{
	if(pRoot==NULL)
	{
		return;
	}
	InOrder(pRoot->lchild);                //中序打印顺序为左子树、根、右子树。
	printf("%c",pRoot->data);
	InOrder(pRoot->rchild);
}

//中序非递归法
void InOrderLoop(TreeNode *pRoot)           //与前序差不多,只是它要先入栈,先输出左孩子,在输出根节点,最后输出右孩子。
{
	TreeNode *pCur=pRoot;
	TreeNode *pTop=NULL;
	Stack s;
	StackInit(&s);

	while(pCur!=NULL ||  !(StackIsEmpty(&s)))
	{
		while(pCur!=NULL)
		{
			StackPush(&s,pCur);
			pCur=pCur->lchild;
		}
		pTop=StackTop(&s);
		StackPop(&s);
		printf("%c",pTop->data);
		pCur=pTop->rchild;
	}
}
//后序递归遍历
void BackOrder(TreeNode *pRoot)
{
	if(pRoot==NULL)
	{
		return;
	}
	BackOrder(pRoot->lchild);                   //后序先遍历左孩子,在右孩子,最后根节点。
	BackOrder(pRoot->rchild);
	printf("%c",pRoot->data);
}

//后序非递归遍历。
void BackOrderLoop(TreeNode *pRoot)
{
	TreeNode *pCur=pRoot;
	TreeNode *pTop=NULL;
	TreeNode *last=NULL;
	Stack s;
	StackInit(&s);
	while(pCur!=NULL || !(StackIsEmpty(&s)))
	{
		while(pCur!=NULL)
		{
			StackPush(&s,pCur);
			pCur=pCur->lchild;
		}

		pTop=StackTop(&s);                            //以上与中序一样。
		if(pTop->rchild==NULL || pTop->rchild==last)  //当栈顶元素的右孩子为空,或者为已经遍历过的节点。
		{
			StackPop(&s);                             //出栈,打印,并令遍历过的节点为此时的栈顶元素,继续循环。
			printf("%c",pTop->data);
			last=pTop;
			continue;
		}
		pCur=pTop->rchild;                            //遍历它的右孩子。
	}
}


//层序遍历
void LeveOrder(TreeNode *pRoot)
{
	Queue q;                      //定义一个队列。
	TreeNode *p;
	if(pRoot==NULL)               //如果根节点为空,则返回。
	{
		return;
	}
	QueueInit(&q);
	QueuePush(&q,pRoot);          //初始化并入队。
	while(QueueIsEmpty(&q)==0)        //当队列不为空时
	{
		p=QueuepFront(&q);          //求队首元素。
		printf("%c ",p->data);      //打印。
		if(p->lchild!=NULL)         //如果它的左孩子不为空,入队。
		{
			QueuePush(&q,p->lchild);
		}
		if(p->rchild!=NULL)         //如果它的右孩子不为空,入队。
		{
			QueuePush(&q,p->rchild);
		}
		QueuePop(&q);               //出队.
	}
	printf("\n");
}

然后是一些应用:

//求二叉树的深度。 
int TreeHighth(TreeNode *pRoot)
{
	int left;                       //定义两个变量。
	int right;
	if(pRoot==NULL)                 //当根节点为空时,返回0.
	{
		return 0;
	}
	if(pRoot->lchild==NULL && pRoot->rchild==NULL) //如果为叶子结点,返回1.
	{
		return 1;
	}
	left=TreeHighth(pRoot->lchild);        //否则递归左右子树。
	right=TreeHighth(pRoot->rchild);
	return left>right?left+1:right+1;      //返回大的那边的子树加1.
}


//求二叉树叶子结点个数。

int Leaves(TreeNode *pRoot)
{
	if(pRoot==NULL)
	{
		return 0;
	}
	if(pRoot->lchild==NULL && pRoot->rchild==NULL)
	{
		return 1;
	}
	return Leaves(pRoot->lchild) + Leaves(pRoot->rchild);    //就是返回左子树的叶子数与右子树的叶子数之和。
}

//求二叉树所有节点数

int All(TreeNode *pRoot)
{
	if(pRoot==NULL)
	{
		return 0;
	}
	if(pRoot->lchild==NULL && pRoot->rchild==NULL)
	{
		return 1;
	}
	return (All(pRoot->lchild)+All(pRoot->rchild)+1);   //返回左右子树之和再加1.
}

//求第k层节点个数。

int Kcount(TreeNode *pRoot,int k)
{
	if(pRoot==NULL)
	{
		return 0;
	}
	if(k==1)
	{
		return 1;
	}
	return Kcount(pRoot->lchild,k-1)+Kcount(pRoot->rchild,k-1);
}

//查找二叉树上的节点。
TreeNode *Find(TreeNode *pRoot,DataType data)
{
	TreeNode *p;
	if(pRoot==NULL)
	{
		return NULL;
	}
	if(pRoot->data=data)
	{
		return pRoot;
	}
	p=Find(pRoot->lchild,data);
	if(p!=NULL)
	{
		return p;
	}
	return Find(pRoot->rchild,data);
}
//是否是完全二叉树。1:是。0:不是。
int IsComplex(TreeNode *pRoot)
{
	Queue q;                  //定义一个队列,并初始化。
	TreeNode *p=NULL;
	QueueInit(&q);
	if(pRoot==NULL)           //如果根节点为空返回1.
	{
		return 1;
	}
	if(pRoot->lchild==NULL && pRoot->rchild==NULL) //如果为叶子结点返回1.
	{
		return 1;
	}
	QueuePush(&q,pRoot);             //先进队。
	while(QueueIsEmpty(&q)==0)       //当队列不为空时,取队首元素,如果为空就退出,否则入队它的左右子树。最后出队。
	{
		p=QueuepFront(&q);
		if(p==NULL)
		{
			break;
		}
		QueuePush(&q,p->lchild);
		QueuePush(&q,p->rchild);
		QueuePop(&q);
	}

	while(QueueIsEmpty(&q)==0)         //当队列不为空时,如果队首元素还是不为空,则它就不是完全二叉树。
	{
		p=QueuepFront(&q);
		if(p!=NULL)
		{
			return 0;
		}
		QueuePop(&q);
	}
	return 1;
}


最后是调试程序:

int main()
{
	DataType *preOrder = "ABD##G##CE##F";
	int index = 0;
	TreeNode *pRoot = CreatTree(preOrder, strlen(preOrder), &index);
	printf("前序为:");
	PreOrder(pRoot); printf("\n");
	printf("中序为:");
	InOrder(pRoot); printf("\n");
	printf("后序为:");
	BackOrder(pRoot); printf("\n");

	printf("前序为:");
	PreOrderLoop(pRoot);printf("\n");
	printf("中序为:");
	InOrderLoop(pRoot);printf("\n");
	printf("后序为:");
	BackOrderLoop(pRoot);printf("\n");
	printf("层序为:");
	LeveOrder(pRoot);printf("\n");

	printf("树的高度为%d\n",TreeHighth(pRoot));
	printf("二叉树的叶子结点为%d\n",Leaves(pRoot));
	printf("二叉树的总结点为%d\n",All(pRoot));
	printf("二叉树第K层的节点数为%d\n",Kcount(pRoot,3));

	printf("%d\n",IsComplex(pRoot));
	system("pause");
	return 0;
}



这就是调试结果,以上就是我分享的内容,谢谢观看。

猜你喜欢

转载自blog.csdn.net/ymk1507050118/article/details/81029062