二叉树模拟实现--c

BinaryTree.h

#pragma once
#include<malloc.h>
#include<assert.h>
#include<stdio.h>

//binary tree node data type二叉树节点数据类型
typedef int BTNDataType;


typedef struct BTNode
{
	struct BTNode* left;
	struct BTNode* right;
	BTNDataType data;//节点中的值域
}BTNode;


BTNode* CreateBinTree(int array[], int size, int* index, int invalid);//创建
BTNode* CopyBinTree(BTNode* root);//拷贝二叉树
void preOrder(BTNode* root);//前序遍历root这个数
void InOrder(BTNode* root);//中序遍历
void PostOrder(BTNode* root);//后序遍历
void LevelOrder(BTNode* root);//层序遍历
int GetNodeCount(BTNode* root);//获取二叉树中节点的个数
int GetLeafNodeCount(BTNode* root);//获取二叉树中叶子节点的个数
int GetKLevelNodeCount(BTNode* root, unsigned int k);//获取二叉树中第k层节点的个数
BTNode* Find(BTNode* root, BTNDataType data);//找值为data节点
int GetHeight(BTNode* root);//获取二叉树的高度

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

void DestroyTree(BTNode** root);//销毁


void TestBinTree();

BinaryTree.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "BinaryTree.h"

#include "Queue.h"

BTNode* BUyBinTreeNode(BTNDataType data)
{
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == newNode)
	{
		assert(0);
		return NULL;
	}
	newNode->data = data;
	newNode->left = NULL;
	newNode->right = NULL;
	return newNode;
}

//array数组中:保存的时二叉树中所有节点的值域
BTNode* CreateBinTree(int array[], int size, int* index, int invalid)
{
	BTNode* root = NULL;
	if (*index < size && array[*index] != invalid)
	{
		//创建根节点
		root = BUyBinTreeNode(array[*index]);

		//创建根节点的左子树
		++(*index);
		root->left = CreateBinTree(array, size, index, invalid);

		//创建根节点的右子树
		++(*index);
		root->right = CreateBinTree(array, size, index, invalid);

	}

	return root;
}
//创建二叉树:
//创建根节点:
//创建根节点的左子树:
//创建根节点的右子树:
//index(索引):递归每次走进来之后,我们应该把数组里面的所有元素都要拿到
//数组中的序列如何给?创建规则:二叉树前序遍历规则 
//因为创建与前序遍历规则类似,考虑:将元素按照前序遍历结果给出
//invalid无效值

BTNode* CopyBinTree(BTNode* root)//拷贝二叉树
{
	BTNode* newroot = NULL;
	if (root)//检查树是否存在
	{
		//拷贝根节点
		newroot = BUyBinTreeNode(root->data);

		//拷贝根节点的左子树
		newroot->left = CopyBinTree(root->left);
		//拷贝根节点的右子树
		newroot->right = CopyBinTree(root->right);

	}
	return newroot;

}
//二叉树拷贝:
//方法:
//拷贝根节点--》malloc新的节点,让根节点中的值域交给新节点
//拷贝根节点的左子树--》也是二叉树--》递归
//拷贝根节点的右子树--》也是二叉树--》递归



//假设:遍历操作就是将节点中的值域打印出来
//根节点--》根节点的左子树--》根节点的右子树
void preOrder(BTNode* root)
{
	if (root)
	{
		printf("%d ", root->data);
		preOrder(root->left);
		preOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d ", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d ", root->data);
	}
}


void LevelOrder(BTNode* root)
{
	Queue q;
	if (NULL == root)
		return;

	QueueInit(&q);
	QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		BTNode* cur = QueueFront(&q); 
		printf("%d", cur->data);
		QueuePop(&q);

		//如果cur左孩子存在,将左孩子入队列
		if (cur->left)
			QueuePush(&q, cur->left);

		//如果cur右孩子存在,将右孩子入队列
		if (cur->right)
			QueuePush(&q, cur->right);
	}
	QueueDestroy(&q);
}





int GetNodeCount(BTNode* root)//获取二叉树中节点的个数
{
	//if (NULL == root)//-------------------------------1
	//	return 0;
	//int leftSize = GetNodeCount(root->left);
	//int rightSize = GetNodeCount(root->right);
	//return leftSize + rightSize + 1;

	//if (NULL == root)//-------------------------------2
	//	return 0;
	//return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;

	return NULL == root ? 0 : GetNodeCount(root->left) + GetNodeCount(root->right) + 1;//-----------3
}
//方法:树空--》直接返回
//非空--》递归获取root左子树中节点个数leftSize,递归获取root右子树中节点个数rightSize  最后return leftSize + rightSize + 1;
//三种方法均可

int GetLeafNodeCount(BTNode* root)//获取二叉树中叶子节点的个数
{
	if (NULL == root)
		return 0;

	if (NULL == root->left && NULL == root->right)
		return 1;

	return GetLeafNodeCount(root->left) + GetLeafNodeCount(root->right);

}
//获取二叉树中的叶子节点方法:空树--》直接返回0
//非空:递归求左子树中叶子节点个数,递归求右子树中叶子节点个数
//返回:左子树叶子节点个数+右子树叶子节点个数

int GetKLevelNodeCount(BTNode* root, unsigned int k)//获取二叉树中第k层节点的个数
{
	if (NULL == root || k == 0)
		return 0;

	//第一层只有根节点
	if (1 == k)
		return 1;

	//将问题转换为:到子树中求k-1层节点个数
	return GetKLevelNodeCount(root->left, k - 1) + GetKLevelNodeCount(root->right, k - 1);
}
//如果k大于二叉树的层数时,返回什么?0

BTNode* Find(BTNode* root, BTNDataType data)//找值为data节点
{
	BTNode* ret = NULL;
	if (NULL == root)
		return NULL;

	if (root->data == data)
		return root;

	//现在左子树中找,找到了直接返回
	//如果左子树没有找到,在到右子树中查找
	//(ret = Find(root->left, data) || Find(root->right, data));
	if (ret = Find(root->left, data))
		return ret;

	return Find(root->right, data);
}

int GetHeight(BTNode* root)//获取二叉树的高度
{
	int leftHeight = 0, rightHeight = 0;
	if (NULL == root)
		return 0;

	leftHeight = GetHeight(root->left);
	rightHeight = GetHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;

}
//方法:
//如果树为空直接返回0
//非空--求递归求root左右子树的高度--return较高子树高度+1;

int BinaryTreeComplete(BTNode* root)
{
	Queue q;
	int flag = 0;
	int ret = 0;
	//空树也是完全二叉树
	if (NULL == root)
		return 1;

	//非空
	//1.按照层序遍历规则找第一个不饱和的节点 
	QueueInit(&q);//初始化
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* cur = QueueFront(&q);
		if (flag)
		{
			//后序节点就不能有孩子
			if (cur->left || cur->right)
				break;
		}
		else
		{
			//找第一个不饱和的节点
			if (cur->left && cur->right)
			{
				QueuePush(&q, cur->left);
				QueuePush(&q, cur->right);
			}
			else if (cur->left)
			{
				//cur只有左孩子
				QueuePush(&q, cur->left);
				flag = 1;
			}
			else if (cur->right)
			{
				//cur只有有右孩子
				break;
			}
			else
			{
				flag = 1;
			}
			QueuePop(&q);
		}

		if (!QueueEmpty(&q))
			ret = 1;
		QueueDestroy(&q);
		return ret;
	}
}
//完全二叉树节点
//按照层序规则往后遍历遇到的第一个不饱和(不是两个孩子)的节点
//解决方法:
//1.按照层序遍历方式找第一个不饱和的节点
//2.从该节点之后,所有的节点不能右二叉树,如果有则不是完全二叉树,如果有则是


void DestroyTree(BTNode** root)
{
	assert(root);//root中的内容:就是外部实参的地址
	if (*root)//*root才是外部的实参
	{
		DestroyTree(&(*root)->left);
		DestroyTree(&(*root)->right);
		free(*root);
		*root = NULL;//让外部的实参直线空
	}
}


void TestBinTree()
{
	//将二叉树中元素放在数组中
	int array[] = { 1, 2, 3, -1, -1, -1, 4, 5, -1, -1, 6 };
	int index = 0;
	BTNode* root = CreateBinTree(array, sizeof(array) / sizeof(array[0]), &index, -1);
	BTNode* newroot = NULL;

	printf("前序遍历结果: ");
	preOrder(root);
	printf("\n");

	printf("中序遍历结果: ");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果: ");
	PostOrder(root);
	printf("\n");


	printf("层序遍历结果: ");
	LevelOrder(root);
	printf("\n");

	printf("%d\n", GetNodeCount(root));
	printf("%d\n", GetLeafNodeCount(root));
	printf("%d\n", GetKLevelNodeCount(root,2));
	printf("%d\n", GetKLevelNodeCount(root, 3));
	printf("%d\n", GetKLevelNodeCount(root, 10));


	BTNode* cur = Find(root, 5);
	if (cur)
		printf("5 is in binary tree!!!\n");
	else
		printf("5 is not in binary tree!!!\n");


	printf("%d\n", GetHeight(root));

	if (BinaryTreeComplete(root))
		printf("is completebinary tree!!!\n");
	else
		printf("is not completebinary tree!!!\n");

	newroot = CopyBinTree(root);
	printf("前序遍历结果: ");
	preOrder(newroot);
	printf("\n");

	printf("中序遍历结果: ");
	InOrder(newroot);
	printf("\n");

	printf("后序遍历结果: ");
	PostOrder(newroot);
	printf("\n");


	printf("层序遍历结果: ");
	LevelOrder(newroot);
	printf("\n");

	DestroyTree(&root);
	DestroyTree(&newroot);

} 

Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"

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


QNode* BuyQNode(QDataType data)
{
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (NULL == newNode)
	{
		assert(0);
		return NULL;
	}

	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}


// 参数检测时:什么情况下应该用assert,什么情况下应该用if来判断
// if: 当条件成立时,该种情况是一种合法的情况,应该用if---比如:空链表
// assert: 当条件成立时,该种情况是一种非法的情况,应用if---比如:链表不存在
void QueueInit(Queue* q)
{
	assert(q);
	q->front = NULL;
	q->rear = NULL;
	q->size = 0;
}

void QueuePush(Queue* q, QDataType data)
{
	QNode* newNode = BuyQNode(data);
	// 链表尾插
	if (QueueEmpty(q))
	{
		q->front = newNode;
	}
	else
	{
		q->rear->next = newNode;
	}

	q->rear = newNode;
	q->size++;
}

void QueuePop(Queue* q)
{
	QNode* delNode = NULL;
	if (QueueEmpty(q))
		return;

	delNode = q->front;
	if (q->front == q->rear)
		q->front = q->rear = NULL;
	else
		q->front = delNode->next;

	free(delNode);
	q->size--;
}

QDataType QueueFront(Queue* q)
{
	assert(!QueueEmpty(q));
	return q->front->data;
}


QDataType QueueBack(Queue* q)
{
	assert(!QueueEmpty(q));
	return q->rear->data;
}

int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

int QueueEmpty(Queue* q)
{
	assert(q);
	return NULL == q->front;
}

void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	while (cur)
	{
		q->front = cur->next;
		free(cur);
		cur = q->front;
	}

	q->front = q->rear = NULL;
	q->size = 0;
}

Queue.h

#pragma once


// 队列底层采用连续空间来实现,效果不是很好
// 队列:采用链表的方式实现的

// typedef int QDataType;
typedef struct BTNode* QDataType;

typedef struct QNode
{
	struct QNode* next;
	QDataType data;
}QNode;


typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;
}Queue;

void QueueInit(Queue* q);
void QueuePush(Queue* q, QDataType data);
void QueuePop(Queue* q);
QDataType QueueFront(Queue* q);
QDataType QueueBack(Queue* q);
int QueueSize(Queue* q);
int QueueEmpty(Queue* q);
void QueueDestroy(Queue* q);

test.c

#define _CRT_SECURE_NO_WARNINGS 1

int main()
{
	TestBinTree();
	return 0;
}

//补充:
//二叉树创建中,我们不一定要创建一个(满二叉树,完全二叉树),一个不标准的二叉树是由标准的却少某些元素后而成的二叉树
//在创建二叉树中,我们用前序遍历的方法创建一个新的二叉树,我们知道我们二叉树创建后的结果是什么样的,但是我们如果只输入新二叉树的元素,则只会得到一个单链表,
//此时,我们需要借用invalid,将一些空余位置占住,此时我们才能遍历(前序遍历)到我们需要输入的位置中,添加正确的数字
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值