1.树的概念及结构
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个结点有零个或多 个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结 点可以分为多个不相交的子树 。
2.二叉树的概念及结构
二叉树是节点的有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成。
二叉树的特点是:每个节点最多有两个子节点;二叉树的子数有左右之分,不能随意互换。
两种特殊的二叉树:一种是满二叉树,一种是完全二叉树。满二叉树是每一层的节点个数都达到最大值,比如第k层,则该层节点数为2^(k-1)。完全二叉树是对于深度为K 的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对 应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉。
3.二叉树的存储方式
二叉树有两种结构存储,一种是顺序存储,一种是链式存储。顺序存储就是用数组来存储,而一般用数组知识和表示完全二叉树。而链式存储是用链表来表示一颗二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表 中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结 点的存储地址 。在这里我实现的是链式结构的二叉树的存储,同时也包含其他相关函数功能。
首先时头文件部分
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef char BTDataType;
typedef struct BTNode
{
struct BTNode* _pLeft;
struct BTNode* _pRight;
BTDataType _data;
}BTNode;
typedef struct {
BTNode* root;
int used;
}Result;
// 1. 创建二叉树
Result* CreateBinTree(BTDataType* array, int size);
// 拷贝二叉树
BTNode* CopyBinTree(BTNode* pRoot);
// 销毁二叉树
void DestroyBinTree(BTNode** pRoot);
// 二叉树的三种遍历方式
void PreOrder(BTNode* pRoot);//递归实现前序遍历
void PreOrderNor(BTNode* pRoot);//非递归实现前序遍历
void InOrder(BTNode* pRoot);//递归实现中序遍历
void InOrderNor(BTNode* pRoot);//递归实现中序遍历
void PostOrder(BTNode* pRoot);//递归实现后序遍历
void PostOrderNor(BTNode* pRoot);//递归实现后序遍历
void LevelOrder(BTNode* pRoot);//层序遍历
// 获取二叉树中节点的个数
int GetNodeCount(BTNode* pRoot);
// 求二叉树的高度
int Height(BTNode* pRoot);
// 检测二叉树是否平衡O(N^2)
int IsBalanceTree(BTNode* pRoot);
// 检测二叉树是否平衡O(N)
int IsBalanceTree_P(BTNode* pRoot, int* height);
// 获取二叉数中叶子节点的个数
int GetLeafNodeCount(BTNode* pRoot);
// 获取二叉树第K层节点的个数
int GetKLevelNodeCount(BTNode* pRoot, int K);
// 获取二叉树中某个节点的双亲节点
BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode);
// 求二叉树的镜像
void Mirror(BTNode* pRoot);
接下来是函数功能实现部分
#include"test.h"
#include"Stack.h"
#include<math.h>
#include"queue.h"
// 1. 创建二叉树
Result* CreateBinTree(BTDataType* array, int size)
{
//前序遍历创建二叉树,并且空节点出用‘#’代替
Result* ret = NULL;
if (size == 0)
{
ret->root = NULL;
ret->used = 0;
return ret;
}
if (array[0] == '#')
{
ret->root = NULL;
ret->used = 1;
return ret;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
root->_data = array[0];
Result* leftroot = CreateBinTree(array + 1, size - 1);
Result* rightroot = CreateBinTree(array + 1 + leftroot->used, size - 1 - leftroot->used);
root->_pLeft = leftroot->root;
root->_pRight = rightroot->root;
ret->root = root;
ret->used = 1 + leftroot->used + rightroot->used;
return ret;
}
// 拷贝二叉树
BTNode* CopyBinTree(BTNode* pRoot)
{
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
if (pRoot == NULL)
{
return NULL;
}
else
{
node->_data = pRoot->_data;
node->_pLeft = CopyBinTree(pRoot->_pLeft);
node->_pRight = CopyBinTree(pRoot->_pRight);
return node;
}
}
// 销毁二叉树
void DestroyBinTree(BTNode** pRoot)
{
if (*pRoot)
{
if ((*pRoot)->_pLeft)
{
DestroyBinTree(&(*pRoot)->_pLeft);
}
if ((*pRoot)->_pRight)
{
DestroyBinTree(&(*pRoot)->_pRight);
}
free(*pRoot);
*pRoot = NULL;
}
}
// 二叉树的三种遍历方式
//前序遍历 根——>左子树——>右子树
//中序遍历 左子树——>根——>右子树
//后序遍历 左子树——>右子树——>根
//前序遍历递归实现
void PreOrder(BTNode* pRoot)
{
if (pRoot == NULL)
{
return;
}
else
{
printf("%c ", pRoot->_data);
PreOrder(pRoot->_pLeft);
PreOrder(pRoot->_pRight);
}
}
//前序遍历非递归实现,非递归的实现需要利用栈,但是由于利用的是c语言,所以需要先写好一个有关栈的头文件
//中序和后序的非递归实现也是如此
void PreOrderNor(BTNode* pRoot)
{
//先把根节点入栈,遍历左子树,边遍历边打印,并且把左子树入栈,当第一轮左子树和根都遍历完了,则开始进入右子树
Stack* s;
BTNode* p = pRoot;
if (pRoot == NULL)
{
return;
}
while (!StackEmpty(s)||p)
{
while (p)
{
printf("%c ", StackTop(s)); //打印栈顶元素
StackPush(s, p->_data); //根节点入栈
p = p->_pLeft; //遍历左子树
}
if (!StackEmpty(s))
{
p = StackTop(s); //保存栈顶元素
StackPop(s); //取出栈顶元素
p = p->_pRight; //遍历右子树
}
}
}
//中序遍历
void InOrder(BTNode* pRoot)
{
if (pRoot == NULL)
{
return;
}
else
{
InOrder(pRoot->_pLeft);
printf("%c ", pRoot->_data);
InOrder(pRoot->_pRight);
}
}
//非递归实现中序遍历
void InOrderNor(BTNode* pRoot)
{
BTNode* p = pRoot;
Stack* s = (Stack*)malloc(sizeof(Stack));
while (!StackEmpty(s)||p)
{
while (p)
{
StackPush(s,p->_data);//根节点入栈
p = p->_pLeft;//遍历左子树
}
if (StackEmpty(s))
{
p->_data = StackTop(s);//第一次是保存最后一个左子树节点
StackPop(s);//第一次是取出最后一个左子树节点
printf("%c ", p->_data);//打印保存的节点
p = p->_pRight;//遍历右子树
}
}
}
//后序遍历
void PostOrder(BTNode* pRoot)
{
if (pRoot == NULL)
{
return;
}
else
{
PostOrder(pRoot->_pLeft);
PostOrder(pRoot->_pRight);
printf("%c ", pRoot);
}
}
//非递归实现后序遍历
void PostOrderNor(BTNode* pRoot)
{
//同样的方法类似于上面的前序和中序遍历
Stack* s;
if (pRoot == NULL)
{
return;
}
BTNode* p = pRoot;
BTNode* last = NULL;
while (p)
{
StackPush(s, p->_data);
p = p->_pLeft;
}
while (!StackEmpty(s))
{
p = StackTop(s);
StackPop(s);
if ((p->_pRight == NULL) || (p->_pRight == last))
{
printf("%c ", p->_data);
last = p;
}
else
{
StackPush(s, p->_data);
p = p->_pRight;
while (p)
{
StackPush(s, p->_data);
p = p->_pRight;
}
}
}
}
//层序遍历
void LevelOrder(BTNode* pRoot)
{
//层序遍历需要用到的是队列,所以也需要提前写好有关队列的头文件
Queue* q;
BTNode* p = NULL;
if (pRoot == NULL)
{
return;
}
QueuePush(q, pRoot->_data);//首先将根节点入队
while (!QueueEmpty(q))
{
p = QueueFront(q);//保存队首元素
QueuePop(q);//取出队首元素
printf("%c ", p->_data);//打印保存的元素
if (p->_pLeft)
{
QueuePush(q,p->_pLeft);//将保存的元素的左子树入队
}
if (p->_pRight)
{
QueuePush(q, p->_pRight);//将保存的元素的左子树入队
}
}
}
// 获取二叉树中节点的个数
int GetNodeCount(BTNode* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
return GetNodeCount(pRoot->_pLeft) + GetNodeCount(pRoot->_pRight) + 1;
}
// 求二叉树的高度
int Height(BTNode* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
int leftheight = Height(pRoot->_pLeft) + 1;//左子树高度,+1是加上根节点
int rightheight = Height(pRoot->_pRight) + 1;//右子树高度
return (leftheight > rightheight) ? leftheight : rightheight;
}
// 检测二叉树是否平衡O(N^2)
int IsBalanceTree(BTNode* pRoot)
{
//平衡树要求左子树高度与右子树高度不好过1
if (pRoot == NULL)
{
return 0;
}
int leftheight = Height(pRoot->_pLeft) + 1;
int rightheight = Height(pRoot->_pRight) + 1;
if (abs(leftheight - rightheight) > 1)
{
return -1;
}
else
return 1;
}
// 检测二叉树是否平衡O(N)
int IsBalanceTree_P(BTNode* pRoot, int* height)
{
if (pRoot == NULL)
{
return 0;
}
int leftheight = 0;
int rightheight = 0;
if (IsBalanceTree_P(pRoot->_pLeft, &leftheight) &&
IsBalanceTree_P(pRoot->_pRight, &rightheight))
{
if (abs(leftheight - rightheight) <= 1)
{
*height = 1 + (leftheight < rightheight ? rightheight : leftheight);
return 1;
}
else
return -1;
}
else
return -1;
}
// 获取二叉数中叶子节点的个数
int GetLeafNodeCount(BTNode* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
if (pRoot->_pLeft == NULL &&pRoot->_pRight == NULL)
{
return 1;
}
int left = GetLeafNodeCount(pRoot->_pLeft);
int right = GetLeafNodeCount(pRoot->_pRight);
return left+right;
}
// 获取二叉树第K层节点的个数
int GetKLevelNodeCount(BTNode* pRoot, int K)
{
if (pRoot == NULL)
{
return 0;
}
if (K == 1)
{
return 1;
}
int left = GetKLevelNodeCount(pRoot->_pLeft, K - 1);//根节点每往下一层,K-1,当根节点到达第K层时,K-1 = 1;
int right = GetKLevelNodeCount(pRoot->_pRight, K - 1);
return left + right;
}
// 获取二叉树中某个节点的双亲节点
BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode)
{
if (pRoot == NULL)
{
return NULL;
}
if (pRoot->_pLeft == pNode || pRoot->_pRight == pNode)
{
return pRoot;
}
BTNode* ret = GetNodeParent(pRoot->_pLeft, pNode);//让根节点的左子树与目标子数比较
if (ret != NULL)//若ret不为NULL索命找到了双亲结点,就不需要继续往下找了
{
return ret;
}
ret = GetNodeParent(pRoot->_pRight, pNode);//让根节点的左子树与目标子数比较
return ret;
}
// 求二叉树的镜像
void Mirror(BTNode* pRoot)
{
if (pRoot == NULL)
{
return;
}
if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
{
return;
}
BTNode* mirror = pRoot->_pLeft;
pRoot->_pLeft = pRoot->_pRight;
pRoot->_pRight = mirror;
if (pRoot->_pLeft)
{
Mirror(pRoot->_pLeft);
}
if (pRoot->_pRight)
{
Mirror(pRoot->_pRight);
}
}