二叉树与堆
- 二叉树
-
- 一:二叉树的概念与性质
- 二:二叉树的存储结构
-
- (1)链式存储
- (2)顺序存储
- 三:二叉树的链式存储结构及实现
-
- (1)二叉树链式存储结构
- (2)二叉树链式存储前序遍历
- (3)二叉树链式存储中序遍历
- (4)二叉树链式存储后序遍历
- (5)二叉树节点个数
- (6)叶子节点个数
- (7)树高
- (8)第k层节点个数
- (9)二叉树查找值为X的节点
- (10)层序遍历 ( 利用队列解决层序遍历)
- (11)判断二叉树是否是完全二叉树
- (12)二叉树销毁
- BinaryTree.c
二叉树
一:二叉树的概念与性质
概念:一棵二叉树是结点的一个有限集合,该集合:
1:或者为空;由一个根节点加上两棵别称为左子树和右子树的二叉树组成
2: 二叉树不存在度大于2的结点; 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
性质:
- 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2的i次方减1个结点.
- 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2的h次方-1
- 对任何一棵二叉树, 如果度为0其叶结点个数为n0,度为2的分支节点结点个数为n2,则有n0=n2+1
- 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1)
- 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
- 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
- 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
- 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
二:二叉树的存储结构
二叉树一般分为两种存储结构,一种是顺序结构,一种是链式结构。
(1)链式存储
概念:二叉树的链式存储结构是指用链表来表示一颗二叉树,即用链表来指示元素的逻辑关系;通常是在高阶数据结构红黑树等会使用该存储结构
(2)顺序存储
概念:顺序存储结构就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不会有空间浪费(例如:堆排序)
三:二叉树的链式存储结构及实现
(1)二叉树链式存储结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
BTNode* ByBTNode(BTDataType x)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->_data = x;
newnode->_left = newnode->_right = NULL;
return newnode;
}
(2)二叉树链式存储前序遍历
// 二叉树前序遍历 根 左子树 右子树
void PreOrder(BTNode* root)
{
//判断是否未NULL树
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%d ", root->_data);
//再递归访问左子树
PreOrder(root->_left);
//再递归访问右子树
PreOrder(root->_right);
}
(3)二叉树链式存储中序遍历
// 二叉树中序遍历 左子树 根 右子树
void InOrder(BTNode* root)
{
//判断是否未NULL树
if (root == NULL)
{
printf("NULL ");
return;
}
//先递归访问左子树
InOrder(root->_left);
printf("%d ", root->_data);
//再递归访问右子树
InOrder(root->_right);
}
(4)二叉树链式存储后序遍历
//后序遍历 左子树 右子树 根
void PostOrder(BTNode* root)
{
//先判断是否为空树
if (root == NULL)
{
printf("NULL ");
return;
}
//先访问左子树
PostOrder(root->_left);
//再访问右子树
PostOrder(root->_right);
printf("%d ", root->_data);
}
(5)二叉树节点个数
//求二叉树节点个数
int TreeSize(BTNode* root)
{
//1:如果为空则返回0
//2:不为空则递归左子树和右子树
return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
(6)叶子节点个数
int TreeLeafSize(BTNode* root)
{
//当节点为空时返回 0,此时为空树
if (root == NULL)
{
return 0;
}
//节点的左子树与右子树同时为空是返回1,代表此时为叶子节点
if (root->_left == NULL&&root->_right == NULL)
{
return 1;
}
//递归到叶子节点
return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}
(7)树高
int TreeHeight(BTNode* root)
{
//根节点为空时为空树
if (root == NULL)
{
return 0;
}
//1:用变量接收左右两边子树的高度
//2:先递归完左子树高度
//3:再递归右子树高度
//最后比较左子树和右子树哪边大,再加根节点高度就为树的高度
int leftheight = TreeHeight(root->_left);
int rightheight = TreeHeight(root->_right);
return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}
(8)第k层节点个数
int TreeKSize(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
//k==1时表示层数为1时
if (k == 1)
{
return 1;
}
//逐层递归计算节点个数
return TreeKSize(root->_left, k - 1) + TreeKSize(root->_right, k - 1);
}
(9)二叉树查找值为X的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
//该节点为空返回空
if (root == NULL)
{
return NULL;
}
//节点值==x,返回root
if (root->_data == x)
{
return root;
}
//找递归左子树是否存在,存在则返回ret1;
BTNode* ret1 = TreeFind(root->_left, x);
if (ret1)
{
return ret1;
}
//找递归右子树是否存在,存在则返回ret2
BTNode* ret2 = TreeFind(root->_right, x);
if (ret2)
{
return ret2;
}
//不存在返回空
return NULL;
}
(10)层序遍历 ( 利用队列解决层序遍历)
void LevelOeder(BTNode* root)
{
Queue q;
QueueInit(&q);
//根节点不为空时,从队尾插入
if (root)
{
QueuePush(&q, root);
}
printf(" LevelOeder:");
//队列不为NULL时,一直插入
while (!QueueEmpty(&q))
{
//取队头元素
QDataType front = QueueFront(&q);
printf("%d ", front->_data);
//判断是否存在左子树,存在就插入
if (front->_left)
{
QueuePush(&q, front->_left);
}
//判断是否存在右子树,存在就插入
if (front->_right)
{
QueuePush(&q, front->_right);
}
//删除队头元素
QueuePop(&q);
}
QueueDestroy(&q);
}
(11)判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
//利用层序遍历思路,用队列解决判断是否是完全二叉树
Queue q;
//初始化
QueueInit(&q);
//插入
QueuePush(&q, root);
while (!QueueEmpty(&q))//
{
BTNode* front = QueueFront(&q);//取队头元素保存
QueuePop(&q);//删除队头元素
if (front == NULL)//当元素为空时跳出判断
{
break;
}
else
{
//左右子树插入
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
}
//出到空之后全是空,则是完全二叉树
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
if (front != NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
(12)二叉树销毁
void TreeDestroy(BTNode* root)
{
//判断是否为空
if (root == NULL)
{
return;
}
//后序遍历销毁
TreeDestroy(root->_left);
TreeDestroy(root->_right);
free(root);
}
BinaryTree.c
#include<stdio.h>
#include<stdlib.h>
#include"queue.h"
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
BTNode* ByBTNode(BTDataType x)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->_data = x;
newnode->_left = newnode->_right = NULL;
return newnode;
}
// 二叉树前序遍历 根 左子树 右子树
void PreOrder(BTNode* root)
{
//判断是否未NULL树
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%d ", root->_data);
//再递归访问左子树
PreOrder(root->_left);
//再递归访问右子树
PreOrder(root->_right);
}
// 二叉树中序遍历 左子树 根 右子树
void InOrder(BTNode* root)
{
//判断是否未NULL树
if (root == NULL)
{
printf("NULL ");
return;
}
//先递归访问左子树
InOrder(root->_left);
printf("%d ", root->_data);
//再递归访问右子树
InOrder(root->_right);
}
//后序遍历 左子树 右子树 根
void PostOrder(BTNode* root)
{
//先判断是否为空树
if (root == NULL)
{
printf("NULL ");
return;
}
//先访问左子树
PostOrder(root->_left);
//再访问右子树
PostOrder(root->_right);
printf("%d ", root->_data);
}
//求二叉树节点个数
int TreeSize(BTNode* root)
{
//1:如果为空则返回0
//2:不为空则递归左子树和右子树
return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
//求叶子节点个数
int TreeLeafSize(BTNode* root)
{
//当节点为空时返回 0,此时为空树
if (root == NULL)
{
return 0;
}
//节点的左子树与右子树同时为空是返回1,代表此时为叶子节点
if (root->_left == NULL&&root->_right == NULL)
{
return 1;
}
//递归到叶子节点
return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}
//求树高
int TreeHeight(BTNode* root)
{
//根节点为空时为空树
if (root == NULL)
{
return 0;
}
//1:用变量接收左右两边子树的高度
//2:先递归完左子树高度
//3:再递归右子树高度
//最后比较左子树和右子树哪边大,再加根节点高度就为树的高度
int leftheight = TreeHeight(root->_left);
int rightheight = TreeHeight(root->_right);
return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}
//求第k层节点个数
int TreeKSize(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
//k==1时表示层数为1时
if (k == 1)
{
return 1;
}
//逐层递归计算节点个数
return TreeKSize(root->_left, k - 1) + TreeKSize(root->_right, k - 1);
}
//二叉树查找值为X的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
//该节点为空返回空
if (root == NULL)
{
return NULL;
}
//节点值==x,返回root
if (root->_data == x)
{
return root;
}
//找递归左子树是否存在,存在则返回ret1;
BTNode* ret1 = TreeFind(root->_left, x);
if (ret1)
{
return ret1;
}
//找递归右子树是否存在,存在则返回ret2
BTNode* ret2 = TreeFind(root->_right, x);
if (ret2)
{
return ret2;
}
//不存在返回空
return NULL;
}
//层序遍历 利用队列解决层序遍历
void LevelOeder(BTNode* root)
{
Queue q;
QueueInit(&q);
//根节点不为空时,从队尾插入
if (root)
{
QueuePush(&q, root);
}
printf(" LevelOeder:");
//队列不为NULL时,一直插入
while (!QueueEmpty(&q))
{
//取队头元素
QDataType front = QueueFront(&q);
printf("%d ", front->_data);
//判断是否存在左子树,存在就插入
if (front->_left)
{
QueuePush(&q, front->_left);
}
//判断是否存在右子树,存在就插入
if (front->_right)
{
QueuePush(&q, front->_right);
}
//删除队头元素
QueuePop(&q);
}
QueueDestroy(&q);
}
//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
//利用层序遍历思路,用队列解决判断是否是完全二叉树
Queue q;
//初始化
QueueInit(&q);
//插入
QueuePush(&q, root);
while (!QueueEmpty(&q))//
{
BTNode* front = QueueFront(&q);//取队头元素保存
QueuePop(&q);//删除队头元素
if (front == NULL)//当元素为空时跳出判断
{
break;
}
else
{
//左右子树插入
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
}
//出到空之后全是空,则是完全二叉树
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
if (front != NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
//二叉树销毁
void TreeDestroy(BTNode* root)
{
//判断是否为空
if (root == NULL)
{
return;
}
//后序遍历销毁
TreeDestroy(root->_left);
TreeDestroy(root->_right);
free(root);
}
int main()
{
BTNode* n1 = ByBTNode(1);
BTNode* n2 = ByBTNode(2);
BTNode* n3 = ByBTNode(3);
BTNode* n4 = ByBTNode(4);
BTNode* n5 = ByBTNode(5);
BTNode* n6 = ByBTNode(6);
BTNode* n7 = ByBTNode(7);
n3->_right = n7;
n1->_left = n2;
n2->_left = n3;
n1->_right = n4;
n4->_left = n5;
n4->_right = n6;
//前序遍历
PreOrder(n1);
printf("
");
//中序遍历
InOrder(n1);
printf("
");
//后续遍历
PostOrder(n1);
printf("
");
//层序遍历
LevelOeder(n1);
printf("
");
//求二叉树节点个数
printf("TreeSize:%d
", TreeSize(n1));
//求二叉树叶子节点
printf("TreeLeafSize:%d
", TreeLeafSize(n1));
//求二叉树的高度
printf("TreeHeight:%d
", TreeHeight(n1));
//求第k层的节点个数
printf("TreeKSize:%d
", TreeKSize(n1, 3));
//二叉树查找值为X的节点
BTNode* ret = TreeFind(n1, 7);
printf("ret=%d val=%d
", ret, ret->_data);
//判断二叉树是否是完全二叉树
printf("BinaryTreeComplete:%d", BinaryTreeComplete(n1));
TreeDestroy(n1);
n1 = NULL;
return 0;
}