二叉树的实现(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);
}