大家好我是小锋,今天我们来学习的是二叉树链式结构的实现
首先我们来学习一下二叉树的基本操作
在看二叉树基本操作前我们来回顾下二叉树的概念,
二叉树是:
1. 空树
2. 非空:根节点,根节点的左子树、根节点的右子树组成的。
二叉树的前序中序后序
学习二叉树结构,最简单的方式就是遍历。
所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。
遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
而前序 中序 后序是三种遍历二叉树的方式,具体的思路如下
前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
先访问 根 然后是 左子树 再是 右子树
中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
先访问 左子树 然后是 根 再是 右子树
后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
先访问 左子树 然后是 右子树 再是 根
我们来举个例子
所有的二叉树我们都可以看成三个组成部分 根 左子树 右子树
而子树又可以划分出这三个结构,直到全部子树为空树
这是一个二叉树,它的前序访问顺序是
1 2 3 NULL NULL NULL 4 5 NULL NULL 6 NULL NULL
中序访问顺序是
NULL 3 NULL 2 NULL 1 NULL 5 NULL 4 NULL 6 NULL
后序访问顺序是
NULL NULL 3 NULL 2 NULL NULL 5 NULL NULL 6 4 1
这里的NULL代表空树
我们了解了前中后序三种遍历方式后,我们用代码实现一下
首先我们快速的手动建立一棵简单的二叉树(这不是二叉树的创建方式,我们先了解基础操作后,对二叉树有一定的理解了,我再来学习二叉树的创建方式)
typedef int CMMlet;
typedef struct Binarytreenode BTnode;
struct Binarytreenode {
CMMlet size;//保存的数据
BTnode* lest;//左子树
BTnode* right;//右子树
};
//初始化
BTnode* byenode(CMMlet n) {
BTnode* ps = (BTnode*)malloc(sizeof(BTnode));
if (ps = NULL) {
printf("%s", strerror(errno));
}
ps->lest = NULL;
ps->right = NULL;
ps->size = n;
return ps;
}
//手动建立的二叉树
BTnode* BThead() {
BTnode* node1 = buynode(1);
BTnode* node2 = buynode(2);
BTnode* node3 = buynode(3);
BTnode* node4 = buynode(4);
BTnode* node5 = buynode(5);
BTnode* node6 = buynode(6);
node1->lest = node2;
node1->right = node4;
node2->lest = node3;
node4->lest = node5;
node4->right = node6;
return node1;
}
我们手动建立了一个如下的二叉树
现在我们来实现前序:主要是通过递归来实现
前序
void preorder(BTnode* node1) {
if (node1==NULL) {
printf("NULL ");//验证访问空子树
return;
}
printf("%d ", node1->size);//验证访问顺序
preorder(node1->lest);
preorder(node1->right);
}
我们可以输出验证一下
而中序,后序只是在前序代码的基础上换一下访问位置就行了
中序
//中序
void inorder(BTnode* node1) {
if (node1 == NULL) {
printf("NULL ");//验证访问空子树
return;
}
inorder(node1->lest);
printf("%d ", node1->size);
inorder(node1->right);
}
后序
//后序
void postorder(BTnode* node1) {
if (node1 == NULL) {
printf("NULL ");
return;
}
postorder(node1->lest);
postorder(node1->right);
printf("%d ", node1->size);
}
这里大家来看看图解
二叉树的基础操作
我们现在学的这种基本的二叉树它的增删查改是没有价值的,只有我们后序深入的学习,在搜索二叉树,红黑树...这些后才有价值,所有我们现在主要学习的基本操作如下
二叉树的节点个数
基本思路是遍历二叉树,然后遇到节点就返回+1;
// 二叉树节点个数
int BinaryTreeSize(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
return BinaryTreeSize(node1->lest)+BinaryTreeSize(node1->right)+1;
}
二叉树叶子节点个数
我们来想一想基本思路
我们遍历二叉树,如果遇到叶子节点我们返回1,如果遇到空指针返回0.那我们终止递归的条件是不是出现了?
//二叉树叶子节点个数
int BinaryTreeLeafSize(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
if (node1->lest == NULL && node1->right == NULL) {
return 1;
}
return BinaryTreeLeafSize(node1->lest) + BinaryTreeLeafSize(node1->right);
}
二叉树第k层的节点个数
我们的思路是将,每进入一层递归我们就--k,这样当k==1是我们就找到了第k层了,然后将第k层的返回+1计数就可以了。
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTnode* node1, int k) {
if (node1 == NULL) {
return 0;
}
if (k == 1) {
return 1;
}
return BinaryTreeLevelKSize(node1->lest, k - 1) + BinaryTreeLevelKSize(node1->right, k - 1);
二叉树查找值为x的节点
要实现这个函数我们先要知道我们是用递归实现的我们返回x的节点时是一层一层返回的,所有我们找到x后要逐层返回x的指针,思路是比较简单的找到x的节点我们就逐层返回没找到我们就返回NULL。
// 二叉树查找值为x的节点
BTnode* BinaryTreeFind(BTnode* node1, CMMlet x) {
if (node1 == NULL) {
return NULL;
}
if (node1->size == x) {
return node1;
}
BTnode*ps=BinaryTreeFind(node1->lest, x);
if (ps != NULL) {
return ps;
}
BTnode*cur=BinaryTreeFind(node1->right, x);
if (cur != NULL) {
return NULL;
}
return NULL;
}
求二叉树的高度
二叉树的高度我们可以看成是它最长的一条路径的长度,所以我们的思路是一直往下遍历,遇到空树返回0,不是空树就加一返回,然后在每个根上作比较,返回大的值递归到最后就是最长的一条路径就是高度
//二叉树的高度
int higebttree(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
int n = higebttree(node1->lest) + 1;
int h = higebttree(node1->right) + 1;
return h > n ? h : n;
}
二叉树的层序遍历
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在 层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层 上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
这里我们要用到队列,队列的先进先出非常契合层序遍历,所以我们要创建一个队列,队列的玩法我们已经学过了,所以我们这里直接上代码
下面是队列的代码大家可直接用
Queue.h
# include<stdio.h>
# include<assert.h>
# include<stdlib.h>
# include<string.h>
# include<errno.h>
# include<stdbool.h>
typedef struct Qhead Qhead;
typedef struct Queue Queue;
//typedef BTnode* CMMlet;
typedef struct Binarytreenode BTnode;
//二叉树
struct Binarytreenode {
int size;//保存的数据
BTnode* lest;//左子树
BTnode* right;//右子树
};
//链表结构
struct Qhead {
BTnode* size;
struct Qhead* next;
};
//队列结构
struct Queue {
Qhead* top;//队头
Qhead* end;//队尾
int SZ;
};
//初始化
void Queueinit(Queue* head);
//队尾输入数据
void Queuepush(Queue* head, BTnode* n);
//判断队列是否为空
bool QueueEmpty(Queue* haed);
//队头删除数据
void Queuepop(Queue* head);
//获取对头数据
BTnode* Queuefrost(Queue* head);
//获取队列中的有效元素个数
int Queuesize(Queue* head);
//销毁队列
void QueueDestroy(Queue* head);
Queue.c
# include"Queue.h"
//初始化
void Queueinit(Queue* head) {
assert(head);
head->end = NULL;
head->top = NULL;
head->SZ = 0;
}
//队尾输入数据
void Queuepush(Queue* head, BTnode* n) {
assert(head);
Qhead* ps = (Qhead*)malloc(sizeof(Qhead));
if (ps == NULL) {
printf("%s", strerror(errno));
return;
}
ps->next = NULL;
ps->size = n;
if (head->top) {
head->end->next = ps;
head->end = head->end->next;
}
else {
head->top = ps;
head->end = ps;
}
head->SZ++;
}
//判断队列是否为空
bool QueueEmpty(Queue* head) {
assert(head);
return head->SZ == 0;
}
//队头删除数据
void Queuepop(Queue* head) {
assert(head);
assert(!QueueEmpty(head));
if (head->top->next == NULL) {
free(head->top);
head->top = NULL;
head->end = NULL;
}
else {
Qhead* cur = head->top->next;
head->top->next = NULL;
free(head->top);
head->top = cur;
}
head->SZ--;
}
//获取队头数据
BTnode* Queuefrost(Queue* head) {
assert(head);
assert(!QueueEmpty(head));
return head->top->size;
}
//获取队列中的有效元素个数
int Queuesize(Queue* head) {
assert(head);
return head->SZ;
}
//销毁队列
void QueueDestroy(Queue* head) {
assert(head);
while (head->top == NULL) {
Qhead* cur = head->top->next;
head->top->next = NULL;
free(head->top);
head->top = cur;
}
head->top = NULL;
head->end = NULL;
head->SZ = 0;
}
下面是层序遍历的函数实现
//层序遍历
void everBTnode(BTnode* node) {
assert(node);
Queue head;
Queueinit(&head);
Queuepush(&head,node);
while (!QueueEmpty(&head)) {
BTnode* frost = Queuefrost(&head);
Queuepop(&head);
printf("%d\n", frost->size);
if (frost->lest != NULL)
everBTnode(frost->lest);
if (frost->right != NULL)
everBTnode(frost->right);
}
}
我们可以来测试一下
# include"Queue.h"
//初始化
BTnode* buynode(int n) {
BTnode* ps = (BTnode*)malloc(sizeof(BTnode));
if (ps == NULL) {
printf("%s", strerror(errno));
}
ps->lest = NULL;
ps->right = NULL;
ps->size = n;
return ps;
}
BTnode* BThead() {
BTnode* node1 = buynode(1);
BTnode* node2 = buynode(2);
BTnode* node3 = buynode(3);
BTnode* node4 = buynode(4);
BTnode* node5 = buynode(5);
BTnode* node6 = buynode(6);
node1->lest = node2;
node1->right = node4;
node2->lest = node3;
node4->lest = node5;
node4->right = node6;
return node1;
}
//层序遍历
void everBTnode(BTnode* node) {
assert(node);
Queue head;
Queueinit(&head);
Queuepush(&head,node);
while (!QueueEmpty(&head)) {
BTnode* frost = Queuefrost(&head);
Queuepop(&head);
printf("%d\n", frost->size);
if (frost->lest != NULL)
everBTnode(frost->lest);
if (frost->right != NULL)
everBTnode(frost->right);
}
}
int main () {
BTnode* rnode = BThead();
everBTnode(rnode);
return 0;
}
下面是本期的代码了大家可以参考一下
# include<stdio.h>
# include<assert.h>
# include<stdlib.h>
# include<string.h>
# include<errno.h>
# include<stdbool.h>
typedef int CMMlet;
typedef struct Binarytreenode BTnode;
struct Binarytreenode {
CMMlet size;//保存的数据
BTnode* lest;//左子树
BTnode* right;//右子树
};
// 二叉树节点个数
int BinaryTreeSize(BTnode* node1);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTnode* node1);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTnode* node1, int k);
// 二叉树查找值为x的节点
BTnode* BinaryTreeFind(BTnode* node1, CMMlet x);
//初始化
BTnode* buynode(int n) {
BTnode* ps = (BTnode*)malloc(sizeof(BTnode));
if (ps == NULL) {
printf("%s", strerror(errno));
}
ps->lest = NULL;
ps->right = NULL;
ps->size = n;
return ps;
}
//前序
void preorder(BTnode* node1) {
if (node1==NULL) {
printf("NULL ");//验证访问空子树
return;
}
printf("%d ", node1->size);//验证访问顺序
preorder(node1->lest);
preorder(node1->right);
}
//中序
void inorder(BTnode* node1) {
if (node1 == NULL) {
printf("NULL ");//验证访问空子树
return;
}
inorder(node1->lest);
printf("%d ", node1->size);
inorder(node1->right);
}
//后序
void postorder(BTnode* node1) {
if (node1 == NULL) {
printf("NULL ");
return;
}
postorder(node1->lest);
postorder(node1->right);
printf("%d ", node1->size);
}
//手动建立的二叉树
BTnode* BThead() {
BTnode* node1 = buynode(1);
BTnode* node2 = buynode(2);
BTnode* node3 = buynode(3);
BTnode* node4 = buynode(4);
BTnode* node5 = buynode(5);
BTnode* node6 = buynode(6);
node1->lest = node2;
node1->right = node4;
node2->lest = node3;
node4->lest = node5;
node4->right = node6;
return node1;
}
//遍历方式测试
int main() {
BTnode* node=BThead();
preorder(node);
printf("\n");
inorder(node);
printf("\n");
postorder(node);
printf("\n");
return 0;
}
// 二叉树节点个数
int BinaryTreeSize(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
return BinaryTreeSize(node1->lest)+BinaryTreeSize(node1->right)+1;
}
//二叉树叶子节点个数
int BinaryTreeLeafSize(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
if (node1->lest == NULL && node1->right == NULL) {
return 1;
}
return BinaryTreeLeafSize(node1->lest) + BinaryTreeLeafSize(node1->right);
}
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTnode* node1, int k) {
if (node1 == NULL) {
return 0;
}
if (k == 1) {
return 1;
}
return BinaryTreeLevelKSize(node1->lest, k - 1) + BinaryTreeLevelKSize(node1->right, k - 1);
}
// 二叉树查找值为x的节点
BTnode* BinaryTreeFind(BTnode* node1, CMMlet x) {
if (node1 == NULL) {
return NULL;
}
if (node1->size == x) {
return node1;
}
BTnode*ps=BinaryTreeFind(node1->lest, x);
if (ps != NULL) {
return ps;
}
BTnode*cur=BinaryTreeFind(node1->right, x);
if (cur != NULL) {
return NULL;
}
return NULL;
}
//二叉树的高度
int higebttree(BTnode* node1) {
if (node1 == NULL) {
return 0;
}
int n = higebttree(node1->lest) + 1;
int h = higebttree(node1->right) + 1;
return h > n ? h : n;
}
节点个数
//int main() {
// BTnode* node = BThead();
// int mon=BinaryTreeSize(node);
// printf("%d ", mon);
// return 0;
//}
叶子节点个数
//int main() {
// BTnode* node = BThead();
// int mon = BinaryTreeLeafSize(node);
// printf("%d ", mon);
// return 0;
//}
//int main() {
// BTnode* node = BThead();
// int mon = higebttree(node);
// printf("%d ", mon);
// return 0;
//}
以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。