【数据结构】C语言实现二叉树(二叉树的链式结构实现)

news/2024/11/2 15:29:39/

二叉树的链式结构实现

  • 一、链式二叉树结点定义
  • 二、二叉树的遍历
    • 2.1 前序遍历:根左右
    • 2.2 中序遍历:左根右
    • 2.3 后序遍历:左右根
    • 2.4 层序遍历
  • 三、二叉树中结点个数
  • 四、二叉树中叶子结点个数
  • 五、二叉树中第k层结点数
  • 六、求树的深度-高度
  • 七、二叉树按值查找
  • 八、二叉树的销毁
  • 九、判断二叉树是否为完全二叉树
  • 源码
  • 总结


一、链式二叉树结点定义

typedef char BTDataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;struct BinaryTreeNode* right;BTDataType data;
}BTNode;

二、二叉树的遍历

前序 PreOrder:

中序 InOrder(MidOrder):

后续 PostOrder:

首先需要手动构建一颗二叉树:

BTNode* CreatBinaryTree()
{/*AB				CD				E		F*/BTNode* nodeA = CreateNode('A');BTNode* nodeB = CreateNode('B');BTNode* nodeC = CreateNode('C');BTNode* nodeD = CreateNode('D');BTNode* nodeE = CreateNode('E');BTNode* nodeF = CreateNode('F');nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;
}

2.1 前序遍历:根左右

// 二叉树前序遍历
void PreOrder(BTNode* root)
{if (root == NULL){//printf("NULL ");return;}printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}

2.2 中序遍历:左根右

void InOrder(BTNode* root)
{if (root == NULL){//printf("NULL ");return;}InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}

2.3 后序遍历:左右根

void PostOrder(BTNode* root)
{if (root == NULL){//printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%c ", root->data);
}

2.4 层序遍历

借助于队列实现。推荐使用C++的Queue。

#include "Queue.h"
void LevelOrder(BTNode* root)
{assert(root);Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);if(root->left)QueuePush(&q, root->left);if(root->right)QueuePush(&q, root->right);}QueueDestroy(&q);
}

三、二叉树中结点个数

使用遍历计数的方法,可以有以下两个代码:

int BinaryTreeSize(BTNode* root)
{if (root == NULL){return;}// 遍历计数思想:多次调用存在问题static int count = 0;++count;BinaryTreeSize(root->left);BinaryTreeSize(root->right);return count;
}void BinaryTreeSize(BTNode* root, int* pn)
{if (root == NULL){return;}++(*pn);BinaryTreeSize(root->left, pn);BinaryTreeSize(root->right, pn);
}

上面代码存在的问题是多次调用会出错。

使用递归方法:

int BinaryTreeSize(BTNode* root)
{/*if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);*/return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

四、二叉树中叶子结点个数

按照递归写法,首先上来需要判断结点为空的情况:

if (root == NULL)
{return 0;
}

转换为递归求解方法:分别求左右子树的叶子结点的和

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

然后找到叶子结点并计数:

// 二叉树叶子节点个数
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);
}

五、二叉树中第k层结点数

按照递归写法,首先上来需要判断结点为空的情况:

if (root == NULL)
{return 0;
}

转换为递归求解方法:求第root的第k层的结点数,为root左子树的k-1层结点数加上root右子树的k-1层结点数。例如:求A的第四层,可以转换为求A的左子树的第三层加上A的右子树的第三层。

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

给出递归结束条件,如果k等于1,则返回1

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k >= 1);if (root == NULL){return 0;}// 找到第k层结点if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

六、求树的深度-高度

首先给出root为空的情况,然后转换为用递归求解,因为根节点深度为1,所以求其左右子树高度的最大值,再加一就是树高:

// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDepth = BinaryTreeDepth(root->left);int rightDepth = BinaryTreeDepth(root->right);return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

七、二叉树按值查找

首先给出root为空的处理:

if (root == NULL)
{return NULL;
}

如果该结点就是查找的值,返回该节点:

if (root->data == x)
{return root;
}

如果该结点不是查找的值,则从左子树查找,如果左子树结点是,则返回左子树。右子树类似。

if (BinaryTreeFind(root->left, x))
{return root->left;
}if (BinaryTreeFind(root->right, x))
{return root->right;
}

都找不到返回NULL:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}if (BinaryTreeFind(root->left, x)){return root->left;}if (BinaryTreeFind(root->right, x)){return root->right;}return NULL;
}

好像没什么问题,但是当我们测试时发现有错误,自己动手调试就知道哪里有错误了。

修改左右子树查找的代码:

BTNode* leftRet = BinaryTreeFind(root->left, x);
if (leftRet)
{return leftRet;
}BTNode* rightRet = BinaryTreeFind(root->right, x);
if (rightRet)
{return rightRet;
}

最终代码:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* leftRet = BinaryTreeFind(root->left, x);if (leftRet){return leftRet;}BTNode* rightRet = BinaryTreeFind(root->right, x);if (rightRet){return rightRet;}return NULL;
}

八、二叉树的销毁

后序遍历销毁:左右根

void BinaryTreeDestroy(BTNode* root)
{if (root == NULL){return;}BinaryTreeDestroy(root->left);BinaryTreeDestroy(root->right);free(root);
}

九、判断二叉树是否为完全二叉树

判断二叉树是否是完全二叉树,我们可以考虑层序遍历,层序遍历过程中,没有间断便是完全二叉树。

间断表示什么意思?如果该二叉树不是完全二叉树,在遍历的过程中,我们还将左右为空的结点也加入到队列中,则会出现,队列中第一个空节点的后面还会有非空结点。如果该二叉树是一棵完全二叉树,则队列中第一个空节点后边全是空节点。

因此在层序遍历过程中,遇到第一个空节点便结束,然后将队列中的剩余节点元素依次弹出,遇到非空节点就不是完全二叉树。

bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);// 遇到第一个空结点跳出if(front == NULL)break;QueuePush(&q, root->left);QueuePush(&q, root->right);}// 检查队列中还有没有非空节点,有非空节点就不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

源码

Gitee-BinaryTree

总结

1.第一步需要上来就对空树情况进行处理。
2.递归的方法进行问题转换:求树的问题,转换为求左树和右树的问题,进行递归处理。
3.第二步空树情况处理完之后,需要给出递归结束条件。或满足当前节点判断的条件。
4.第三步需要给出递归表达式。



http://www.ppmy.cn/news/118616.html

相关文章

记一篇工作中遇到的问题及解决问题的经验感受.

在平时工作中或多或少都会遇到一些难缠的问题,在遇到问题时我们总是习惯性的先看日志,然后定位问题,排查问题,debug,log一套走,可是有些问题往往超出自己的认知范围,知道有问题但是不知道从哪里入手,在这里…

浅谈智能化配电室在居民小区的建设应用

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要:近年来居民小区配电室的数量增长快且设备情况较复杂,以致巡视效果不理想、缺陷和事故处理不及时,亟需建立一套智能化的配电室监控系统。按照实用性、统一性、分层和模块化设计…

FFmpeg入门基础

FFmpeg 是什么 FFmpeg 既是一款音视频编解码工具,同时也是一组音视频编解码开发套件,作为编解码开发套件,他为开发者提供了丰富的音视频处理的调用接口。 FFmpeg 提供了多种媒体格式的封装和解封装,包括多种音视频编码、多种协议…

c语言程序软件下载,C语言下载_C语言官方下载【C语言编程软件】-太平洋下载中心...

微软官方 Visual C 2013 (x86、x64)位运行库 Visual C Redistributable Packages 安装运行时组件,C语言下载版的组件是在未安装 Visual Studio 2013 的计算机上运行使用 Visual Studio 2013 开发的应用程序所必需的。这些软件包安装以下库的运行时组件:C…

最新版手机端C/C++语言编程的软件

今天介绍一个软件—C编译器(c4droid),可以直接编辑运行C/C程序,代码高亮、语法检查,使用起来非常不错,下面我简单介绍一下这个软件的安装和使用: 安装C编译器,这个直接在手机应用中搜索就行,如…

几个常用的C语言编程工具,极力推荐!

c语言编程软件适于编写系统软件,是学习编程的同学们的必备软件。c语言一种非常强大的计算机语言,应用非常广泛,不仅仅是在软件开发上,而且各类科研都会用到c语言。今天小编给大家汇总下C语言的编程工具 中国有句古话叫做“工欲善其…

C语言编程工具软件推荐

c语言编程软件适于编写系统软件,是学习编程的同学们的必备软件。c语言一种非常强大的计算机语言,应用非常广泛,不仅仅是在软件开发上,而且各类科研都会用到c语言。今天小编给大家汇总下C语言的编程工具 中国有句古话叫做“工欲善其…

手机上做c语言作业的软件下载,c语言编程软件手机版下载-C语言编程 安卓版v1.0.2-PC6安卓网...

C语言编程这是为众多考证用户专门制作的在线学习软件,C语言编程app将考证要用到的相关知识归纳好经过题库的形式来让大家熟练和上手,C语言编程app可以协助大家经过二级计算机考试。 软件介绍 C语言编程是一款掌上C语言学习软件,平台为用户提供…