二叉树链式结构的实现

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;
}

猜你喜欢

转载自blog.csdn.net/ych9527/article/details/112302468