一.什么是二叉树?
二叉树是一颗特殊的树,每个节点最多有两个孩子,以这两个孩子作为根的树也是二叉树。
吐槽一下,因为之前有同学在面试的时候被问到二叉树的标准定义,所以有必要将标准定义列出来。
标准定义(引用自百度百科): 二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点.
二.二叉树的性质
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
2.若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1.
3.对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2+1 推导过程如下: 二叉树节点的个数 = 二叉树边的个数 + 1 节点个数 = n0 + n1 + n2 n0:度为0的节点个数 n1:度为1的节点个数 n2:度为2的 节点个数 边的个数 = 0 * n0 + 1 * n1 + 2 * n2 n0 + n1 + n2 = n1 + 2n2 + 1,则n0 = n2 + 1
4.若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=Log2(n+1). (ps:Log2(n+1)是log以2为 底,n+1为对数)
5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对 于序号为i的结点有:
1)若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2)若2i+1<n,左孩子序号:2i+1,2i+1>=n,否则无左孩子
3)若2i+2<n,右孩子序号:2i+2,2i+2>=n,否则无右孩子
三.完全二叉树和满二叉树
1.完全二叉树
一个有k层n个节点的二叉树,如果前k-1层是满的,并且第k层从左往右连续,则这棵树是完全二叉树 完全二叉树示意图:
2.满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。满二叉树是特殊的完全二叉树. 满二叉树示意图:
四.二叉树的实现
1.顺序存储—堆
堆的实现见博客: https://blog.csdn.net/m0_51765966/article/details/120579694
2.链式存储
链式存储可以采用孩子兄弟表示法,左右孩子表示法,父亲左右孩子表示法等,此处采用左右孩子表示法
1)二叉树数据结构的定义
每个节点不仅要能存储自己的数据,还要有左右孩子的指针
typedef char DataType;
typedef struct TreeNode
{
DataType data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
2)核心操作的实现思路
根据先序遍历的结果创建二叉树
一颗二叉树,即使是同一个先序遍历的结果,也可能会有多种结构,所以为了让这颗二叉树具有唯一性,用#表示空节点. 当遍历先序结果时,遇见#就返回一个空指针,表示此节点为空,否则就创建一个节点,并递归创建左右孩子
二叉树先序遍历结果及对应的二叉树示例如下图所示:
层序遍历
通过队列来实现层序遍历 a:将根节点存入队列; b:统计当前队列中的元素个数curSz也就是这一层的节点个数, 让这curSz个元素出队并保存结果,每次出队时将队头元素的左孩子和右孩子按照顺序入队(前提是左孩子和右孩子非空); c:重复b直到队列为空;
获取第k层的节点个数
这个实现起来难度不大,但对于递归的使用很灵活和巧妙,所以归到核心操作中,概括起来就一句话:第k层的节点个数就是左右孩子的第k-1层的节点个数之和
销毁二叉树
销毁二叉树时,通过递归的方法,先销毁左子树的节点,再销毁右子树的节点,最后销毁根节点。 最重要的是要传一个根节点指针的指针作为参数,不然释放完堆上的节点空间之后,无法将指针置为空。
判断二叉树是否为完全二叉树
通过层序遍历来判断 在层序遍历的过程中,遇见空节点,查看这一层后面的节点是否全为空节点,如果不全为空节点,则说明这一层节点非连续,不是完全二叉树;其他情况则说明是完全二叉树。
3)二叉树源码
因为要用到队列,所以也包含队列的源码 因为队列的节点中存储的数据为树节点指针,所以树的定义在队列的头文件中
Queue.h:
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef char DataType;
typedef struct TreeNode
{
DataType data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
typedef TreeNode* QDataType;
typedef struct Qnode
{
struct Qnode* _next;
QDataType _data;
}Qnode;
typedef struct Queue
{
Qnode* _front;
Qnode* _rear;
int size;
}Queue;
void queueInit(Queue* q);
Qnode* createNode(QDataType val);
void queuePush(Queue* q, QDataType val);
void queuePop(Queue* q);
int queueSize(Queue* q);
int queueEmpty(Queue* q);
void queueDestroy(Queue* q);
QDataType queueFront(Queue* q);
QDataType queueBack(Queue* q);
Queue.c:
#include "Queue.h"
void queueInit(Queue* q)
{
q->_front = q->_rear = NULL;
q->size = 0;
}
Qnode* createNode(QDataType val)
{
Qnode* node = (Qnode*)malloc(sizeof(Qnode));
node->_data = val;
node->_next = NULL;
return node;
}
void queuePush(Queue* q, QDataType val)
{
Qnode* node = createNode(val);
if (q->_front == NULL)
q->_front = q->_rear = node;
else
{
q->_rear->_next = node;
q->_rear = node;
}
q->size++;
}
void queuePop(Queue* q)
{
if (q->_front)
{
Qnode* next = q->_front->_next;
free(q->_front);
q->_front = next;
if (q->_front == NULL)
q->_rear = NULL;
q->size--;
}
}
int queueSize(Queue* q)
{
return q->size;
}
QDataType queueFront(Queue* q)
{
return q->_front->_data;
}
QDataType queueBack(Queue* q)
{
return q->_rear->_data;
}
int queueEmpty(Queue* q)
{
if (q->_front == NULL)
return 1;
return 0;
}
void queueDestroy(Queue* q)
{
Qnode* cur = q->_front;
while (cur)
{
Qnode* next = cur->_next;
free(cur);
cur = next;
}
q->_front = q->_rear = NULL;
q->size = 0;
}
BinaryTree.h:
#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "Queue.h"
TreeNode* CreateTree(DataType* PreOrderRes, int* curIdx)
{
if (PreOrderRes[*curIdx] == '#')
{
++(*curIdx);
return NULL;
}
else
{
TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
root->data = PreOrderRes[*curIdx];
++(*curIdx);
root->left = CreateTree(PreOrderRes, curIdx);
root->right = CreateTree(PreOrderRes, curIdx);
return root;
}
}
void PreOrder(TreeNode* root)
{
if (root)
{
printf("%c ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
}
void InOrder(TreeNode* root)
{
if (root)
{
InOrder(root->left);
printf("%c ", root->data);
InOrder(root->right);
}
}
void PostOrder(TreeNode* root)
{
if (root)
{
PostOrder(root->left);
PostOrder(root->right);
printf("%c ", root->data);
}
}
void LevelOrder(TreeNode* root)
{
if (root == NULL)
return;
struct Queue q;
queueInit(&q);
queuePush(&q, root);
while (!queueEmpty(&q))
{
int sz = queueSize(&q);
while (sz--)
{
TreeNode* front = queueFront(&q);
printf("%c ", front->data);
queuePop(&q);
if (front->left)
queuePush(&q, front->left);
if (front->right)
queuePush(&q, front->right);
}
}
printf("\n");
queueDestroy(&q);
}
int GetTreeNodeSize(TreeNode* root)
{
if (root == NULL)
return 0;
int left = GetTreeNodeSize(root->left);
int right = GetTreeNodeSize(root->right);
return left + right + 1;
}
void GetTreeNodeSize2(TreeNode* root, int* sum)
{
if (root)
{
++(*sum);
GetTreeNodeSize2(root->left, sum);
GetTreeNodeSize2(root->right, sum);
}
}
int GetLeafSize(TreeNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return GetLeafSize(root->left) + GetLeafSize(root->right);
}
int GetKLevelSize(TreeNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
return GetKLevelSize(root->left, k - 1) +
GetKLevelSize(root->right, k - 1);
}
int GetHeight(TreeNode* root)
{
if (root == NULL)
return 0;
int lDepth = GetHeight(root->left);
int rDepth = GetHeight(root->right);
return lDepth > rDepth ? lDepth + 1 : rDepth + 1;
}
TreeNode* FindNode(TreeNode* root, DataType target)
{
if (root == NULL)
return NULL;
if (root->data == target)
return root;
struct TreeNode* res = FindNode(root->left, target);
if (res)
return res;
return FindNode(root->right, target);
}
void DestroyTree2(TreeNode** root)
{
if (*root)
{
DestroyTree2(&((*root)->left));
DestroyTree2(&((*root)->right));
free(*root);
*root = NULL;
}
}
bool IsCompleteBinaryTree(TreeNode* root)
{
if (root == NULL)
return true;
struct Queue q;
queueInit(&q);
queuePush(&q, root);
while (!queueEmpty(&q))
{
QDataType front = queueFront(&q);
queuePop(&q);
if (front)
{
queuePush(&q, front->left);
queuePush(&q, front->right);
}
else
{
break;
}
}
while (!queueEmpty(&q))
{
QDataType front = queueFront(&q);
queuePop(&q);
if (front)
return false;
}
queueDestroy(&q);
return true;
}
|