文章目录
1.变量的声明
在头文件中声明我们需要实现的函数接口和结构体;
#ifndef _BINART_H_
#define _BINART_H_
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode *_left;
struct BinaryTreeNode *_right;
}BTNode;
BTNode *BinaryTreeCreate(BTDataType *root,int *pi);//构建二叉树
void BinaryTreeDestory(BTNode **root);//二叉树的销毁
int BinaryTreeSize(BTNode *root);//二叉树节点个数
int BinaryTreeLeafSize(BTNode *root);//二叉树叶子节点个数
int BinaryTreeLevelKSize(BTNode *root, int k);//第K层节点个数
BTNode *BinaryTreeFind(BTNode *root, BTDataType x);//二叉树查找值为x的节点
void BinaryTreePrveOrder(BTNode *root);//二叉树前序遍历
void BinaryTreeInOrder(BTNode *root);//二叉树中序遍历
void BinaryTreePostOrder(BTNode *root);//二叉树后序遍历
void BinaryTreeLevelOrder(BTNode *root);//层序遍历
int BinaryTreeComplete(BTNode *root);//判断二叉树是否完全二叉树
#endif
2.前序构建二叉树
前序遍历方式为:先根,再左子树然后是右子树。又由于树是具有递归属性的,因此我们可以将其看做三个部分,即根,左子树,右子树,按照前序遍历的方式依次开辟节点链接起来;
BTNode *BinaryTreeCreate(BTDataType *a, int *idx)//前序构建二叉树
{
if (a[*idx] == '#')
{
return NULL;
}
BTNode *root = (BTNode*)malloc(sizeof(BTNode));
root->_data = a[*idx];//根,左,右节点
(*idx)++;
root->_left = BinaryTreeCreate(a, idx);
(*idx)++;
root->_right = BinaryTreeCreate(a, idx);
return root;
}
3.二叉树的销毁
二叉树的销毁采用的是后序的遍历方式,即先左节点再右节点再根。这是因为如果先将根给销毁了就找不到它的左右节点了;
需要注意的是,下图代码中的root和cur的区别,root是二级指针,指向储存根节点地址的内存空间;
void BinaryTreeDestory(BTNode **root)//二叉树的销毁
{
BTNode *cur = *root;
if (cur)
{
BinaryTreeDestory(&cur->_left);
BinaryTreeDestory(&cur->_right);
free(cur);
*root = NULL;//这里不能用cur,cur只是*root的一份拷贝,不会改变外面的内容
}
}
4.二叉树节点和叶子节点的个数
4.1节点的个数
同样利用递归的方式进行计算,一个二叉树节点的个数可以看作当前根节,加上左子树和右子树的个数;
int BinaryTreeSize(BTNode *root)//二叉树节点个数
{
if (root == NULL)
return 0;
return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}
4.2 叶子节点的个数
在节点的计算方式上面加上一个判定,即当前节点的左右子树为空则表示叶子节点的个数+1;
int BinaryTreeLeafSize(BTNode *root)//二叉树叶子节点个数
{
if (root == NULL)
return 0;
if (root->_left == NULL&&root->_right == NULL)
return 1;
return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}
5.第K层节点的个数
int BinaryTreeLevelKSize(BTNode *root, int k)//第K层节点个数
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}
6.二叉树的查找
递归前序遍历二叉树,如果找到对应的值则直接返回,如果当前节点不是则继续往下查找;
需要注意的是:当二叉树中没有对应的值是也要有返回值;
BTNode *BinaryTreeFind(BTNode *root, BTDataType x)//二叉树查找值为x的节点
{
if (root == NULL)
{
return NULL;
}
if (root->_data == x)
{
return root;
}
BTNode *temp = BinaryTreeFind(root->_left, x);
if (temp != NULL)
{
return temp;
}
return BinaryTreeFind(root->_right,x);
}
7.二叉树的前序遍历
利用栈先进后出的特性对二叉树进行遍历,我们将取得的节点打印之后再放入栈之中,再拿出来取其右子树进行遍历
下面用到的栈和队列的实现链接:栈和队列的模拟实现
void BinaryTreePrveOrder(BTNode *root)//二叉树前序遍历
{
BTNode *cur = root;
stack st;
StackInit(&st);
while (cur || !StackEmpty(&st))//当前根节点不为空或者栈不为空
{
while (cur)
{
printf("%c ", cur->_data);
StackPush(&st, cur);//入栈
cur = cur->_left;
}
cur = StackTop(&st);
cur = cur->_right;
StackPop(&st);
}
}
8.二叉树的中序遍历
前序遍历是先打印出根节点,中序遍历是先打印出左节点,因此我们将全部的左节点放入栈之中,然后取出来进行进行打印,再获取它的右节点
void BinaryTreeInOrder(BTNode *root)//二叉树中序遍历
{
//左,根,右,先入栈,后出栈打印
BTNode *cur = root;
stack st;
StackInit(&st);
while (cur || !StackEmpty(&st))
{
while (cur)
{
StackPush(&st, cur);
cur = cur->_left;
}
cur = StackTop(&st);
StackPop(&st);
printf("%c ", cur->_data);
cur = cur->_right;
}
}
9.二叉树的后序遍历
后序遍历中,根节点是最后访问的,因此我们不能过早的将根节点出栈。所以需要一个符号标记是否访问了当前节点的右节点,如果访问了则出栈,没有访问则不出栈
void BinaryTreePostOrder(BTNode *root)//二叉树后序遍历
{
BTNode *cur = root;
BTNode *prev = NULL;//标记是否访问了右子树
stack st;
StackInit(&st);
while (cur || !StackEmpty(&st))
{
while (cur)
{
StackPush(&st, cur);
cur = cur->_left;
}
cur = StackTop(&st);
if (cur->_right == NULL || cur->_right == prev)//右子树为空,或者已经访问过了
{
StackPop(&st);
printf("%c ", cur->_data);
prev = cur;
cur = NULL;
}
else
{
cur = cur->_right;
}
}
}
10.层序遍历
层序遍历是一层一层的往下进行遍历,因此我们利用队列先进先出的特性进行遍历;
如果当前节点不为空,我们将其入队,再出队,然后进行打印,再将其左右子树(不为空)进行入队;
void BinaryTreeLevelOrder(BTNode *root)//层序遍历
{
Queue q;
QueueInit(&q);
BTNode *cur = root;
if (cur)
QueuePush(&q, cur);//入队
while (!QueueEmpty(&q))
{
BTNode *front = QueueFront(&q);
QueuePop(&q);
printf("%c ", front->_data);
if (front->_left)
QueuePush(&q, front->_left);
if (front->_right)
QueuePush(&q, front->_right);
}
}
11.判断是否为完全二叉树
int BinaryTreeComplete(BTNode *root)//判断二叉树是否完全二叉树
{
BTNode *cur = root;
Queue q;
QueueInit(&q);
if (cur)
QueuePush(&q, cur);
while (!QueueEmpty(&q))
{
BTNode *front = QueueFront(&q);
QueuePop(&q);
if (front)//如果队头不为空
{
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
else//遇到空队头则停止循环
{
break;
}
}
while (!QueueEmpty(&q))//判断剩余的队列元素是否全是空
{
BTNode *front = QueueFront(&q);
if (QueueEmpty != NULL)
return 0;
}
return 1;
}