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,将一些空余位置占住,此时我们才能遍历(前序遍历)到我们需要输入的位置中,添加正确的数字