二叉树是孩子节点数最多只有两个的树,在许多算法中都能看到它,例如:二叉平衡树,AVL树,红黑树等,为了掌握这些算法,必须对二叉树有基本的了解。所以,本文将介绍普通二叉树的构建。
在数据结构中, 二叉树是树节点数最多为两个的树结构。而且,二叉树的子节点分为左子树与右子树,其次序不能随意颠倒。
深度为 k
的二叉树结点最多为 ( 2k-1 )。度为0的结点数
为 ( n 0 n_0 n0) ,度为 2 的节点数
为 ( n 2 n_2 n2 ) ,则 n 0 = n 2 + 1 \bold{n_0 = n_2 + 1} n0=n2+1若 i > 0
, i 位置节点的双亲序号:( i - 1 )/ 2 ;i = 0, i 为根结点编号,无双亲节点若 2i + 1 < n
,左孩子序号:2i + 1 ; 2i + 1 ≥ \geq ≥ n 否则无左孩子若 2i + 2 < n
, 右孩子序号:2i+2 ; 2i+2 ≥ \geq ≥ n 否则无右孩子二叉树的实现能够通过 顺序存储结构
与 链表存储结构
实现。
根据二叉树的性质,二叉树的孩子结点分别存储在 2i + 1 与 2i + 2 的空间,但我们不难得知,这种存储方式只适用于完全二叉树,对于普通二叉树,将造成大量的空间浪费。在极端环境下,一个深度为 k 且只有 k 个结点的单支树(树中不存在度为 2 的结点)却需要长度为2k-1的一维数组。
通过二叉树的定义可知,二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支组成
。所以,表示二叉树的域至少要有3个,有时为了方便找到双亲结点还会新增一个指向其双亲结点的指针域,而它们分别被称为二叉链表
与三叉链表
。
二叉树的二叉链结构声明与函数声明:
//头文件
#include
#include
#include
#include
// ---- 二叉树的二叉链存储表示
typedef char BTDataType;
typedef struct BinaryTreeNode {
BTDataType _data; //当前节点值域
struct BinaryTreeNode *_left; //左孩子
struct BinaryTreeNode *_right; //右孩子
} BTNode;
// ------
// ---- 二叉树的三叉链存储表示
//本文不写三叉链的实现
struct BinaryTreeNode
{
struct BinTreeNode* _pParent; // 指向当前节点的双亲
struct BinTreeNode* _pLeft; // 指向当前节点左孩子
struct BinTreeNode* _pRight; // 指向当前节点右孩子
BTDataType _data; // 当前节点值域
};
// -------
// 通过前序遍历的数组"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);
// 二叉树第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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode *root);
二叉树的层序遍历就是从左到右依序遍历树,需要一个队列来实现,因为队列的先进先出符合层序遍历的遍历条件,词穷图见 ⇓ \Downarrow ⇓
//二叉树的层序遍历
void BinaryTreeLevelOrder(BTNode *root)
{
if(!root)
return;
Que que; //队列的声明与初始化
QueueInit(&que);
QueuePush(&que, root);
while(!QueueEmpty(&que))
{
int sz = QueueSize(&que); //记录当前队列数据量
while(sz--)
{
BTNode* node = QueueFront(&que);
printf("%c ", node->_data);
// 依次入队列左右结点,注意判断是否为空
if(node->_left)
QueuePush(&que, node->_left);
if(node->_right)
QueuePush(&que, node->_right);
QueuePop(&que);
}
}
QueueDestroy(&que);
}
该函数和层序遍历相似,通过队列模拟层序遍历,直到遇到一个NULL指针,然后继续循环出队列,如果遇到非空结点则说明不是完全二叉树。
int BinaryTreeComplete(BTNode *root)
{
Que que;
QueueInit(&que);
QueuePush(&que, root);
while(!QueueEmpty(&que)) //层序遍历
{
if(!QueueFront(&que))
break;
BTNode* node = QueueFront(&que);
QueuePush(&que, node->_left);
QueuePush(&que, root->_right);
QueuePop(&que);
}
while(!QueueEmpty(&que)) //判断是否有非空结点
{
if(QueueFront(&que))
return 0;
QueuePop(&que);
}
QueueDestroy(&que);
return 1;
}
#include "BTNode.h"
#include "queue.h"
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode *BinaryTreeCreate(BTDataType *a, int n, int *pi) {
if (a[*pi] == '#' || *pi == n) {
(*pi)++
return NULL;
}
BTNode *node = (BTNode *)malloc(sizeof(BTNode));
node->_data = a[(*pi)++];
node->_left = BinaryTreeCreate(a, n, pi); //建造左右孩子并返回
node->_right = BinaryTreeCreate(a, n, pi);
return node;
}
//二叉树的销毁
void BinaryTreeDestory(BTNode **root) {
if (*root == NULL)
return;
//通过后序方式销毁
BinaryTreeDestory(&((*root)->_left));
BinaryTreeDestory(&((*root)->_right));
free(*root);
}
int BinaryTreeSize(BTNode *root) {
if (!root)
return 0;
return BinaryTreeSize(root->_left) +
BinaryTreeSize(root->_right) + 1;
}
int BinaryTreeLeafSize(BTNode *root) {
if (!root)
return 0;
if (!root->_left && !root->_right)
return 1;
int left = BinaryTreeLeafSize(root->_left);
int right = BinaryTreeLeafSize(root->_right);
return left + right;
}
//寻找值为x的结点
BTNode *BinaryTreeFind(BTNode *root, BTDataType x) {
if (!root)
return NULL;
if (root->_data == x)
return root;
BTNode *left = BinaryTreeFind(root->_left, x);
BTNode *right = BinaryTreeFind(root->_right, x);
// 如果left 和 right指针不为空,则说明找到了目标
if (left)
return left;
if (right)
return right;
return NULL;
}
//第k层结点个数
int BinaryTreeLevelKSize(BTNode *root, int k) {
if (!root)
return 0;
if (k == 1) //k == 1
return 1;
return BinaryTreeLevelKSize(root->_left, k - 1) +
BinaryTreeLevelKSize(root->_right, k - 1);
}
//前序遍历
void BinaryTreePrevOrder(BTNode *root) {
if (!root) {
return;
}
printf("%c->", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
//中序遍历
void BinaryTreeInOrder(BTNode *root) {
if (!root)
{
return;
}
BinaryTreeInOrder(root->_left);
printf("%c->", root->_data);
BinaryTreeInOrder(root->_right);
}
// 后序遍历
void BinaryTreePostOrder(BTNode *root)
{
if(!root)
{
return;
}
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%c->", root->_data);
}
//二叉树的层序遍历
void BinaryTreeLevelOrder(BTNode *root)
{
if(!root)
return;
Que que;
QueueInit(&que);
QueuePush(&que, root);
while(!QueueEmpty(&que))
{
int sz = QueueSize(&que);
while(sz--)
{
BTNode* node = QueueFront(&que);
printf("%c ", node->_data);
if(node->_left)
QueuePush(&que, node->_left);
if(node->_right)
QueuePush(&que, node->_right);
QueuePop(&que);
}
}
QueueDestroy(&que);
}
int BinaryTreeComplete(BTNode *root)
{
Que que;
QueueInit(&que);
QueuePush(&que, root);
while(!QueueEmpty(&que)) //层序遍历
{
if(!QueueFront(&que))
break;
BTNode* node = QueueFront(&que);
QueuePush(&que, node->_left);
QueuePush(&que, root->_right);
QueuePop(&que);
}
while(!QueueEmpty(&que))
{
if(QueueFront(&que) //遇到非空结点证明不是完全二叉树
return 0;
QueuePop(&que);
}
return 1;
}