【初阶数据结构】8.二叉树(3)

文章目录

  • 4.实现链式结构二叉树
    • 4.1 前中后序遍历
      • 4.1.1 遍历规则
      • 4.1.2 代码实现
    • 4.2 结点个数以及高度等
    • 4.3 层序遍历
    • 4.4 判断是否为完全二叉树
    • 4.5层序遍历和判断是否为完全二叉树完整代码


4.实现链式结构二叉树

用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 ,其结构如下:

typedef int BTDataType;
// 二叉链
typedef struct BinaryTreeNode
{struct BinTreeNode* left; // 指向当前结点左孩子 struct BinTreeNode* right; // 指向当前结点右孩子 BTDataType val; // 当前结点值域 
}BTNode;

二叉树的创建方式比较复杂,为了更好的步入到二叉树内容中,我们先手动创建一棵链式二叉树:

BTNode* BuyBTNode(int val)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->val = val;newnode->left = NULL;newnode->right = NULL;return newnode;
}
BTNode* CreateTree()
{BTNode* n1 = BuyBTNode(1);BTNode* n2 = BuyBTNode(2);BTNode* n3 = BuyBTNode(3);BTNode* n4 = BuyBTNode(4);BTNode* n5 = BuyBTNode(5);BTNode* n6 = BuyBTNode(6);BTNode* n7 = BuyBTNode(7);n1->left = n2;n1->right = n4;n2->left = n3;n4->left = n5;n4->right = n6;n5->left = n7;return n1;
}

回顾二叉树的概念,二叉树分为空树和非空二叉树,非空二叉树由根结点、根结点的左子树、根结点的右子树组成的

img

根结点的左子树和右子树分别又是由子树结点、子树结点的左子树、子树结点的右子树组成的,因此二叉树定义是递归式的,后序链式二叉树的操作中基本都是按照该概念实现的。


4.1 前中后序遍历

二叉树的操作离不开树的遍历,我们先来看看二叉树的遍历有哪些方式

img


4.1.1 遍历规则

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右子树之前

    访问顺序为:根结点、左子树、右子树

  2. 中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)

    访问顺序为:左子树、根结点、右子树

  3. 后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后

    访问顺序为:左子树、右子树、根结点


4.1.2 代码实现

void PreOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->val);PreOrder(root->left);PreOrder(root->right);
}
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}
void PostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);InOrder(root->right);printf("%d ", root->val);
}

以前序遍历为例:

img


4.2 结点个数以及高度等

Tree.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//定义二叉树的链式结构
//二叉树结点的结构
//Binary 二进制的意思
typedef int BTDataType;typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//前序遍历
void PreOrder(BTNode* root);//中序遍历--左根右
void InOrder(BTNode* root);//后序遍历 ---左右根
void PostOrder(BTNode* root);// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root);// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root);// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);

Tree.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Tree.h"//递归
//前序遍历
void PreOrder(BTNode* root)
{if (root == NULL)//走到为空就不遍历了{return;}printf("%d ", root->data);//打印根节点PreOrder(root->left);//左PreOrder(root->right);//右
}//中序遍历--左根右
void InOrder(BTNode* root)
{if (root == NULL){return;}InOrder(root->left);//左printf("%d ", root->data);//中InOrder(root->right);//右
}//后序遍历 ---左右根
void PostOrder(BTNode* root)
{if (root == NULL){//printf("NULL ");return;}PostOrder(root->left);//左PostOrder(root->right);//右printf("%d ", root->data);//中
}/*
// ⼆叉树结点个数
//这个会出现错误,因为size是全局变量,如果调用两次,会导致size的值变成两倍
int size = 0;
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}++size;BinaryTreeSize(root->left);BinaryTreeSize(root->right);return size;
}// ⼆叉树结点个数
//错误的写法
//这个会出现错误,因为size是全局变量,如果调用两次,会导致size的值变成两倍
void BinaryTreeSize(BTNode* root,int* psize)
{if (root == NULL){return 0;}++(*psize);BinaryTreeSize(root->left,psize);BinaryTreeSize(root->right,psize);
}
*/// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(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层结点个数
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 BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* leftFind = BinaryTreeFind(root->left, x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right, x);if (rightFind){return rightFind;}return NULL;
}// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}BinaryTreeDestory(& ((*root) ->left)  );BinaryTreeDestory(& ((*root) ->right) );free(*root);*root = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Tree.h"//创建节点
BTNode* buyNode(BTDataType x) {BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL) {perror("malloc fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}void test01() {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->left = node2;node1->right = node3;node2->left = node4;//node2->right = node5;//node3->left = node6;/*PreOrder(node1);printf("\n");InOrder(node1);printf("\n");PostOrder(node1);*/printf("size:%d\n", BinaryTreeSize(node1));// ⼆叉树结点个数printf("leaf size: %d\n", BinaryTreeLeafSize(node1));// ⼆叉树叶⼦结点个数printf("第K层 size:%d\n", BinaryTreeLevelKSize(node1, 2));// ⼆叉树第k层结点个数printf("depth/height:%d\n", BinaryTreeDepth(node1));//二叉树深度BTNode* find = BinaryTreeFind(node1, 33);printf("%s\n", find == NULL ? "未找到!" : "找到了!");// ⼆叉树查找值为x的结点BinaryTreeDestory(&node1);// ⼆叉树销毁
}int main() {test01();return 0;
}

4.3 层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历

设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历.

实现层序遍历需要额外借助数据结构:队列

img

// 层序遍历
void LevelOrder(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);printf("%c ", top->data);QueuePop(&q);if (top->_left) {QueuePush(&q, top->_left);}if (top->_right) {QueuePush(&q, top->_right);}}QueueDesTroy(&q);
}

4.4 判断是否为完全二叉树

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root) 
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);if (top == NULL) {break;}QueuePush(&q, top->_left);QueuePush(&q, top->_right);}while (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);if (top != NULL) {QueueDesTroy(&q);return false;}}QueueDesTroy(&q);return true;
}

4.5层序遍历和判断是否为完全二叉树完整代码

tree.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>//定义二叉树的链式结构
//二叉树结点的结构
//Binary 二进制的意思
typedef int BTDataType;typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);//定义队列结构
//typedef int QDataType;
//typedef struct BinaryTreeNode* QDataType;
typedef struct BTNode* QDataType;typedef struct QueueNode {QDataType data;struct QueueNode* next;
}QueueNode;typedef struct Queue {QueueNode* phead;//队头:删QueueNode* ptail;//队尾:插int size;//保存队列有效数据个数
}Queue;//初始化队列
void QueueInit(Queue* pq);// 入队列,队尾
void QueuePush(Queue* pq, QDataType x);//队列判空
bool QueueEmpty(Queue* pq);// 出队列,队头
void QueuePop(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//销毁队列
void QueueDestroy(Queue* pq);//层序遍历
//借助数据结构---队列
void LevelOrder(BTNode* root);

tree.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "LevelOrder.h"//初始化队列
void QueueInit(Queue* pq) {assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}// 入队列,队尾
void QueuePush(Queue* pq, QDataType x) {assert(pq);//申请新结点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL) {perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->phead == NULL) {//判断队列是否为空pq->phead = pq->ptail = newnode;}else {//队列不为空pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;//入一次,size++ 一次
}//队列判空
bool QueueEmpty(Queue* pq) {assert(pq);return (pq->phead == NULL) && (pq->ptail == NULL);
}// 出队列,队头
void QueuePop(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));//只有一个结点的情况,避免ptail变成野指针if (pq->ptail == pq->phead) {free(pq->phead);pq->phead = pq->ptail = NULL;}else {//删除队头元素QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}--pq->size;//出一次,size-- 一次
}//取队头数据
QDataType QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));//判断队列不为空return pq->phead->data;
}//销毁队列
void QueueDestroy(Queue* pq) {assert(pq);/*注意下面这行在这里要注释掉,不然会报错*///assert(!QueueEmpty(pq));//判断队列不为空,空队列不需要销毁QueueNode* pcur = pq->phead;while (pcur) {QueueNode* Next = pcur->next;free(pcur);pcur = Next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}// ⼆叉树销毁
void BinaryTreeDestory(BTNode * *root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}//层序遍历
//借助数据结构---队列
void LevelOrder(BTNode * root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){//取队头,打印BTNode* front = QueueFront(&q);printf("%d ", front->data);QueuePop(&q);//队头节点的左右孩子入队列if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}//队列为空QueueDestroy(&q);
}//判断二叉树是否为完全二叉树
//---队列
bool BinaryTreeComplete(BTNode * root)
{Queue q;QueueInit(&q);//初始化QueuePush(&q, root);//入队列while (!QueueEmpty(&q))//不为空就循环取队头{BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//让队头出队,确保下一次出来的是新的队头if (front == NULL){break;}QueuePush(&q, front->left);//把队头左孩子入队列QueuePush(&q, front->right);//把队头右孩子入队列}//队列不一定为空while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//出队列if (front != NULL)//如果不为空,说明不是完全二叉树{QueueDestroy(&q);//销毁return false;}}QueueDestroy(&q);//销毁return true;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "LevelOrder.h"//创建节点
BTNode* buyNode(BTDataType x) {BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL) {perror("malloc fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}void test01() {BTNode* node1 = buyNode(1);BTNode* node2 = buyNode(2);BTNode* node3 = buyNode(3);BTNode* node4 = buyNode(4);node1->left = node2;node1->right = node3;node2->left = node4;LevelOrder(node1);bool ret = BinaryTreeComplete(node1);printf("%s\n", ret == false ? "不是完全二叉树!" : "是完全二叉树!");BinaryTreeDestory(&node1);// ⼆叉树销毁
}int main() {test01();return 0;
}

打印:

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/49962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

space desk设备屏幕拓展软件

在正常开发的时候一般采用多个屏幕的方式来提高效率&#xff0c;这时就采用hdmi和vga拓展的形式&#xff0c;前提是屏幕但往往有电源以及续航不够的问题&#xff0c;不太方便出门在外的话 这时我就推荐大家使用软件无线连接的形式 进行软件下载下图为投影端可以在pc端下载 我…

如何保护您的 WordPress 不被黑?

明月可以说是见到过太多 WordPress 网站被黑的示例了&#xff0c;加上平时明月也会接一些 WordPress 疑难杂症的解决服务订单&#xff0c;所以这方面绝对是专业对口了。作为一个资深 WordPress 博客站长&#xff0c;谁都有被黑过的经历&#xff0c;都是一步步走过来的&#xff…

【数据结构】搜索二叉树

二叉搜索树 二叉树的博客 在之前的数据结构的文章中已经基本对二叉树有一定的了解&#xff0c;二叉搜索树也是一种数据结构&#xff0c;下面将对二叉搜索树进行讲解。 二叉搜索树的概念 二叉搜索树又称为二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有下面性…

外贸SOHO如何选择企业邮箱

外贸SOHO&#xff08;Small Office Home Office&#xff09;企业正以前所未有的速度崛起&#xff0c;然而&#xff0c;要在这片竞争激烈的蓝海中立足&#xff0c;高效的全球通信能力、坚实的安全防线、成本效益的考量以及专业的品牌形象塑造&#xff0c;缺一不可。本文旨在为外…

webStorm 实时模板笔记

文章目录 1、单斜杠效果 2、双斜杠效果 3、控制台打印效果 1、单斜杠 /** $END$ */效果 2、双斜杠 /*** $END$* author Ikun* since $DATE$ $TIME$ */DATE date() ✔ TIME time() ✔效果 3、控制台打印 console.log("███████$EXPR_COPY$>>>>&a…

前端调试合集(包含移动端/内嵌h5)

代码内使用方法 alert/console alert和console.log作为JS最基本的调试能力&#xff0c;提供了简易版的断点 (只能断一下) 和输出 (只能输出字符串) 能力&#xff0c;可以在代码运行到预期的位置输出预期的log&#xff0c;通过对不同流程下写入alert&#xff0c;输出变量的值来…

Java笔试分享

1、设计模式&#xff08;写>3种常用的设计模式&#xff09; 设计模式是在软件工程中解决常见问题的经验性解决方案。以下是一些常用的设计模式&#xff1a; 单例模式&#xff08;Singleton&#xff09;&#xff1a; 意图&#xff1a;确保一个类只有一个实例&#xff0c;并…

从0到1,AI我来了- (1)从AI手写数字识别开始

前两篇我们我们把控制台、Python环境Anaconda 搞定了&#xff0c;接下来&#xff0c;我们快速进入主题&#xff0c;把AI 界的“Hello World” 实现一下&#xff0c;有个感觉&#xff0c;再逐步了解一些AI的概念。 1、Pytorch 安装 1) 什么是Pytorch? 一个深度学习框架&#…

通信原理-实验六:实验测验

实验六 实验测验 一&#xff1a;测验内容和要求 测试需要完成以下几个步骤&#xff1a; 配置好以下网络图&#xff1b;占总分10%&#xff08;缺少一个扣一分&#xff09;根据下面图配置好对应的IP和网关以及路由等相关配置&#xff0c;保证设备之间连通正常&#xff1b;占总…

加速决策过程:企业级爬虫平台的实时数据分析

摘要 在当今数据驱动的商业环境中&#xff0c;企业如何才能在海量信息中迅速做出精准决策&#xff1f;本文将探讨企业级爬虫平台如何通过实时数据分析加速决策过程&#xff0c;实现数据到决策的无缝衔接。我们聚焦于技术如何赋能企业&#xff0c;提升数据处理效率&#xff0c;…

NSS [NSSRound#13 Basic]flask?jwt?

NSS [NSSRound#13 Basic]flask?jwt? 开题 注册一下 要admin才能拿flag 看看是如何进行身份验证的 是flask session flask-unsign --decode --cookie .eJwtzjESwyAMBMC_UKfghJCEP-MRICZp7bjK5O9xkX6L_aR9HXE-0_Y-rnik_TXTlsiXEhUXleKGGGuG1jbmogrCEmNirZ7BEB-VJbTfIi-26hQD…

跨棒距、公法线和齿厚对应关系分析

前面有一期讨论了下滚齿径向进刀量和齿厚的对应关系&#xff1a;《》&#xff0c;有小伙伴又问了&#xff0c;加工时是用跨棒距或者公法线去控制齿厚的&#xff0c;直接给齿厚是无法测量的&#xff0c;如果测一个值再去计算&#xff0c;有点麻烦&#xff0c;有没有他们之间的对…

多多OJ评测系统 在前端脚手架Vue-Cli中设置页面路由

目录 设置页面路由 我们把菜单上的路由改成读取路由文件 设置成export 导出路由 在刚刚的原始路由 index.ts中导入就行了 在这边引入我们的路由文件 我们之后点击菜单 我们的路由文件是这样的 但是没有跳转 写一下事件 接下来要同步路由到菜单项 自己定义监听函数 …

推荐3款不可错过的实用工具

TouchPro TouchPro是一款运行于Windows系统下的时间属性修改工具&#xff0c;其主要功能是允许用户批量修改文件和文件夹的创建时间、修改时间和访问时间。该软件安装后会集成到资源管理器中&#xff0c;不占用任何系统资源&#xff0c;并支持多级目录与隐藏文件的日期属性批量…

推荐几款支持AI剪辑并可使用个人视频素材的软件!

最强AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量 其实现在大部分的AI视频剪辑工具都可以实现一键成片&#xff0c;这里给你分享6款可以使用自己的素材实现AI剪辑的工具及其操作方法&#xff01; 一、剪映 剪映…

服务器重启了之后就卡在某个页面了,花屏,如何解决??

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

前端开发知识(二)-css

<head> <style> div{ } </style> </head> div是布局标签&#xff0c; 一般放在head标签内&#xff0c;最下部。 若直接在在.css文件中写css,文件中&#xff0c;直接写就行&#xff0c;如下所示。 div{ }

MySQL数据库安装使用

我们都知道数据库又分为关系型数据库和非关系型数据库&#xff1b; 关系型数据库指采用了关系模型来组织数据的数据库&#xff0c;指的就是二维表格模型。可以先初步理解为Excel表格。非关系型数据库又被称为NoSQL&#xff0c;对NoSQL 最普遍的定义是“非关联型的”&#xff0…

C语言 | Leetcode C语言题解之第279题完全平方数

题目&#xff1a; 题解&#xff1a; // 判断是否为完全平方数 bool isPerfectSquare(int x) {int y sqrt(x);return y * y x; }// 判断是否能表示为 4^k*(8m7) bool checkAnswer4(int x) {while (x % 4 0) {x / 4;}return x % 8 7; }int numSquares(int n) {if (isPerfect…

Linux环境安装KubeSphere容器云平台并实现远程访问Web UI 界面

文章目录 前言1. 部署KubeSphere2. 本地测试访问3. Linux 安装Cpolar4. 配置KubeSphere公网访问地址5. 公网远程访问KubeSphere6. 固定KubeSphere公网地址 前言 本文主要介绍如何在Linux CentOS搭建KubeSphere并结合Cpolar内网穿透工具&#xff0c;实现远程访问&#xff0c;根…