【数据结构】二叉树的基本操作

  本篇主要实现了二叉树的创建、前中后序遍历(递归以及非递归)、层序遍历、判断一个二叉树是否是完全二叉树、查找第一次匹配的结点以及求叶子结点个数和树的高度等等。

头文件

1、tree.h

# ifndef __TREE_H__
# define __TREE_H__

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

# define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))

typedef char DataType;

typedef struct BinaryTreeNode
{
	DataType data;
	struct BinaryTreeNode * pLeft;
	struct BinaryTreeNode * pRight;
}BTNode;

BTNode * BuildTree(DataType array[], int size, int * pIndex); // 生成二叉树
void PreOrder(BTNode * pRoot); // 前序遍历递归
void PreOrderLoop(BTNode * pRoot); // 前序遍历非递归
void InOrder(BTNode * pRoot); // 中序遍历递归
void InOrderLoop(BTNode * pRoot); // 中序遍历非递归
void PostOrder(BTNode * pRoot); // 后序遍历递归
void PostOrderLoop(BTNode * pRoot); // 后序遍历非递归
void LevelOrder(BTNode * pRoot); // 层序遍历
int TreeSize(BTNode * pRoot); // 树的结点数
int LeafSize(BTNode * pRoot); // 叶子结点数
int GetKSize(BTNode * pRoot, int k); // 求第k层结点数
int GetHeight(BTNode * pRoot); // 树的高度
BTNode * Find(BTNode * pRoot, DataType data); // 查找第一次匹配的结点,若找到该结点则返回结点地址,反之则返回NULL
int IsComplete(BTNode * pRoot); // 判断当前二叉树是否是完全二叉树,假如是则返回1,反之则返回0

# endif // __TREE_H__	

2、queue.h

# ifndef __QUEUE_H__
# define __QUEUE_H__

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

typedef void * QDataType;

typedef struct QNode
{
	QDataType data;
	struct QNode * pNext;
}QNode, * pQNode;

typedef struct Queue
{
	pQNode pFront;
	pQNode pRear;
	int size;
}Queue, * pQueue;

void QueueInit(pQueue pQ); // 队列的初始化
void QueuePush(pQueue pQ, QDataType data); // 入队
void QueuePop(pQueue pQ); // 出队
QDataType QueueFront(pQueue pQ); // 取队首元素
int QueueIsEmpty(pQueue pQ); // 队列判空
void QueueDestory(pQueue pQ); // 销毁队列

# endif // __QUEUE_H__

3、stack.h

# ifndef _STACK_H__
# define _STACK_H__

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

# define MAX_SIZE (10)

typedef void * SDataType;

typedef struct Stack
{
	SDataType data[MAX_SIZE]; // 存放栈的元素
	int top; // 用于栈顶指针,类似于游标卡尺的游标
}Stack, *pStack;

void StackInit(pStack pS); // 栈的初始化
void StackPush(pStack pS, SDataType data); // 入栈
void StackPop(pStack pS); // 出栈
SDataType StackTop(pStack pS); // 获取栈顶元素
int StackIsEmpty(pStack pS); // 判断栈是否为空
void StackDestory(pStack pS); // 栈的销毁

# endif // _STACK_H__

难点剖析

1、如何判断一个二叉树是否是完全二叉树

  层序遍历完全二叉树时,可以发现NULL接连出现(并且队列中只剩下NULL),假如该树不是完全二叉树,可以发现第一次出现NULL后,后边还会出现其他非NULL的结点,这时候只需要去判断队列中的元素是否全为NULL即可。

2、注意事项

  层序遍历考虑用队列,非递归的前中后序遍历考虑用栈。

源代码

1、queue.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:queue.c
* 功能:链式队列内部实现细节
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年6月6日22:30:25
*/

# include "queue.h"

/*
*	函数名称:QueueInit
*
*	函数功能:队列的初始化
*
*	入口参数:pQ
*
*	出口参数:void
*
*	返回类型:void
*/

void QueueInit(pQueue pQ)
{
	assert(NULL != pQ);

	pQ->pFront = pQ->pRear = NULL;
	pQ->size = 0;

	return;
}

/*
*	函数名称:QueuePush
*
*	函数功能:入队
*
*	入口参数:pQ, data
*
*	出口参数:void
*
*	返回类型:void
*/

void QueuePush(pQueue pQ, QDataType data)
{
	pQNode pNewNode = NULL;

	assert(NULL != pQ);

	pNewNode = (pQNode)malloc(sizeof(QNode));

	assert(NULL != pNewNode);

	pQ->size++;

	if (NULL == pQ->pFront)
	{
		pQ->pFront = pQ->pRear = pNewNode;
		pNewNode->data = data;
		pQ->pRear->pNext = NULL;
	}
	else
	{
		pNewNode->data = data;
		pNewNode->pNext = NULL;
		pQ->pRear->pNext = pNewNode;
		pQ->pRear = pNewNode;
	}

	return;
}

/*
*	函数名称:QueuePop
*
*	函数功能:出队
*
*	入口参数:pQ
*
*	出口参数:void
*
*	返回类型:void
*/

void QueuePop(pQueue pQ)
{
	pQNode pDelNode = NULL;

	assert(NULL != pQ);
	assert(NULL != pQ->pFront);

	pQ->size--;

	pDelNode = pQ->pFront;
	pQ->pFront = pDelNode->pNext;
	free(pDelNode);

	if (NULL == pQ->pFront)
	{
		//pQ->pRear = NULL;
		pQ->pRear = pQ->pFront;
	}
	else
	{
		;	
	}

	return;
}

/*
*	函数名称:QueueFront
*
*	函数功能:取队首的元素
*
*	入口参数:pQ
*
*	出口参数:pQ->pFront->data
*
*	返回类型:QDataType
*/

QDataType QueueFront(pQueue pQ)
{
	assert(NULL != pQ);
	
	assert(NULL != pQ->pFront);

	return pQ->pFront->data;
}

/*
*	函数名称:QueueIsEmpty
*
*	函数功能:队列判空
*
*	入口参数:pQ
*
*	出口参数:0 or 1
*
*	返回类型:int
*/

int QueueIsEmpty(pQueue pQ)
{
	assert(NULL != pQ);

	return 0 == pQ->size ? 1 : 0;
}

/*
*	函数名称:QueueDestory
*
*	函数功能:队列的销毁
*
*	入口参数:pQ
*
*	出口参数:void
*
*	返回类型:void
*/

void QueueDestory(pQueue pQ)
{
	pQNode pCurNode = NULL;
	pQNode pNextNode = NULL;

	assert(NULL != pQ);

	for (pCurNode = pQ->pFront; NULL != pCurNode; pCurNode = pNextNode)
	{
		pNextNode = pCurNode->pNext;
		free(pCurNode);
	}

	pQ->pFront = pQ->pRear = NULL;
	pQ->size = 0;

	return;
}

2、stack.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:stack.c
* 功能:顺序栈的基本功能内部实现细节
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年6月2日20:19:45
*/

# include "stack.h"

/*
*	函数名称:StackInit
*
*	函数功能:栈的初始化,pS->top = 0表示空栈
*
*	入口参数:pS
*
*	出口参数:void
*
*	返回类型:void
*/

void StackInit(pStack pS)
{
	assert(NULL != pS);

	pS->top = 0;

	return;
}

/*
*	函数名称:StackPush
*
*	函数功能:入(压)栈
*
*	入口参数:pS, data
*
*	出口参数:void
*
*	返回类型:void
*/

void StackPush(pStack pS, SDataType data)
{
	assert(NULL != pS);
	assert(pS->top < MAX_SIZE);

	pS->data[pS->top++] = data;	
	
	return;
}

/*
*	函数名称:StackPop
*
*	函数功能:出栈
*
*	入口参数:pS
*
*	出口参数:void
*
*	返回类型:void
*/

void StackPop(pStack pS)
{
	assert(NULL != pS);
	assert(pS->top > 0);	
	
	pS->top--;

	return;
}

/*
*	函数名称:StackTop
*
*	函数功能:获取栈顶元素
*
*	入口参数:pS
*
*	出口参数:void
*
*	返回类型:void
*/

SDataType StackTop(pStack pS)
{
	assert(NULL != pS);
	assert(pS->top > 0);
	
	return pS->data[pS->top - 1];
}

/*
*	函数名称:StackIsEmpty
*
*	函数功能:判断栈是否为空
*
*	入口参数:pS
*
*	出口参数:1 or 0
*
*	返回类型:int
*/

int StackIsEmpty(pStack pS)
{
	assert(NULL != pS);

	return 0 == pS->top ? 1 : 0;
}

/*
*	函数名称:StackDestory
*
*	函数功能:栈的销毁
*
*	入口参数:pS
*
*	出口参数:void
*
*	返回类型:void
*/

void StackDestory(pStack pS)
{
	assert(NULL != pS);

	pS->top = 0;

	return;
}

3、tree.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:tree.c
* 功能:二叉树的基本操作内部实现细节
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年6月13日22:30:27
*/

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

/*
*	函数名称:BuildTree
*
*	函数功能:创建树
*
*	入口参数:array, size, pIndex
*
*	出口参数:pRoot or NULL
*
*	返回类型:BTNode *
*/

BTNode * BuildTree(DataType array[], int size, int * pIndex)
{
	BTNode *pRoot = NULL;

	assert(NULL != pIndex);

	if (*pIndex >= size)
	{
		return NULL;
	}
	else if ( '#' == array[*pIndex])
		{
			(*pIndex)++;
			return NULL;
		}
		else
		{
			pRoot = (BTNode *)malloc(sizeof(BTNode));
			assert(pRoot);
			pRoot->data = array[*pIndex];
			
			(*pIndex)++;

			pRoot->pLeft = BuildTree(array, size, pIndex);
			pRoot->pRight = BuildTree(array, size, pIndex);

			return pRoot;
		}
}

/*
*	函数名称:PreOrder
*
*	函数功能:前序遍历(递归)
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void PreOrder(BTNode * pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	else
	{
		;
	}

	printf("%c ", pRoot->data);
	PreOrder(pRoot->pLeft);
	PreOrder(pRoot->pRight);

	return;
}

/*
*	函数名称:PreOrderLoop
*
*	函数功能:前序遍历(非递归)
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void PreOrderLoop(BTNode * pRoot)
{
	Stack stack;
	BTNode * pCur = pRoot;
	BTNode * pTop = NULL;

	if (NULL == pRoot)
	{
		printf("\n");
		return;
	}
	else
	{
		;
	}

	StackInit(&stack);

	while (NULL != pCur || !StackIsEmpty(&stack))
	{
		while (NULL != pCur)
		{
			printf("%c ", pCur->data);
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}

		pTop = StackTop(&stack);
		
		StackPop(&stack);
		
		pCur = pTop->pRight;
	}
	
	StackDestory(&stack);

	return;
}

/*
*	函数名称:InOrder
*
*	函数功能:中序遍历
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void InOrder(BTNode * pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	else
	{
		;
	}

	InOrder(pRoot->pLeft);
	printf("%c ", pRoot->data);
	InOrder(pRoot->pRight);

	return;
}

/*
*	函数名称:InOrderLoop
*
*	函数功能:中序遍历(非递归)
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void InOrderLoop(BTNode * pRoot)
{
	Stack stack;
	BTNode * pCur = pRoot;
	BTNode * pTop = NULL;

	if (NULL == pRoot)
	{
		printf("\n");
		return;
	}
	else
	{
		;
	}

	StackInit(&stack);

	while (NULL != pCur || !StackIsEmpty(&stack))
	{
		while (NULL != pCur)
		{	
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}

		pTop = StackTop(&stack);

		printf("%c ", pTop->data);
		
		StackPop(&stack);
		
		pCur = pTop->pRight;
	}
	
	StackDestory(&stack);

	return;
}

/*
*	函数名称:PostOrder
*
*	函数功能:后序遍历
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void PostOrder(BTNode * pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	else
	{
		;
	}

	PostOrder(pRoot->pLeft);
	PostOrder(pRoot->pRight);
	printf("%c ", pRoot->data);

	return;
}

/*
*	函数名称:PostOrderLoop
*
*	函数功能:后序遍历(非递归)
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void PostOrderLoop(BTNode * pRoot)
{
	Stack stack;
	BTNode * pCur = pRoot;
	BTNode * pTop = NULL;
	// 上一个被打印的结点
	BTNode * pPrev = NULL;

	if (NULL == pRoot)
	{
		printf("\n");
		return;
	}
	else
	{
		;
	}

	StackInit(&stack);

	while (NULL != pCur || !StackIsEmpty(&stack))
	{
		while (NULL != pCur)
		{	
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}

		pTop = StackTop(&stack);

		// 右子树为空 或者 右子树已遍历过
		if (NULL == pTop->pRight || pPrev == pTop->pRight)
		{
			printf("%c ", pTop->data);
			StackPop(&stack);
			pPrev = pTop;
			continue;
		}
		else
		{
			pCur = pTop->pRight;
		}
	}
	
	StackDestory(&stack);

	return;
}

/*
*	函数名称:LevelOrder
*
*	函数功能:层序遍历
*
*	入口参数:pRoot
*
*	出口参数:void
*
*	返回类型:void
*/

void LevelOrder(BTNode * pRoot)
{
	Queue queue;
	BTNode * pFront = NULL;

	if (NULL == pRoot)
	{
		printf("\n");
		return;
	}
	else
	{
		;
	}

	QueueInit(&queue);
	QueuePush(&queue, pRoot);

	while (!QueueIsEmpty(&queue))
	{
		pFront = QueueFront(&queue);
		printf("%c ", pFront->data);
		QueuePop(&queue);

		if (NULL != pFront->pLeft)
		{
			QueuePush(&queue, pFront->pLeft);
		}
		else
		{
			;
		}

		if (NULL != pFront->pRight)
		{
			QueuePush(&queue, pFront->pRight);
		}
		else
		{
			;
		}
	}

	QueueDestory(&queue);

	return;
}

/*
*	函数名称:TreeSize
*
*	函数功能:树的结点数(遍历)
*
*	入口参数:pRoot
*
*	出口参数:tree_count
*
*	返回类型:int
*/

//int tree_count = 0;
//
//int TreeSize(BTNode * pRoot)
//{
//	if (NULL == pRoot)
//	{
//		return 0;
//	}
//	else
//	{
//		tree_count++;
//	}
//
//	TreeSize(pRoot->pLeft);
//	TreeSize(pRoot->pRight);
//		
//	return tree_count;
//}

/*
*	函数名称:TreeSize
*
*	函数功能:树的结点数(递归)
*
*	入口参数:pRoot
*
*	出口参数:0 or TreeSize(pRoot->pLeft) + TreeSize(pRoot->pRight) + 1
*
*	返回类型:int
*/

int TreeSize(BTNode * pRoot)
{
	if (NULL == pRoot)
	{
		return 0;
	}
	else
	{
		return TreeSize(pRoot->pLeft) + TreeSize(pRoot->pRight) + 1;
	}
}

/*
*	函数名称:LeafSize
*
*	函数功能:叶子结点数(遍历)
*
*	入口参数:pRoot
*
*	出口参数:leaf_count
*
*	返回类型:int
*/

//int leaf_count = 0;
//
//int LeafSize(BTNode * pRoot)
//{
//	if (NULL == pRoot)
//	{
//		return 0;
//	}
//	else if ((NULL == pRoot->pLeft) && (NULL == pRoot->pRight))
//		{
//			leaf_count++;
//		}
//		else
//		{
//			;
//		}
//	
//	LeafSize(pRoot->pLeft);
//	LeafSize(pRoot->pRight);
//
//	return leaf_count;
//}

/*
*	函数名称:LeafSize
*
*	函数功能:叶子结点数(递归)
*
*	入口参数:pRoot
*
*	出口参数:count
*
*	返回类型:int
*/

int LeafSize(BTNode * pRoot)
{
	if (NULL == pRoot)
	{
		return 0;
	}
	else if ((NULL == pRoot->pLeft) && (NULL == pRoot->pRight))
		{
			return 1;
		}
		else
		{
			;
		}

	return LeafSize(pRoot->pLeft) + LeafSize(pRoot->pRight);
}

/*
*	函数名称:GetKSize
*
*	函数功能:求第k层的结点数
*
*	入口参数:pRoot, k
*
*	出口参数:0 or 1 or GetKSize(pRoot->pLeft, k-1) + GetKSize(pRoot->pRight, k-1)
*
*	返回类型:int
*/

int GetKSize(BTNode * pRoot, int k)
{
	if (NULL == pRoot)
	{
		return 0;
	}

	if (NULL == pRoot && 1 == k)
	{
		return 0;
	}

	if (NULL != pRoot && 1 == k)
	{
		return 1;
	}

	return GetKSize(pRoot->pLeft, k - 1) + GetKSize(pRoot->pRight, k - 1);
}

/*
*	函数名称:GetHeight
*
*	函数功能:树的高度
*
*	入口参数:pRoot
*
*	出口参数:0 or MAX(leftH, rightH) + 1
*
*	返回类型:int
*/

int GetHeight(BTNode * pRoot)
{
	int left_height = 0;
	int right_height  = 0;

	if (NULL == pRoot)
	{
		return 0;
	}
	else
	{
		;
	}

	left_height = GetHeight(pRoot->pLeft);
	right_height = GetHeight(pRoot->pRight);

	return MAX(left_height, right_height) + 1;
}

/*
*	函数名称:Find
*
*	函数功能:查找第一次匹配的结点,若找到该结点则返回结点地址,反之则返回NULL
*
*	入口参数:pRoot, data
*
*	出口参数:NULL or pRoot or pFound or Find(pRoot->pRight, data)
*
*	返回类型:BTNode *
*/

BTNode * Find(BTNode * pRoot, DataType data)
{
	BTNode *pFound = NULL;

	if (NULL == pRoot)
	{
		return NULL;
	}

	if (data == pRoot->data)
	{
		return pRoot;
	}
	
	pFound = Find(pRoot->pLeft, data);

	if (NULL != pFound)
	{
		return pFound;
	}

	return Find(pRoot->pRight, data);

	//if (NULL != pRoot->pLeft)
	//{
	//	return Find(pRoot->pLeft, data);
	//}

	//if (NULL != pRoot->pRight)
	//{
	//	return Find(pRoot->pRight, data);
	//}

	//return NULL;
}

/*
*	函数名称:IsComplete
*
*	函数功能:判断当前二叉树是否是完全二叉树,假如是则返回1,反之则返回0
*
*	入口参数:pRoot
*
*	出口参数:0 or 1
*
*	返回类型:int
*/

int IsComplete(BTNode * pRoot)
{
	Queue queue;
	BTNode * pFront = NULL;

	if (NULL == pRoot)
	{
		return 1;
	}

	QueueInit(&queue);
	QueuePush(&queue, pRoot);

	while (!QueueIsEmpty(&queue))
	{
		pFront = QueueFront(&queue);

		if (NULL == pFront)
		{
			break;
		}
		else
		{
			;
		}

		QueuePop(&queue);
		QueuePush(&queue, pFront->pLeft);
		QueuePush(&queue, pFront->pRight);
	}

	while (!QueueIsEmpty(&queue))
	{
		pFront = QueueFront(&queue);
		QueuePop(&queue);

		if (NULL != pFront)
		{
			QueueDestory(&queue);
			return 0;
		}
		else
		{
			;
		}
	}

	QueueDestory(&queue);

	return 1;
}

4、test.c

#define _CRT_SECURE_NO_WARNINGS 1

/*
* Copyright (c) 2018, code farmer from sust
* All rights reserved.
*
* 文件名称:test.c
* 功能:测试二叉树的基本操作
*
* 当前版本:V1.0
* 作者:sustzc
* 完成日期:2018年6月13日22:30:02
*/

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

/*
*	函数名称:main
*
*	函数功能:测试主程序
*
*	入口参数:void
*
*	出口参数:0
*
*	返回类型:int
*/

int main(void)
{
	BTNode *pRoot = NULL;
	BTNode *pFound = NULL;
	int index = 0;

	//不是完全二叉树
	char array[] = {  'A', 'B', 'D',
					  '#', '#', '#',
				      'C', 'E', '#',
				      '#', 'F'};
	//是完全二叉树
	//char array[] = {  'A', 'B', 'D',
	//				  '#', '#', 'G',
	//				  '#', '#',
	//			      'C', 'E', '#',
	//			      '#', 'F'};

	pRoot = BuildTree(array, sizeof(array)/sizeof(char), &index);

	printf("前序遍历二叉树(递归):\n");
	PreOrder(pRoot);
	printf("\n前序遍历二叉树(非递归):\n");
	PreOrderLoop(pRoot);
	printf("\n中序遍历二叉树(递归):\n");
	InOrder(pRoot);
	printf("\n中序遍历二叉树(非递归):\n");
	InOrderLoop(pRoot);
	printf("\n后序遍历二叉树(递归):\n");
	PostOrder(pRoot);
	printf("\n后序遍历二叉树(非递归):\n");
	PostOrderLoop(pRoot);
	printf("\n层序遍历二叉树:\n");
	LevelOrder(pRoot);

	printf("\n树的结点数为: %d\n", TreeSize(pRoot));
	printf("叶子结点数为: %d\n", LeafSize(pRoot));
	printf("第%d层结点数为: %d\n", 3, GetKSize(pRoot, 3));
	printf("树的高度为: %d\n", GetHeight(pRoot));

	pFound = Find(pRoot, 'A');

	if (NULL != pFound)
	{
		printf("找到了 %c !\n", pFound->data);
	}
	else
	{
		printf("没找到!\n");
	}

	if (1 == IsComplete(pRoot))
	{
		printf("是完全二叉树!\n");
	}
	else 
	{
		printf("不是完全二叉树!\n");
	}

	return 0;
}

输出结果


猜你喜欢

转载自blog.csdn.net/sustzc/article/details/80691407