一:二叉树的基本概念和性质
-
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
-
完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
二叉树的性质:
-
若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
-
若规定根结点的层数为1,则深度为h的二叉树的最大结点数是 .
-
对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
-
若规定根结点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2
为底,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否则无右孩子
二:二叉树一些接口的实现:
函数声明和头文件包含:
cpp
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "Queue.h"
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
// 申请节点
BTNode* BuyNode(BTDataType x);
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode* root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 求二叉树的高度
int BinaryHeight(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
对应接口实现:
层序遍历的时候需要调用队列来实现。
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "BTree.h"
// 申请节点
BTNode* BuyNode(BTDataType x)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL)
{
perror("malloc fail");
return NULL;
}
else
{
newnode->data = x;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
}
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
}
else
{
printf("%d ", root->data);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
}
else
{
BinaryTreeInOrder(root->left);
printf("%d ", root->data);
BinaryTreeInOrder(root->right);
}
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
}
else
{
BinaryTreePostOrder(root->left);
BinaryTreePostOrder(root->right);
printf("%d ", root->data);
}
}
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
// 如果遍历到数组的 一个位置 当前位置为空
if (a[*pi] == '#' || *pi >= n)
{
(*pi)++;
return NULL;
}
BTNode* cur = BuyNode(a[*pi]);
cur->data = a[*pi];
(*pi)++;
cur->left = BinaryTreeCreate(a, n, pi);
cur->right = BinaryTreeCreate(a, n, pi);
return cur;
}
// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{
// 采用后序遍历
if (root == NULL)
{
return;
}
BinaryTreeDestory((root)->left);
BinaryTreeDestory((root)->right);
free(root);
root = NULL;
}
// 层序遍历
// 上一层带下一层
void BinaryTreeLevelOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL");
return;
}
Queue qu;
QueueInit(&qu);
// 如果树不是空树,先将第一个根节点入队列
if (root != NULL)
{
QueuePush(&qu, root);
}
// 如果队列不为空,则将队列的中的队头数据取出,并pop掉,如果做右子树不为空,就将左右子树也入队列
while(!QueueEmpty(&qu))
{
// 取队头元素,根节点
BTNode* front = QueueFront(&qu);
printf("%d ", front->data);
if(front->left)
QueuePush(&qu, front->left);
if(front->right)
QueuePush(&qu, front->right);
QueuePop(&qu);
}
QueueDestroy(&qu);
}
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
// 如果改树根节点不为空,则改树的节点个数等于左子树加右子树加1
if (root == NULL)
{
return 0;
}
else
{
return (BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1);
}
}
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
// 如果是空树
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
{
return 1;
}
//int left = BinaryTreeLeafSize(root->left);
//int right = BinaryTreeLeafSize(root->right);
//return left + right;
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
// 求二叉树的高度
int BinaryHeight(BTNode* root)
{
// 求出左子树的高度和右子树的高度比较,大的那个加上根(+1);
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
// 求出叶子节点的个数之后还要加上自己(根)才是最后的高度,左右子树都一样。
int left = BinaryHeight(root->left)+1;
int right = BinaryHeight(root->right)+1;
return left > right ? left : right;
// 为什么这下面的代码和上面的结果不一样?
//int left = BinaryHeight(root->left);
//int right = BinaryHeight(root->right);
//return (left > right ? left : right + 1);
}
// 二叉树第k层节点个数
/*
求解第K层的节点个数,就是求解第K-1层左右节点的个数
*/
int BinaryTreeLevelKSize(BTNode* root, int k)
{
// 不管是多大的问题,都先要考虑特殊情况
if (root == 0)
return 0;
// 使用K来当递归的出口
if (k == 1)
{
return 1;
}
// 转换成子问题
return BinaryTreeLevelKSize(root->right, k - 1)+ BinaryTreeLevelKSize(root->left, k - 1);
}
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root->data == x)
{
return root;
}
// 这里找到了的值应该存起来,然后返回给上一层的函数调用
// 自己写的这个代码如果右子树也为空的话就返回的是空了,但是也没关系,返回是空后面也可以,
// 这个代码应该就是那个网图的那种情况
//BTNode* Find = BinaryTreeFind(root->left, x);
//if (Find != NULL)
//{
// return Find;
//}
//else
//{
// return Find = BinaryTreeFind(root->right, x);
//}
BTNode* ret1 = BinaryTreeFind(root->left, x);
if (ret1)
{
return ret1;
}
BTNode* ret2 = BinaryTreeFind(root->right, x);
if (ret2)
{
return ret2;
}
return NULL;
}
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
// 如果是空树的情况下
if (root == NULL)
{
// printf("NULL");
return false;
}
Queue qu;
QueueInit(&qu);
// 如果树不是空树,先将第一个根节点入队列
if (root != NULL)
{
QueuePush(&qu, root);
}
// 如果队列不为空,则将队列中的队头数据取出,并pop掉,如果做右子树不为空,就将左右子树也入队列
while (!QueueEmpty(&qu))
{
// 取队头元素,根节点
BTNode* front = QueueFront(&qu);
QueuePop(&qu);
if (front == NULL)
{
break;
}
// 这里不需要判断左右孩子为空再入队列,因为只有将空节点也入队列后面不断出队列的时候才能找到非空
QueuePush(&qu, front->left);
QueuePush(&qu, front->right);
}
while (!QueueEmpty(&qu))
{
// 取队头元素,根节点
BTNode* front = QueueFront(&qu);
QueuePop(&qu);
if (front != NULL)
{
return false;
}
}
QueueDestroy(&qu);
return true;
}
测试函数:
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "BTree.h"
//void testarrtree()
//{
// char a[] = "ABD##E#H##CF##G##";
//
// int n = sizeof(a) / sizeof(a[0]);
// int i = 0;
//
// BTNode* tree_root = BinaryTreeCreate(a, n, &i);
//
// BinaryTreePrevOrder(tree_root);
//}
// 自己手搓的树
BTNode* CreatTree()
{
BTNode* root = BuyNode(0);
// BTNode* root = NULL;
BTNode* node1 = BuyNode(1);
BTNode* node2 = BuyNode(2);
BTNode* node3 = BuyNode(3);
BTNode* node4 = BuyNode(4);
BTNode* node5 = BuyNode(5);
BTNode* node6 = BuyNode(6);
BTNode* node7 = BuyNode(7);
BTNode* node8 = BuyNode(8);
BTNode* node9 = BuyNode(9);
//BTNode* node10 = BuyNode(10);
root->left = node1;
root->right = node2;
node1->left = node3;
node1->right = node4;
node2->left = node5;
node2->right = node6;
node3->left = node7;
node3->right = node8;
node4->left = node9;
//node8->right = node10;
return root;
}
void testTree()
{
// 创建一棵树
BTNode* treeroot = CreatTree();
// 前序遍历
// BinaryTreePrevOrder(treeroot);
// 中序遍历
// BinaryTreeInOrder(treeroot);
// 后序遍历
// BinaryTreePostOrder(treeroot);
// 测试树"ABD##E#H##CF##G##";
// char a[] = "ABD##E#H##CF##G##";
// int n = sizeof(a) / sizeof(a[0]);
// int pi = 0;
// BTNode* root = BinaryTreeCreate(a, n, &pi);
// BinaryTreePrevOrder(root);
二叉树的销毁
//BinaryTreeDestory(treeroot);
//treeroot = NULL;
前序遍历
// BinaryTreePrevOrder(treeroot);
// 求节点个数
//printf("%d", BinaryTreeSize(treeroot));
// 求叶子节点个数
// printf("%d\n", BinaryTreeLeafSize(treeroot));
// 求树的高度
// printf("%d\n", BinaryHeight(treeroot));
// 求第K层节点的个数
// printf("%d\n", BinaryTreeLevelKSize(treeroot, 5));
//BTNode* Node = BinaryTreeFind(treeroot, 4);
//printf("%d\n", Node->data);
// 层序遍历
// BinaryTreeLevelOrder(treeroot);
// 判断是否是完全二叉树
printf("%d\n", BinaryTreeComplete(treeroot));
}
int main()
{
// testTree();
// testarrtree();
testTree();
return 0;
}
三:二叉树的基础OJ练习:
4:144. 二叉树的前序遍历 - 力扣(LeetCode)