1.树的基本概念
2.二叉树的基本概念
2.1特殊的二叉树
满二叉树
完全二叉树
3.二叉树的性质
4 .二叉树的存储结构
5.二叉树的遍历
5.1 前序、中序以及后序遍历
5.2 层序遍历
6.二叉树代码实现
思路
前序/中序/后序遍历
递归思想:将当前的大问题拆解成小问题
以前序遍历为例:
当前问题——打印根,打印左子树,打印右子树
子问题——如图
递归返回条件——root==NULL
前序遍历代码
//前序遍历 根节点 左节点 右节点
void BinaryTreePrevOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
printf("%d ", root->data);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
中序遍历代码
void BinaryTreeInOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
BinaryTreeInOrder(root->left);
printf("%d ", root->data);
BinaryTreeInOrder(root->right);
}
后序遍历代码
void BinaryTreePostOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
BinaryTreePostOrder(root->left);
BinaryTreePostOrder(root->right);
printf("%d ", root->data);
}
节点个数/叶子节点个数/树高/第k层叶子数
1.节点个数
递归思想:
情况1:空,0个
情况2:不为空,左子树+右子树+1
2.叶子节点个数
情况1:空,返回0
情况2:只有一个结点,返回1
情况3:左子树+右子树
3.树的高度
情况1:空,返回0
情况2:左子树和右子树高度中大的值+1
4.第k层叶子数
情况1:空,返回0
情况2:非空,k==1,返回1
情况3:非空,k>1,左子树第k-1层+右子树第k-1层
int BinaryTreeSize(BTNode* root) {
if (root == NULL) {
return 0;
}
if (root->left == NULL && root->right == NULL) {
return 1;
}
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;
}
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int leftHeight = TreeHeight(root->left);
int rightHeight = TreeHeight(root->right);
return leftHeight > rightHeight ?
leftHeight + 1 : rightHeight + 1;
}
int BinaryTreeLevelKSize(BTNode* root, int k) {
if (root == NULL) {
return 0;
}
if (k==1) {
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
查找值为x的节点
递归思想
情况1:空,返回NULL
情况2:不为空,根值为x,返回根节点
情况3:不为空,根值不为x,查找左子树,有则返回
左子树中无,查找右子树,有则返回
右子树中也无,返回空
BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {
BTNode* ret = NULL;
if (root == NULL) {
return NULL;
}
if (root->data == x) {
ret = root;
return ret;
}
if (BinaryTreeFind(root->left, x) != NULL) {
ret = BinaryTreeFind(root->left, x);
}
if (BinaryTreeFind(root->right, x) != NULL) {
ret = BinaryTreeFind(root->right, x);
}
}
层序遍历/完全二叉树
层序遍历
1.根进队列
2.节点出队列时,该节点的子节点(非空)进队列
3.当队列为空时,循环结束
完全二叉树
1.进行层序遍历,空也进队列
2.遇到第一个空节点,开始判断,后面全空就是完全二叉树,后面有非空就不是完全二叉树
void BinaryTreeLevelOrder(BTNode* root) {
if (!root) {
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (QueueSize(&q) > 0) {
BTNode* head = QueueFront(&q);
if (head->left) {
QueuePush(&q, head->left);
}
if (head->right) {
QueuePush(&q, head->right);
}
printf("%d", head->data);
QueuePop(&q);
}
QueueDestroy(&q);
}
bool BinaryTreeComplete(BTNode* root) {
if (!root) {
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (QueueSize(&q) > 0) {
BTNode* head = QueueFront(&q);
if (head == NULL) {
break;
}
QueuePush(&q, head->left);
QueuePush(&q, head->right);
QueuePop(&q);
}
while(!QueueEmpty(&q)){
BTNode* head = QueueFront(&q);
if (head) {
QueueDestroy(&q);
return false;
}
QueuePop(&q);
}
QueueDestroy(&q);
return true;
}
代码汇总
binarytree.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate();
// 二叉树销毁
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);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
binarytree.c
#define _CRT_SECURE_NO_WARNINGS
#include "binarytree.h"
#include "queue.h"
BTNode* BuyNode(BTDataType x) {
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL) {
perror("malloc fail!");
}
newnode->left = NULL;
newnode->right = NULL;
newnode->data = x;
return newnode;
}
BTNode* BinaryTreeCreate() {
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);
Node1->left = Node2;
Node1->right = Node3;
Node2->left = Node4;
Node2->right = Node5;
Node3->left = Node6;
//Node6->left = Node7;
return Node1;//返回根节点
}
//前序遍历 根节点 左节点 右节点
void BinaryTreePrevOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
printf("%d ", root->data);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
void BinaryTreeInOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
BinaryTreeInOrder(root->left);
printf("%d ", root->data);
BinaryTreeInOrder(root->right);
}
void BinaryTreePostOrder(BTNode* root) {
if (root == NULL) {
printf("N ");
return;
}
BinaryTreePostOrder(root->left);
BinaryTreePostOrder(root->right);
printf("%d ", root->data);
}
int BinaryTreeSize(BTNode* root) {
if (root == NULL) {
return 0;
}
if (root->left == NULL && root->right == NULL) {
return 1;
}
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;
}
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
int BinaryTreeLevelKSize(BTNode* root, int k) {
if (root == NULL) {
return 0;
}
if (k==1) {
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int leftHeight = TreeHeight(root->left);
int rightHeight = TreeHeight(root->right);
return leftHeight > rightHeight ?
leftHeight + 1 : rightHeight + 1;
}
BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {
BTNode* ret = NULL;
if (root == NULL) {
return NULL;
}
if (root->data == x) {
ret = root;
return ret;
}
if (BinaryTreeFind(root->left, x) != NULL) {
ret = BinaryTreeFind(root->left, x);
}
if (BinaryTreeFind(root->right, x) != NULL) {
ret = BinaryTreeFind(root->right, x);
}
}
void BinaryTreeLevelOrder(BTNode* root) {
if (!root) {
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (QueueSize(&q) > 0) {
BTNode* head = QueueFront(&q);
if (head->left) {
QueuePush(&q, head->left);
}
if (head->right) {
QueuePush(&q, head->right);
}
printf("%d", head->data);
QueuePop(&q);
}
QueueDestroy(&q);
}
bool BinaryTreeComplete(BTNode* root) {
if (!root) {
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (QueueSize(&q) > 0) {
BTNode* head = QueueFront(&q);
if (head == NULL) {
break;
}
QueuePush(&q, head->left);
QueuePush(&q, head->right);
QueuePop(&q);
}
while(!QueueEmpty(&q)){
BTNode* head = QueueFront(&q);
if (head) {
QueueDestroy(&q);
return false;
}
QueuePop(&q);
}
QueueDestroy(&q);
return true;
}
void BinaryTreeDestory(BTNode* root) {
if (root==NULL) {
return;
}
BinaryTreeDestory(root->left);
BinaryTreeDestory(root->right);
free(root);
}
在实现层序遍历时,会使用到队列。但由于C语言中没有现成的数据结构队列可以直接使用,需要自己实现。
queue.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef struct BinaryTreeNode* QDataType;
typedef struct QListNode{
struct QListNode* next;
QDataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
queue.c
#define _CRT_SECURE_NO_WARNINGS
#include "queue.h"
// 初始化队列
void QueueInit(Queue* q) {
assert(q);
q->phead = q->ptail = NULL;
q->size = 0;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data) {
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL) {
perror("malloc fail!");
exit(1);
}
else {
newnode->data = data;
newnode->next = NULL;
if (q->ptail == NULL) {
q->phead = q->ptail = newnode;
q->size++;
}
else {
q->ptail->next =newnode;
q->ptail = newnode;
q->size++;
}
}
}
// 队头出队列
void QueuePop(Queue* q) {
assert(q);
assert(q->size != 0);
if (q->phead->next == NULL) {
free(q->ptail);
q->ptail = q->phead = NULL;
q->size--;
}
else {
QNode* next = q->phead->next;
free(q->phead);
q->phead = next;
q->size--;
}
}
// 获取队列头部元素
QDataType QueueFront(Queue* q) {
assert(q);
assert(q->size > 0);
return q->phead->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q) {
assert(q);
assert(q->size > 0);
return q->ptail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q) {
assert(q);
return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q) {
assert(q);
return !QueueSize(q);
}
// 销毁队列
void QueueDestroy(Queue* q) {
assert(q);
while (q->size) {
QueuePop(q);
}
q->phead = NULL;
q->ptail = NULL;
}
7.堆及堆排序及TopK问题
详见我的另一篇文章~(TopK问题待更)
数据结构 | 详解二叉树——堆与堆排序