数据结构——二叉树链式结构的实现(下)

二叉树找值找为x的结点

找值不简单吗?轻轻松松拿捏,大部分同学都会写出这样的代码

但这种代码有问题,因为没有把查找结果返回给上一层,没有用返回值接收。

当找到3时返回给了上一层,但并没有用返回值接收,那么结果就会丢失,理论上如果左树找到了,就不会去右树去寻找,因此用返回值判断左树是否存在且返回结果是很重要的。 

那么就有同学突发奇想了,那么我把&&改成||不就行了,这样在左树找到就不用去右树找了。 

首先||只能返回值1和0,也就真(true)和假(false),只有当返回值是bool布尔值时才能用||,况且返回值是BTNode*,所以这种方法是错误的。

那么我们用接收返回值写一下。

这个代码有什么问题吗?

这个代码有两个问题,第一,理论上左树找到结果就不用去右树去查找,但这个代码不管左树有没有找到结果,都会去右树查找,第二,如果左树找到结果永远会被右树的空值覆盖。

正确写法

逻辑最顺的写法

BTNode* Treefind(BTNode* root, int x)
{if (root == NULL){return NULL;}if (root->val == x){return root;}BTNode* ret = NULL;ret = Treefind(root->_left, x);if (ret)return ret;ret = Treefind(root->_right, x);if (ret)return ret;return NULL;}

 找x==4时

二叉树的销毁

二叉树销毁采用后序比较方便 前序也可以 不过很麻烦,推荐用后序

void TreeDestroy(BTNode* root)
{if (root == NULL){return;}TreeDestroy(root->_left);TreeDestroy(root->_right);free(root);
}

这里root不用置空 因为置不置空都不影响root,因为root形参是局部变量,如果要置空,可以在外部置空。 

二叉树的层序遍历

二叉树的层序遍历最好的办法就是队列结构,因为队列是先进先出的

void LevelOrder(BTNode* root)
{Que q;QueInit(&q);if (root)QuePush(&q,root);while (Empty(&q)){BTNode* Front = QueFront(&q);printf("%d ", Front->val);if (Front->_left)QuePush(&q, Front->_left);if (Front->_right)QuePush(&q, Front->_right);QuePop(&q);}printf("\n");QueDestroy(&q);}

1带2 4     2带3 N  4带5 6 层序遍历使用队列遍历是最好办法! 

 

判断二叉树是否是完全二叉树

假设有k层高度,满二叉树的每一层结点都是满的 从左到右是连续

假设有k层高度,完全二叉树的k-1层都是满的,k层不完全满 且从左到右是连续。

那么使用层序遍历是最好的。

完全二叉树:如果非空节点是连续的,是完全二叉树。

不是完全二叉树:如果非空节点不是连续的,中间有空节点,就不是完全二叉树。

int Treecomplete(BTNode* root)
{Que q;QueInit(&q);if (root)QuePush(&q, root);while (!Empty(&q)){BTNode* Front = QueFront(&q);if (Front == NULL){break;}QuePush(&q, Front->_left);QuePush(&q, Front->_right);QuePop(&q);}printf("\n");//已经遇到空节点,如果队列中后面的节点还有非空,就不是完全二叉树while (!Empty(&q)){BTNode* Front = QueFront(&q);QuePop(&q);//这里pop的队列的节点 不会影响二叉树取Front的节点。if (Front != NULL){QueDestroy(&q);return false;}}QueDestroy(&q);return true;
}

 

求二叉树的高度

二叉树高度不就是左子树或者右子树的深度最长的那一个,加上根节点自己。

一般大家求高度的时候,都会这样去写代码,但这样写是有问题的,使用三目运算符使虽然让代码行数减少了,但造成了空间栈的浪费,因为在算左子树深度和右子树深度时,求出来的结果值只用在了判断它们俩谁大谁小的问题上面并没有保存返回值,当判断完左还是右大以后,后面运行的代码它还要再次去计算左子树或者右子树深度再+1,造成了重复计算(栈浪费),如果是数据量大会造成栈溢出。

解决办法就是创建变量接收左子树或者右子树的深度,再进行比较,这样就不会造成栈溢出的问题,也节省了空间和提高了效率。

int Treehight(BTNode* root)
{if (root == NULL){return 0;}int lefthight = Treehight(root->_left);int righthight = Treehight(root->_right);return lefthight > righthight ? lefthight + 1 : righthight + 1;
}

完整代码

Queue.h

#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef struct BinaryTree* Queuetype;
typedef struct QueueNode
{struct QueueNode* next;Queuetype data;
}QNode;typedef struct Queque
{QNode* tail;QNode* head;int size;
}Que;void QueInit(Que* p);
void QueDestroy(Que* p);
void QuePush(Que* p,Queuetype x);
void QuePop(Que* p);Queuetype QueFront(Que* p);
Queuetype QueBack(Que* p);
bool Empty(Que* p);

Queue.c

#include"Queue.h"
void QueInit(Que* p)
{assert(p);p->head = p->tail =NULL;p->size = 0;
}
void QueDestroy(Que* p)
{QNode* cur = p->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}p->head = p->tail = NULL;p->size = 0;
}
void QuePush(Que* p, Queuetype x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = x;newnode->next = NULL;if (p->tail == NULL){p->head = p->tail = newnode;}else{p->tail->next = newnode;p->tail = newnode;}p->size++;
}void QuePop(Que* p)
{assert(p);assert(!Empty(p));if (p->head->next == NULL){free(p->head);p->head = p->tail = NULL;}else{QNode* next = p->head->next;free(p->head);p->head = next;}p->size--;
}Queuetype QueFront(Que* p)
{assert(p);assert(!Empty(p));return p->head->data;
}
Queuetype QueBack(Que* p)
{assert(p);assert(!Empty(p));return p->tail->data;
}
bool Empty(Que* p)
{assert(p);return p->head == NULL;
}

test.c

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef struct BinaryTree
{struct BinaryTree* _left;struct BinaryTree* _right;int val;
}BTNode;#include"Queue.h"
BTNode* buynode(int x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->_left = NULL;newnode->_right = NULL;newnode->val = x;return newnode;
}void PreOrder(BTNode* root)
{if (root == NULL){printf(" NULL ");return;}printf("%d ", root->val);PreOrder(root->_left);PreOrder(root->_right);}
void InOrder(BTNode* root)
{if (root == NULL){printf(" NULL ");return;}InOrder(root->_left);printf("%d ", root->val);InOrder(root->_right);}
void  PostOrder(BTNode* root)
{if (root == NULL){printf(" NULL ");return;}PostOrder(root->_left);PostOrder(root->_right);printf("%d ", root->val);}
void LevelOrder(BTNode* root)
{Que q;QueInit(&q);if (root)QuePush(&q,root);while (!Empty(&q)){BTNode* Front = QueFront(&q);printf("%d ", Front->val);if (Front->_left)QuePush(&q, Front->_left);if (Front->_right)QuePush(&q, Front->_right);QuePop(&q);}printf("\n");QueDestroy(&q);}
int Treecomplete(BTNode* root)
{Que q;QueInit(&q);if (root)QuePush(&q, root);while (!Empty(&q)){BTNode* Front = QueFront(&q);if (Front == NULL){break;}QuePush(&q, Front->_left);QuePush(&q, Front->_right);QuePop(&q);}printf("\n");//已经遇到空节点,如果队列中后面的节点还有非空,就不是完全二叉树while (!Empty(&q)){BTNode* Front = QueFront(&q);QuePop(&q);if (Front != NULL){QueDestroy(&q);return false;}}QueDestroy(&q);return true;
}
int Treesize(BTNode*root)
{return root == NULL ? 0 : Treesize(root->_left) + Treesize(root->_right)+1;
}
int Treeleafsize(BTNode* root)
{if (root == NULL){return 0;}if (root->_left == NULL && root->_right == NULL){return 1;}return Treeleafsize(root->_left) + Treeleafsize(root->_right);
}
int TreeKlevel(BTNode* root,int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return TreeKlevel(root->_left, k - 1) + TreeKlevel(root->_right, k - 1);
}
int Treehight(BTNode* root)
{if (root == NULL){return 0;}return Treehight(root->_left) >Treehight(root->_right)?Treehight(root->_left) + 1:Treehight(root->_right)+ 1;
}
void TreeDestroy(BTNode* root)
{if (root == NULL){return;}TreeDestroy(root->_left);TreeDestroy(root->_right);free(root);
}
BTNode* Treefind(BTNode* root, int x)
{if (root == NULL){return NULL;}if (root->val == x){return root;}BTNode* ret = NULL;ret = Treefind(root->_left, x);if (ret)return ret;ret = Treefind(root->_right, x);if (ret)return ret;return NULL;}
int main()
{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 = node4;node2->_left = node3;node4->_left = node5;node4->_right = node6;PreOrder(node1);printf("\n");InOrder(node1);printf("\n");PostOrder(node1);printf("\n");printf("Treesize:%d\n", Treesize(node1));printf("Treeleafsize:%d\n", Treeleafsize(node1));printf(" TreeKlevel:%d\n", TreeKlevel(node1, 2));printf("Treehight:%d\n", Treehight(node1));LevelOrder(node1);printf("Treecomplete:%d\n", Treecomplete(node1));TreeDestroy(node1);node1 = NULL;
}

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

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

相关文章

Rust 生命周期浅谈

1. 简述 Rust 中的每一个引用都有其 生命周期&#xff08;lifetime&#xff09;&#xff0c;也就是引用保持有效的作用域。大部分时候生命周期是隐含并可以推断的&#xff0c;正如大部分时候类型也是可以推断的一样。类似于当因为有多种可能类型的时候必须注明类型&#xff0c;…

大数据面试题(九):Hive的高频面试考点(值得收藏)

文章目录 Hive的高频面试考点 一、Hive中两个大表实现join的操作,简单描述一下

书接上文,助力智能化诊断高质提效,基于轻量级CNN模型MobileNet开发构建人体手骨X光骨骼骨龄分析识别系统

骨龄是骨骼年龄的简称&#xff0c;需要借助于骨骼在X光摄像中的特定图像来确定。通常要拍摄左手手腕部位的X光片&#xff0c;医生通过X光片观察来确定骨龄。这在临床上是一件非常消耗精力和时间的一项放射临床工作。写一个骨龄可能要10多分钟去完成。如果一天要写几十个骨龄&am…

【汇编语言】中断及外部设备操作

【汇编语言】中断及外部设备操作 文章目录 【汇编语言】中断及外部设备操作前言一、中断及其处理中断的概念8086内中断中断处理程序案例&#xff1a;系统中的0号中断中断过程 二、编制中断处理程序中断处理程序及其结构编制中断处理程序——以除法错误中断为例do0子程序应该放在…

基础I/O--文件系统

文章目录 回顾C文件接口初步理解文件理解文件使用和并认识系统调用open概述标记位传参理解返回值 closewriteread总结 文件描述符fd0&1&2理解 回顾C文件接口 C代码&#xff1a; #include<stdio.h> int main() { FILE *fpfopen("log.txt",&…

《MySQL45讲》读书笔记

重建表 alter table t engine InnoDB&#xff08;也就是recreate&#xff09;&#xff0c;而optimize table t 等于recreateanalyze&#xff0c;让表大小变小 重建表的执行流程 建立一个临时文件&#xff0c;扫描表 t 主键的所有数据页&#xff1b;用数据页中表 t 的记录生…

mac通过termius连接Linux服务器

mac上安装 linux系统 如果有 linux服务器账号密码&#xff0c;那么上一步可忽略&#xff1b; 比如&#xff1a;直接连接阿里云或腾讯云账号 1. 安装termius 链接: https://pan.baidu.com/s/1iYsZPZThPizxqtkLPT89-Q?pwdbw6j 提取码: bw6j 官网 Termius - SSH platform for …

【C++】STL — vector的接口讲解 +详细模拟实现

前言: 本章我们将学习STL中另一个重要的类模板vector… vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。但是又不像数组&#xff0c;它的大小是可以动态改变的本质讲&#xff0c;vector使用动态分配数组来存储它的元素v…

配电室智能巡检机器人

近年来&#xff0c;生产过程高度自动化&#xff0c;各工矿企业关键场所需定期巡检维护。但目前巡检主要靠人工&#xff0c;既耗时费力效率又低&#xff0c;且受环境等因素影响&#xff0c;巡检难以全面规范&#xff0c;隐患或问题易被忽视。在此情况下&#xff0c;如何利用现有…

ElasticSearch02(DSL查询文档,DSL处理结果,RestClient查询,旅游案例,数据聚合)【全详解】

目录 一、DSL查询文档 1. 说明 2. 文本检索 3. 精确查询 4. 地理坐标查询 5. 复合查询 6. 课堂演示 7. 小结 二、DSL处理结果 1. 排序 2. 分页 3. 高亮 4. 课堂演示 5. 小结 三、RestClient查询 1.快速入门 2.match查询 3.精确查询 4.布尔查询 5. 算分函数…

锁相环原理解析

在计算机和嵌入式系统中&#xff0c;常常要用锁相环来倍频&#xff0c;那么&#xff0c;锁相环是如何倍频的&#xff0c;其原理又是什么呢&#xff1f; 目录 1. 锁相环基本概念与构成1.1 鉴相器1.2 低通滤波器1.3 压控振荡器 2. 锁相环如何实现倍频3. 锁相环也会失效&#xff…

【前端学习——正则】

https://www.bilibili.com/video/BV1da4y1p7iZ/?spm_id_from333.337.search-card.all.click&vd_source5cef5968d539682b683e7d01b00ad01b 学习网站 https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

Bookends for Mac:文献管理工具

Bookends for Mac&#xff0c;一款专为学术、研究和写作领域设计的文献管理工具&#xff0c;以其强大而高效的功能深受用户喜爱。这款软件支持多种文件格式&#xff0c;如PDF、DOC、RTF等&#xff0c;能够自动提取文献的关键信息&#xff0c;如作者、标题、出版社等&#xff0c…

在M1芯片安装鸿蒙闪退解决方法

在M1芯片安装鸿蒙闪退解决方法 前言下载鸿蒙系统安装完成后&#xff0c;在M1 Macos14上打开闪退解决办法接下来就是按照提示一步一步安装。 前言 重新安装macos系统后&#xff0c;再次下载鸿蒙开发软件&#xff0c;竟然发现打不开。 下载鸿蒙系统 下载地址&#xff1a;http…

MATLAB实现遗传算法优化第三类生产线平衡问题

第三类生产线平衡问题的数学模型 假设&#xff1a; 工作站数量&#xff08;m&#xff09;和生产线节拍&#xff08;CT&#xff09;是预设并固定的。每个任务&#xff08;或作业元素&#xff09;只能分配到一个工作站中。任务的执行顺序是预先确定的&#xff0c;且不可更改。每…

PHP医疗不良事件上报系统源码 AEMS开发工具vscode+ laravel8 医院安全(不良)事件报告系统源码 可提供演示

PHP医疗不良事件上报系统源码 AEMS开发工具vscode laravel8 医院安全&#xff08;不良&#xff09;事件报告系统源码 可提供演示 医院安全不良事件报告系统&#xff08;AEMS&#xff09;&#xff1b;分为外部报告系统和内部报告系统两类。内部报告系统主要以个人为报告单位&…

Docker私有镜像仓库搭建 带图形化界面的

搭建镜像仓库可以基于Docker官方提供的DockerRegistry来实现。 官网地址&#xff1a;https://hub.docker.com/_/registry 先配置私服的信任地址: # 打开要修改的文件 vi /etc/docker/daemon.json # 添加内容&#xff1a; "insecure-registries":["http://192.…

暴力匹配字符串的升级版算法 —— Kmp算法

文章目录 一、Kmp算法是什么&#xff1f;二、算法分析1.构建next数组2.匹配主串 三、完整代码 一、Kmp算法是什么&#xff1f; 简单来说&#xff0c;KMP&#xff08;Knuth-Morris-Pratt&#xff09;算法主要用于解决字符串匹配问题。也就是当你有一个主串&#xff08;text&…

OceanBase 轻量级数仓关键技术解读

码到三十五 &#xff1a; 个人主页 为了更好地聚合和治理跨域数据&#xff0c;帮助企业用较低的成本快速聚合分析&#xff0c;快速决策&#xff0c;不断的让企业积累的数据产生价值&#xff0c;从全域海量数据抓取&#xff0c;高性能流批处理&#xff0c;元数据血缘治理等等方面…