数据结构->二叉树的简单实现(C语言)

头文件

以此二叉树为例
在这里插入图片描述

二叉树节点结构的定义及操作函数的声明

部分操作实现需要用到链栈和链队列,所以引入链栈和链队列的头文件
链栈和链队列的实现及操作函数:链接: https://blog.csdn.net/qq_43560037/article/details/113141176?utm_source=app&app_version=4.5.1.

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<stdbool.h>
#include"LinkQueue.h"/*引入链式栈,须在该头文件预先创建二叉树节点,并将队列元素类型预定义为二叉树节点类型
(struct BinTreeNode;
#define QueueElemType struct BinTreeNode* )*/
#include"LinkStack.h"//引入链式队列,做法同上
#define ElemType char

typedef struct BinTreeNode//二叉树节点的创建
{
    
    
	ElemType data;
	struct BinTreeNode* leftChild;
	struct BinTreeNode* rightChild;
}BinTreeNode;

typedef BinTreeNode* BinTree;

//typedef struct BinTree
//{
    
    
//	BinTreeNode* root;
//}BinTree;


///
//函数声明:

//void BinTreeInit(BinTree* t);
//创建方式↓
void BinTreeCreate1(BinTree* t);//此创建方式需要输入二叉树前序序列,用'#'代替空
BinTree BinTreeCreate2();//此创建方式无参数需要用二叉树节点接收,也需输入二叉树前序序列,用'#'代替空
BinTree BinTreeCreate3(const char* str, int i);/*此创建方式需提前在test.c里面定义二叉树前序序列的字符串,
从而不需要输入前序序列,↑参数为字符串首元素地址,i相当于下标*/

//递归遍历↓
void PreOrder(BinTree t);//前序遍历
void InOrder(BinTree t);//中序遍历
void PostOrder(BinTree t);//后序遍历
void LevelOrder(BinTree t);//层级遍历
//非递归遍历↓
void PreOrder_Nor(BinTree t);//
void InOrder_Nor(BinTree t);
void PostOrder_Nor(BinTree t);

size_t Size(BinTree t);//二叉树节点个数
size_t Height(BinTree t);//二叉树高度
BinTreeNode* Find(BinTree t,ElemType key);//查找值为key的节点
BinTreeNode* Parent(BinTree t, BinTreeNode* s);//查找s节点的父节点
int BinTreeLeafSize(BinTree t); //二叉树叶子节点个数
int BinTreeLevelKSize(BinTree t, int k);//二叉树第k层节点个数
BinTree Clone(BinTree t);//克隆二叉树
int BinTreeComplete(BinTree t);// 判断二叉树是否是完全二叉树
bool Equal(BinTree t1, BinTree t2);//比较两个二叉树

各种二叉树操作函数的实现

二叉树创建

(1)创建方式1:

void BinTreeCreate1(BinTree* t)//按前序创建ABCDEFGH
{
    
    
	ElemType item;
	scanf("%c", &item);//ABC##DE##F##G#H##
	if (item == '#')
	{
    
    
		*t = NULL;
	}
	else
	{
    
    
		*t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		assert(*t);
		(*t)->data = item;
		BinTreeCreate1(&((*t)->leftChild));//创建左子树
		BinTreeCreate1(&((*t)->rightChild));//创建右子树
	}
}

(2)创建方式2:

BinTree BinTreeCreate2()
{
    
    
	ElemType item;
	scanf("%c", &item);//ABC##DE##F##G#H##
	if (item == '#')
	{
    
    
		return NULL;
	}
	else
	{
    
    
		BinTreeNode* t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		assert(t);
		t->leftChild = BinTreeCreate2();
		t->rightChild = BinTreeCreate2();
		return t;
	}
}

(3)创建方式3:

BinTree BinTreeCreate3(const char* str,int* i)
{
    
    
	if (str[*i] == '#' || str[*i] == '\0')
		return NULL;
	else
	{
    
    
		BinTreeNode* t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		assert(t);
		t->data = str[*i];
		(*i)++;//下标值++
		t->leftChild = BinTreeCreate3(str, i);
		(*i)++;
		t->rightChild = BinTreeCreate3(str, i);
		return t;
	}
}

二叉树销毁

void DestroyNode(BinTreeNode* node)//销毁节点
{
    
    
	free(node);
    return;
}

void BinTreeDestroy(BinTree* t)
{
    
    
	if (t == NULL)
	{
    
    
		return;//非法
	}
    if (*t == NULL)
	{
    
    
		return;
	}
	 BinTreeDestroy(&((*t)->leftChild));
	 BinTreeDestroy(&((*t)->rightChild));
	 DestroyNode(*t);
	 *t = NULL;
	     return;
}

二叉树遍历

递归遍历

(1)前序遍历

void PreOrder(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		printf("%c ", t->data);
		PreOrder(t->leftChild);
		PreOrder(t->rightChild);
	}
}

(2)中序遍历

void InOrder(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		InOrder(t->leftChild);
		printf("%c ", t->data);
		InOrder(t->rightChild);
	}
}

(3)后序遍历

void PostOrder(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		PostOrder(t->leftChild);
		PostOrder(t->rightChild);
		printf("%c ", t->data);
	}
}

非递归遍历

非递归遍历需要借助到栈结构,头文件里面我们已经引入了“LinkStack.h”文件。
(1)前序遍历
在这里插入图片描述

void PreOrder_Nor(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		LinkStack st;
		LinkStackInit(&st);

		LinkStackPush(&st, t);
	
		while (!LinkStackIsEmpty(&st))
		{
    
    
			BinTreeNode* p = LinkStackTop(&st);
			LinkStackPop(&st);
			printf("%c ", p->data);
			if (p->rightChild != NULL)
				LinkStackPush(&st, p->rightChild);
			if (p->leftChild != NULL)
				LinkStackPush(&st, p->leftChild);
		}
	}
}

(2)中序遍历
在这里插入图片描述

void InOrder_Nor(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		LinkStack st;
		LinkStackInit(&st);
		BinTreeNode* p;
		while (t || !LinkStackIsEmpty(&st))
		{
    
    
			while (t)
			{
    
    
				LinkStackPush(&st, t);
				t = t->leftChild;
			}//直到左树为空时

			p = LinkStackTop(&st);
			LinkStackPop(&st);
			printf("%c ", p->data);

			t = p->rightChild;
		}
	}
}

(3)后序遍历

void PostOrder_Nor(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		LinkStack st;
		LinkStackInit(&st);
		BinTreeNode* p, *prev;//prev为当前节点的前一访问节点
		
		while (t || !LinkStackIsEmpty(&st))
		{
    
    
			while (t)
			{
    
    
				LinkStackPush(&st, t);
				t = t->leftChild;
			}

			p = LinkStackTop(&st);
			if (p->rightChild == NULL || p->rightChild == prev)//右树为空或右树已访问过
			{
    
    
				printf("%c ", p->data);
				LinkStackPop(&st);//要访问
				prev = p;//更新
			}
			else
				t = p->rightChild;
		}
	}
}

层序遍历

在这里插入图片描述

void LevelOrder(BinTree t)
{
    
    
	if (t != NULL)
	{
    
    
		LinkQueue Q;
		LinkQueueInit(&Q);

		LinkQueueEn(&Q, t);
		while (!LinkQueueIsEmpty(&Q))
		{
    
    
			BinTreeNode* p = LinkQueuefront(&Q);
			LinkQueueDe(&Q);
			printf("%c ", p->data);
			if (p->leftChild != NULL)
				LinkQueueEn(&Q, p->leftChild);
			if (p->rightChild != NULL)
				LinkQueueEn(&Q, p->rightChild);
		}
	}
}

求二叉树节点个数

size_t Size(BinTree t)
{
    
    
	if (t == NULL)
		return 0;
	else
		return Size(t->leftChild) + Size(t->rightChild) + 1;//加1不能丢
}

求二叉树高度(深度)

size_t Height(BinTree t)
{
    
    
	if (t == NULL)
		return 0;
	else
	{
    
    
		int left_h = Height(t->leftChild);
		int right_h = Height(t->rightChild);
		return (left_h > right_h ? left_h : right_h) + 1;
	}
}

查找值为key的节点

BinTreeNode* Find(BinTree t, ElemType key)
{
    
    
	BinTreeNode* p;
	if (t == NULL || t->data == key)
		return t;
	p = Find(t->leftChild, key);
	if (p != NULL)
		return p;//左树找到
	return Find(t->rightChild, key);
}

查找s节点的父节点

BinTreeNode* Parent(BinTree t, BinTreeNode* s)
{
    
    
	BinTreeNode* p = NULL;
	if (t == NULL || t == s)
		return NULL;
	if (t->leftChild == s || t->rightChild == s)
		return t;
	p = Parent(t->leftChild, s);
	if (p != NULL)
		return p;
	return Parent(t->rightChild, s);
}

求二叉树叶子节点个数

int BinTreeLeafSize(BinTree t)
{
    
    
	if (t == NULL)
		return 0;
	if (t->leftChild == NULL && t->rightChild == NULL)
		return 1;
	return (BinTreeLeafSize(t->leftChild) + BinTreeLeafSize(t->rightChild));
}

求二叉树第k层节点个数

int BinTreeLevelKSize(BinTree t, int k)
{
    
    
	if (t == NULL || k<1)
	{
    
    
		return 0;
	}
	if (k == 1)
	{
    
    
		return 1;
	}
	return BinTreeLevelKSize(t->leftChild, k - 1) + BinTreeLevelKSize(t->rightChild, k - 1);
}

克隆二叉树

BinTree Clone(BinTree t)
{
    
    
	if (t == NULL)
		return NULL;
	else
	{
    
    
		BinTreeNode* new_t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		assert(new_t);
		new_t->data = t->data;
		new_t->leftChild = Clone(t->leftChild);
		new_t->rightChild = Clone(t->rightChild);
		return new_t;
	}
}

判断二叉树是否是完全二叉树

标记法

int BinTreeComplete(BinTree t)
{
    
    
	LinkQueue Q;
	BinTreeNode * cur;
	int i = 0;//标记值为0代表完整的节点,为1代表不完整的节点。

	LinkQueueInit(&Q);

	LinkQueueEn(&Q, t);

	while (!LinkQueueIsEmpty(&Q))
	{
    
    
		cur = LinkQueuefront(&Q);

		if (cur->rightChild && !cur->leftChild)//有右无左
			return 0;//返回0则不为完全二叉树

		if (i && (cur->rightChild || cur->leftChild))//标记值为1且此时的节点有子树
			return 0;

		if (cur->leftChild)//层序遍历入队
			LinkQueueEn(&Q, cur->leftChild);
			
		if (cur->rightChild)
			LinkQueueEn(&Q, cur->rightChild);
			
		if(cur->_left == NULL || cur->_right == NULL)//如果左或右子树为空,则将标记值改为1
				flag=true;
		LinkQueueDe(&Q);
	}
	return 1;
}

比较两个二叉树是否相等

bool Equal(BinTree t1, BinTree t2)
{
    
    
	if (t1 == NULL && t2 == NULL)
		return true;
	if (t1 == NULL || t2 == NULL)
		return false;
	return (t1->data == t2->data)
		&& Equal(t1->leftChild, t2->leftChild)
		&& Equal(t1->rightChild, t2->rightChild);
}

猜你喜欢

转载自blog.csdn.net/qq_43560037/article/details/113595190