这里写目录标题
1:创建链式二叉树
用简单的方法,创建简易的链式二叉树
1.1节点基本结构
链式二叉树的节点基本结构为一个数据变量,两个指向节点的指针组成
typedef int HeapData;
typedef struct Heap
{
HeapData data;//数据
struct Heap* LeftNode;//左孩子
struct Heap* RightNode;//右孩子
}HP;
1.2节点的创建
由于咱是链表,需要用malloc从堆上申请一个节点空间,并将数据赋值,左右孩子在申请时默认指向NULL。
HP* CreateHeap(HeapData x)
{
HP* cur = (HP*)malloc(sizeof(HP));
if (NULL == cur)//如果内存申请失败
{
perror("malloc");
exit(-1);
}
cur->data = x;//给节点数据变量赋值
cur->LeftNode = cur->RightNode = NULL;//将指针置空
return cur;//把节点指针返回
}
1.3节点之间的链接
选一个节点做根,并把其他节点根据自身要求连接即可
int main()
{
HP *p1, * p2, * p3, * p4, * p5, * p6, * p7, * p8;
p1 = CreateHeap(10);//创建节点
p2 = CreateHeap(20);//创建节点
p3 = CreateHeap(30);//创建节点
p4 = CreateHeap(40);//创建节点
p5 = CreateHeap(50);//创建节点
p6 = CreateHeap(60);//创建节点
p7 = CreateHeap(70);//创建节点
p8 = CreateHeap(80);//创建节点
p1->LeftNode = p2;//p1节点左孩子指针,指向p2
p1->RightNode = p3;//p1节点右孩子指针,指向p3
p2->LeftNode = p4;//p2节点左孩子指针,指向p4
p2->RightNode = p5;
p3->LeftNode = p6;
p3->RightNode = p7;
p4->LeftNode = p8;
return 0;
}
上述代码我创建的链式二叉树如下图,创建节点时默认赋值左右孩子为NULL,所以创建好后只管链接就好了没链接的默认指向NULL表示结束了。
注意:下面代码演示也是用下图二叉树测试哦
2:遍历二叉树
遍历二叉树分为前序遍历,中序遍历,后续遍历 及 层序遍历
四种方式的访问节点数据顺序分别为
前序:根(数据) --> 左子树 --> 右子树;
中序:左子树 --> 根(数据) --> 右子树;
后序:左子树 --> 右子树 --> 根(数据);
层序:从根开始自上而下每层从左到右访问;
递归的要点
由于本篇用的递归比较多,我简要总结了递归函数的俩个要点
1:单层递归的主要逻辑
2:递归结束条件
比如
前序遍历的逻辑:先访问根再访问左孩子,然后访问右孩子
前序遍历结束条件:遇到NULL结束
2.1前序遍历
由于数据访问顺序是根(数据) --> 左子树 --> 右子树,
所以遍历结果是:10 20 40 80 NULL NULL NULL 50 NULL NULL 30 60 NULL NULL 70 NULL NULL
//前序遍历
void FrontHeap(HP* head)
{
if (NULL == head)//遍历完了
{
printf(" NULL");
return;
}
printf(" %d", head->data);//根(访问数据)
FrontHeap(head->LeftNode);//左子树
FrontHeap(head->RightNode);//右子树
}
2.2中序遍历
由于数据访问顺序是左子树 --> 根(数据) --> 右子树;
所以遍历结果是:NULL 80 NULL 40 NULL 20 NULL 50 NULL 10 NULL 60 NULL 30 NULL 70 NULL
void MiddleHeap(HP* head)//中序遍历
{
if (NULL == head)
{
printf(" NULL");
return;
}
MiddleHeap(head->LeftNode);//左子树
printf("%d ", head->data);//根(访问数据)
MiddleHeap(head->RightNode);//右子树
}
2.3后序遍历
由于数据访问顺序是左子树 --> 右子树 --> 根(数据);
所以遍历结果是:NULL NULL 80 NULL 40 NULL NULL 50 20 NULL NULL 60 NULL NULL 70 30 10
void TailHeap(HP* head)//后序遍历
{
if (NULL == head)
{
printf(" NULL");
return;
}
TailHeap(head->LeftNode);//左子树
TailHeap(head->RightNode);//右子树
printf(" %d", head->data);//根(访问数据)
}
2.4层序遍历
层序遍历的实现需要用队的先进先出思想,所以层序遍历需要用队来辅助实现;
实现思想:
1:将链式二叉树的根入队
2:每次将队头出队时先打印,然后判断左右孩子是否为空,不为空则将左右孩子入队。最后将对头出队,依此循环;
3:如果队为空时则结束循环
层序:从根开始自上而下每层从左到右访问;
所以遍历结果是:10 20 30 40 50 60 70 80
//层序遍历
void StrataHeap(HP* head)
{
assert(head);
Team Tm;//创建一个队结构
TmInit(&Tm);//初始化队
TmPus(&Tm, head);//将链式二叉树的根入队
while (!TmEmpty(&Tm))//队内不为空(有数据)则进入循环
{
HP* cur = TmHead(&Tm);
printf("%d ", cur->data);//打印队头数据
if (cur->LeftNode != NULL)//如果对头数据左孩子不为空
{
TmPus(&Tm, cur->LeftNode);//左孩子入队
}
if (cur->RightNode != NULL)//如果对头数据右孩子不为空
{
TmPus(&Tm, cur->RightNode);//右孩子入队
}
TmPop(&Tm);//出队
}
}
这里只展示了层序遍历函数,此文章用到的所有函数完整源代码放在文章的结尾
3 链式二叉树常用外部接口
1:求链式二叉树节点个数
2:求链式二叉树叶节点个数
3:求链式二叉树的高度(有几层)
4:求链式二叉树第K层节点个数
3.1求链式二叉树节点个数
依然为递归实现:如果该节点为空则不是节点返回0,不为空则返回左节点个数加右节点个数 ,加 1(加的是当前节点)
//求二叉树节点个数
int HeapSize(HP* head)
{
if (NULL == head)//如果为空则不是节点返回0
{
return 0;
}
return HeapSize(head->LeftNode)
+ HeapSize(head->RightNode) + 1;
//返回 左节点个数加右节点个数 ,加 1(加的是当前节点)
}
3.2求链式二叉树叶节点个数
依然为递归实现
主要思想:如果该节点为空返回0,如果该节点左右孩子都为NULL则他为叶节点所以返回1 ,递归左右孩子并相加。
//求二叉树叶子节点个数
int HeapLeafSize(HP* head)
{
if (head == NULL)
{
return 0;
}
if (head->LeftNode == NULL && head->RightNode == NULL)
{
return 1;//如果为叶节点则返回1
}
return HeapLeafSize(head->LeftNode)
+ HeapLeafSize(head->RightNode);//递归左右孩子并相加
}
3.3求链式二叉树的高度(有几层)
依然为递归实现
主要思想:取左右节点节点较多的一方
//求二叉树高度
int Heaplen(HP* head)
{
if (head == NULL)
{
return 0;
}
int left, right;
left = Heaplen(head->LeftNode)+1;
right = Heaplen(head->RightNode)+1;
return left > right ? left : right;
}
3.4求链式二叉树第K层节点个数
依然为递归实现
主要思想:K为5时,由于每次递归的深度为1所以每次递归传k-1,当 k 等于1时说明已经到达第层。如不为空则返回1;
int HeapLevelSize(HP* head, int k )//求二叉树第K层节点个数
{
if (NULL == head)
{
return 0;
}
if (k == 1)//说明到达第k层了
{
return 1;
}
//如果K>1
return HeapLevelSize(head->LeftNode, k - 1) + HeapLevelSize(head->RightNode, k - 1);
}
本文章所用代码
Heap.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HeapData;
typedef struct Heap
{
HeapData data;//数据
struct Heap* LeftNode;//左孩子
struct Heap* RightNode;//右孩子
}HP;
HP* CreateHeap(HeapData x);//创建二叉树节点
void FrontHeap(HP* head);//前序遍历
void MiddleHeap(HP* head);//中序遍历
void TailHeap(HP* head);//后序遍历
void StrataHeap(HP* head);//层序遍历
int HeapSize(HP* head);//求二叉树节点个数
int HeapLeafSize(HP* head);//求二叉树叶子节点个数
int Heaplen(HP* head);//求二叉树高度
int HeapLevelSize(HP* head , int k);//求二叉树第K层节点个数
Team.h
#pragma once
#include"Heap.h"
typedef HP* TmData;
typedef struct TeamNode
{
TmData data;//队的数据
struct TeamNode* next;//链表指针
}TmNode;
typedef struct Team
{
TmNode* head;//队头
TmNode* tail;//队尾
int size;//队内数据个数
}Team;
//由于单链表尾删不太方便,所以咱采用头删尾插的思路
void TmInit(Team* Tm);//初始化
void TmDestroy(Team* Tm);//销毁
void TmPus(Team* Tm,TmData data);//入队
void TmPop(Team* Tm);//出队
TmData TmHead(Team* Tm);//获取头部数据
TmData TmTail(Team* Tm);//获取尾部数据
int TmSize(Team* Tm);//获取队中数据个数
bool TmEmpty(Team* Tm);//判断队是否为空
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
#include"Team.h"
HP* CreateHeap(HeapData x)
{
HP* cur = (HP*)malloc(sizeof(HP));
if (NULL == cur)//如果内存申请失败
{
perror("malloc");
exit(-1);
}
cur->data = x;
cur->LeftNode = cur->RightNode = NULL;
return cur;
}
//前序遍历
void FrontHeap(HP* head)
{
if (NULL == head)//遍历完了
{
printf(" NULL");
return;
}
printf(" %d", head->data);//根
FrontHeap(head->LeftNode);//左子树
FrontHeap(head->RightNode);//右子树
}
void MiddleHeap(HP* head)//中序遍历
{
if (NULL == head)
{
printf(" NULL");
return;
}
MiddleHeap(head->LeftNode);//左子树
printf(" %d", head->data);//根(访问数据)
MiddleHeap(head->RightNode);//右子树
}
void TailHeap(HP* head)//后序遍历
{
if (NULL == head)
{
printf(" NULL");
return;
}
TailHeap(head->LeftNode);//左子树
TailHeap(head->RightNode);//右子树
printf(" %d", head->data);//根
}
//层序遍历
void StrataHeap(HP* head)
{
assert(head);
Team Tm;//创建一个队结构
TmInit(&Tm);//初始化队
TmPus(&Tm, head);//将链式二叉树的根入队
while (!TmEmpty(&Tm))//队内不为空(有数据)则进入循环
{
HP* cur = TmHead(&Tm);
printf("%d ", cur->data);//打印队头数据
if (cur->LeftNode != NULL)//如果对头数据左孩子不为空
{
TmPus(&Tm, cur->LeftNode);//左孩子入队
}
if (cur->RightNode != NULL)//如果对头数据右孩子不为空
{
TmPus(&Tm, cur->RightNode);//右孩子入队
}
TmPop(&Tm);//出队
}
}
求二叉树节点个数
//int HeapSize(HP* head)
//{
// return head == NULL ? 0 :
// HeapSize(head->LeftNode) + HeapSize(head->RightNode) + 1;
//}
//求二叉树节点个数
int HeapSize(HP* head)
{
if (NULL == head)//如果为空则不是节点返回0
{
return 0;
}
return HeapSize(head->LeftNode) + HeapSize(head->RightNode) + 1;
//返回 左节点个数加右节点个数 ,加 1(加的是当前节点)
}
//求二叉树叶子节点个数
int HeapLeafSize(HP* head)
{
if (head == NULL)
{
return 0;
}
if (head->LeftNode == NULL && head->RightNode == NULL)//如果为叶节点
{
return 1;
}
return HeapLeafSize(head->LeftNode) + HeapLeafSize(head->RightNode);//递归左右孩子并相加
}
//求二叉树高度
int Heaplen(HP* head)
{
if (head == NULL)
{
return 0;
}
int left, right;
left = Heaplen(head->LeftNode)+1;
right = Heaplen(head->RightNode)+1;
return left > right ? left : right;
}
int HeapLevelSize(HP* head, int k )//求二叉树第K层节点个数
{
if (NULL == head)
{
return 0;
}
if (k == 1)//说明到达第k层了
{
return 1;
}
//如果K>1
return HeapLevelSize(head->LeftNode, k - 1) + HeapLevelSize(head->RightNode, k - 1);
}
Team.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Team.h"
void TmInit(Team* Tm)//初始化
{
assert(Tm);
Tm->size = 0;
Tm->head = NULL;
Tm->tail = NULL;
}
void TmDestroy(Team* Tm)//销毁
{
assert(Tm);
TmNode* cur = Tm->head;
while (cur)
{
TmNode* pp = cur;
cur = cur->next;
free(pp);//可不置空因为别人访问不到pp
}
Tm->head = NULL;
Tm->tail = NULL;
}
void TmPus(Team* Tm, TmData data)//入队
{
assert(Tm);
TmNode* newNode = (TmNode*)malloc(sizeof(TmNode));
if (newNode == NULL)//如果申请失败
{
perror("malloc");
exit(-1);
}
newNode->data = data;
newNode->next = NULL;
if (Tm->head == NULL)
{
Tm->head = newNode;
Tm->tail = newNode;
}
else
{
Tm->tail->next = newNode;
Tm->tail = newNode;
}
Tm->size++;
}
bool TmEmpty(Team* Tm)//判断队是否为空
{
assert(Tm);
return !Tm->size;//队内无数据返回真
}
void TmPop(Team* Tm)//出队
{
assert(Tm);
if (TmEmpty(Tm))
{
printf("队内无数据\n");
return;
}
TmNode* cur = Tm->head;
Tm->head = Tm->head->next;//头删
free(cur);
if (Tm->head == NULL)//如果已经删完了
{
Tm->tail = NULL;
}
Tm->size--;
}
TmData TmHead(Team* Tm)//获取头部数据
{
assert(Tm);
if (TmEmpty(Tm))
{
printf("队内无数据\n");
return NULL;
}
return Tm->head->data;
}
TmData TmTail(Team* Tm)//获取尾部数据
{
assert(Tm);
if (TmEmpty(Tm))
{
printf("队内无数据\n");
return -1;
}
return Tm->tail->data;
}
int TmSize(Team* Tm)//获取队中数据个数
{
assert(Tm);
return Tm->size;
}
main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
int main()
{
HP *p1, * p2, * p3, * p4, * p5, * p6, * p7, * p8;
p1 = CreateHeap(10);//创建节点
p2 = CreateHeap(20);
p3 = CreateHeap(30);
p4 = CreateHeap(40);
p5 = CreateHeap(50);
p6 = CreateHeap(60);
p7 = CreateHeap(70);
p8 = CreateHeap(80);
p1->LeftNode = p2;
p1->RightNode = p3;
p2->LeftNode = p4;
p2->RightNode = p5;
p3->LeftNode = p6;
p3->RightNode = p7;
p4->LeftNode = p8;
FrontHeap(p1);
printf("\n");
MiddleHeap(p1);
printf("\n");
TailHeap(p1);
printf("\n");
StrataHeap(p1);
printf("\n");
printf("节点个数=>%d ", HeapSize(p1));
printf("\n叶节点个数=>%d ", HeapLeafSize(p1));
printf("\n树的高度=>%d ", Heaplen(p1));
printf("\n第K层节点个数=>%d ", HeapLevelSize(p1,2));
return 0;
}
希望这篇博客能够对你有所帮助,我们下期再见~