当前位置: 首页 > news >正文

非线性表之堆的实际应用和二叉树的遍历

目录

前言:前一篇我已经介绍过了二叉树和堆的介绍和相关代码的实现

一、堆的实现

1.1堆向上调整算法

1.2堆向下调整算法

二、堆的应用

        2.1堆的排序

        2.2TOP-K问题

三、二叉树的遍历

3.1 二叉树的创建 

 3.2遍历介绍

3.3前序遍历 

3.4中序遍历

3.5后序遍历

四、二叉树的其他求法

4.1求二叉树的结点个数

4.2求二叉树的深度/高度

4.3求二叉树的第k层节点个数

五、结尾


前言:前一篇我已经介绍过了二叉树和堆的介绍和相关代码的实现

非线性链表之树结构和堆的代码实现-CSDN博客

一、堆的实现

1.1堆向上调整算法

使用堆的向上调整算法的前提是:在插入新元素之前,前面的元素就已经满足了堆的性质!!

堆的向上调整(heapify up)算法的思想是:

        1.将新元素插入到叶子节点。

        2.与父节点进行比较。

        3.如果新元素的值大于父节点的值,则需要进行交换。 将新元素看作父节点,重复上述过程。 使

void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void HPAdjustPush(int* a, int child)
{assert(a);int father = (child - 1) / 2;while (child > 0){if (a[father] < a[child]){swap(&a[father], &a[child]);child = father;father = (child - 1) / 2;}else{return;}}
}

1.2堆向下调整算法

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以

把它调整 成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void HPAdjustdown(int* a, int father,int sz)
{assert(a);int child = father * 2 + 1;while (child < sz){if (child + 1 < sz && a[child] < a[child + 1]){child++;}if (a[father] < a[child]){swap(&a[father], &a[child]);father = child;child = father * 2 + 1;}else{return;}}
}

二、堆的应用

        2.1堆的排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

1. 建堆 升序:建大堆 降序:建小堆

2. 利用堆删除思想来进行排序 建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以

完成堆排序。

 代码实现

#define _CRT_SECURE_NO_WARNINGS 1#include<assert.h>
#include<stdio.h>void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void HPAdjustPush(int* a, int child)
{assert(a);int father = (child - 1) / 2;while (child > 0){if (a[father] < a[child]){swap(&a[father], &a[child]);child = father;father = (child - 1) / 2;}else{return;}}
}void HPAdjustdown(int* a, int father,int sz)
{assert(a);int child = father * 2 + 1;while (child < sz){if (child + 1 < sz && a[child] < a[child + 1]){child++;}if (a[father] < a[child]){swap(&a[father], &a[child]);father = child;child = father * 2 + 1;}else{return;}}
}void HeapSort(int* a, int n)
{// 建堆 -- 向上调整建堆 -- O(N*logN)/*for (int i = 1; i < n; ++i){AdjustUp(a, i);}*/// 建堆 -- 向下调整建堆 -- O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, n, i);}
}

        2.2TOP-K问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能 数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

1. 用数据集合中前K个元素来建堆

  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆

2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

代码实现


typedef int HPDataType;void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}//从从后往前的第一个非叶子节点开始向下调整
void AdjustDown(int* arr, int N, int parent)
{int child = parent * 2 + 1;//这里假设左孩子为小的/大的一个while (child < N){//假设这里建小堆//假设有右孩子并且如果右孩子比左孩子小的if (child + 1 < N && arr[child + 1] < arr[child]){child++;}//如果孩子比双亲小,则将双亲和孩子交换if (arr[child] > arr[parent]){Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else //当孩子比双亲大时,则不需要调整了{break;}}
}void TopK(int* arr, int n, int k)
{//建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, n, i);}//定义一个变量end记录堆最后一个元素int end = n - 1;//取前k个最值for (int i = end; i < k; i--){//将堆顶与比它大的数交换,必依次比较到n-kif (*(arr+end) < *arr){Swap(&arr[0], &arr[end]);AdjustDown(arr, end, 0);}}for (int i = 0; i < k; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{int n = 10000;srand((unsigned int)time(0));int* arr = (int*)malloc(sizeof(int) * n);if (arr == NULL){perror("malloc fail");return;}for (int i = 0; i < n; i++){arr[i] = rand() % 1000000 + 5;}//最大/*arr[100] = 1000001;arr[500] = 1000002;arr[1000] = 1000003;arr[5555] = 1000004;arr[9999] = 1000005;*///最小arr[100] = 1;arr[500] = 2;arr[1000] = 3;arr[5555] = 4;arr[9999] = 5;TopK(arr, n, 5);return 0;
}

三、二叉树的遍历

要想遍历二叉树,首先我手动创建一个二叉树

3.1 二叉树的创建 

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}BTNode* CreatTree()
{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;return node1;
}

 3.2遍历介绍

学习二叉树结构,最简单的方式就是遍历。

所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。

遍历 是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

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

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

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

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

上述二叉图遍历结果

前序遍历结果:1 2 3 4 5 6

中序遍历结果:3 2 1 5 4 6

后序遍历结果:3 2 5 6 4 1  

3.3前序遍历 

void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}//前序遍历 根 左子树 右子树printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}

3.4中序遍历

void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}//中序遍历 左子树 根 右子树InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

3.5后序遍历

void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}//后序遍历 左子树 右子树 根PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

四、二叉树的其他求法

以下解法所用的是递归法

4.1求二叉树的结点个数

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

4.2求二叉树的深度/高度

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

4.3求二叉树的第k层节点个数

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);
}

五、结尾

如果有什么建议和疑问,或是有什么错误,希望大家可以在评论区提一下。
希望大家以后也能和我一起进步!!
如果这篇文章对你有用的话,希望能给我一个小小的赞!

相关文章:

非线性表之堆的实际应用和二叉树的遍历

目录 前言&#xff1a;前一篇我已经介绍过了二叉树和堆的介绍和相关代码的实现 一、堆的实现 1.1堆向上调整算法 1.2堆向下调整算法 二、堆的应用 2.1堆的排序 2.2TOP-K问题 三、二叉树的遍历 3.1 二叉树的创建 3.2遍历介绍 3.3前序遍历 3.4中序遍历 3.5后序遍历 …...

os.path库学习之splitext函数

os.path库学习之splitext函数 一、简介 os.path.splitext 是 Python 标准库 os.path 模块中的一个函数&#xff0c;用于将文件名分割成两部分&#xff1a;文件名和扩展名。这个函数非常有用&#xff0c;特别是在处理文件路径和文件扩展名时。 二、语法和参数 语法: os.path…...

Python知识点:如何使用Sqlmap进行SQL注入测试

使用 Sqlmap 进行 SQL 注入测试是一个非常有效的方法&#xff0c;它可以帮助你自动化地检测和利用 SQL 注入漏洞。以下是使用 Sqlmap 进行 SQL 注入测试的详细步骤&#xff1a; 1. 安装 Sqlmap 首先&#xff0c;你需要安装 Sqlmap。Sqlmap 是一个 Python 工具&#xff0c;因此…...

Android Gradle开发与应用 (一) : Gradle基础

Gradle基础 Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具。它使用一种基于 Groovy 的特定领域语言&#xff08;DSL&#xff09;来声明项目设置&#xff0c;而不是传统的 XML。Gradle 提供了灵活的构建脚本和强大的依赖管理功能&#xff0c;使其成为…...

Linux驱动开发—设备树分析:GPIO,中断,时钟信息,CPU信息

书接上回&#xff1a;Linux驱动开发—设备树基本概念&#xff0c;语法详解-CSDN博客 文章目录 使用设备树描述中断使用设备树描述CPU节点CPU 节点缓存节点总结 使用设备树描述时钟总结 使用设备树描述GPIO示例设备树节点逐行解析GPIO 单元 使用设备树描述中断 在NXP 官方中截…...

Java全栈解密:从JVM内存管理到Spring框架,揭秘垃圾回收、类加载机制与Web开发精髓的全方位旅程

JVM内存划分 在JVM中&#xff0c;每个线程有自己的虚拟机栈&#xff0c;而整个JVM实例共享一些内存区域。JVM的内存划分主要包括四个部分&#xff1a;程序计数器、虚拟机栈、堆区和方法区&#xff08;元数据区&#xff09;。 程序计数器&#xff1a;程序计数器用于存储当前线程…...

【探索Linux】P.46(高级IO —— 五种IO模型简介 | IO重要概念)

阅读导航 引言一、五种IO模型1. 阻塞IO&#xff08;1&#xff09;定义&#xff08;2&#xff09;特点 2. 非阻塞IO&#xff08;1&#xff09;定义&#xff08;2&#xff09;特点 3. IO多路复用&#xff08;1&#xff09;定义&#xff08;2&#xff09;特点 4. 信号驱动IO&#…...

【MongoDB 】MongoDB 介绍及应用,设计到4个案例

MongoDB 介绍概述 基础概念 MongoDB 是非关系型数据库&#xff0c;也就是nosql&#xff0c;存储json数据格式会非常灵活&#xff0c;要比数据库mysql/MariaDB更好&#xff0c;同时也能为mysql/MariaDB分摊一部分的流量压力。 对于经常读写的数据他会存入内存&#xff0c;如此…...

AI浪潮下的程序员生存指南:如何在智能时代锻造不可替代的核心竞争力

人工智能时代&#xff0c;程序员如何保持核心竞争力&#xff1f; 随着AIGC&#xff08;如chatgpt、midjourney、claude等&#xff09;大语言模型接二连三的涌现&#xff0c;AI辅助编程工具日益普及&#xff0c;程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工…...

Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]

文章目录 Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术…...

vue 日期控件 100天内的时间禁用不允许选择

vue 日期控件 100天内的时间禁用不允许选择&#xff0c;可以从101天选起 比如&#xff0c;2024年8月9号开始&#xff0c;100天内禁止选择&#xff0c;第101天之后的日期可以选&#xff0c;效果如图所示 // 日期控件代码 加上 :picker-options"pickerOptions" <…...

服务器HTTP响应头安全性优化与漏洞修复方案

在对服务器进行漏洞扫描后,通常会发现一些常见的安全漏洞,特别是涉及HTTP响应头的问题。以下是本次扫描过程中发现的漏洞问题以及对应的修复方案 1.X-Content-Type-Options 响应头缺失 描述: 缺失此响应头可能导致浏览器错误地解析资源类型,存在MIME类型混淆攻击的风险。 …...

4.定时器(TIMER)

理论 预分频寄存器(TIMx_PSC)&#xff1a;由于时钟源为&#xff1a;72MHz&#xff0c;T 1/f 1/72MHz&#xff0c;由于不好计算周期时间&#xff0c;则需要分频&#xff0c;若分72则T 1/1MHz 1us(1MHz 一百万秒) 计数方式&#xff1a;向上(递增到某个数触发中断)、向下(递…...

java springboot mqtt控制海康摄像头

GHHKControlService 接口 package org.gh.ghhk.service;public interface GHHKControlService {boolean monitorControl(String payload);}GHHKControlServiceImpl 实现类 ​ package org.gh.ghhk.service.impl;import com.alibaba.fastjson.JSONArray; import com.alibaba.…...

AI大模型02:Prompt Engineering 提示工程

一、什么是提示工程&#xff08;Prompt Engineering&#xff09; 1.提示工程&#xff0c;也叫“指令工程” &#xff08;1&#xff09;Prompt 就是我们给大模型发送的指令&#xff0c;或者说是在聊天对话框中发送的内容。 Prompt是AGI时代的编程语言。 Prompt是去控制大模型的…...

EasyExcel动态表头导出

1、封装方法 package com.skybird.iot.base.utils;import cn.hutool.core.util.StrUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.w…...

可视化基础的设计四大原则

一个好的数据可视化设计可以帮助观众迅速理解数据背后的意义。然而&#xff0c;如何确保我们的可视化设计既美观又简单易懂呢&#xff1f;本文将介绍四大设计原则——亲密原则、对比原则、对齐原则和重复原则。 1、 亲密原则&#xff08;Proximity&#xff09; 定义与应用&am…...

MySQL基础练习题27-上升的温度

目录 题目 准备数据 分析数据 总结 题目 找出与之前&#xff08;昨天的&#xff09;日期相比温度更高的所有日期的 id 。 准备数据 ## 创建库 create database db; use db;## 创建表 Create table If Not Exists Weather (id int, recordDate date, temperature int);#…...

只出现一次的数字 II

给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [2,2,3,2]…...

第十一章 数据仓库和商务智能 10分

11.1.0语境关系图 11.1 Q 建立数据仓库&#xff0c;有哪些步骤&#xff1f;如何建设&#xff1f;【6 个步骤非常重要&#xff01;必须知道】 1. 理解需求&#xff08;P&#xff09;&#xff08;目的明确&#xff0c;ETL&#xff09; (1) 考虑业务目标和业务战略。 (2) 确定业…...

一篇文章带你解析完整数据结构-----满满干活值得收藏

数据结构是计算机科学中的一个重要分支&#xff0c;它涉及到计算机存储、组织数据的方式。以下是数据结构的主要知识点&#xff1a; 基本概念 数据&#xff08;Data&#xff09;。数据元素&#xff08;Data Element)&#xff1a;数据项&#xff08;Data Item&#xff09;&…...

11.3 用Python处理常见文件

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…...

Linux知识复习第2期

RHCE 远程登录服务-CSDN博客 Linux 用户和组管理_linux用户和组的管理-CSDN博客 Linux 文件权限详解-CSDN博客 目录 1、sshd 免密登录 (1)纯净实验环境 (2)生成密钥 (3)上锁 2、用户管理 (1)添加新用户 (2)删除用户 (3)修改用户信息 (4)为用户账号设…...

驗證HTTP代理的有效性的方法和步驟-okeyproxy

如何驗證HTTP代理的有效性&#xff0c;確保它的性能和安全性&#xff0c;是非常必要的。本文將詳細介紹驗證HTTP代理有效性的方法和步驟。 HTTP代理作為一種仲介伺服器&#xff0c;它可以幫助用戶在訪問目標網站時隱藏真實IP地址&#xff0c;從而提高匿名性和安全性。通過HTTP…...

Java和kotlin 反射机制

Java 反射机制详解 Java 反射机制是一种强大的工具&#xff0c;使得程序可以在运行时动态地获取类的信息&#xff0c;并且可以在运行时操作类的成员变量、方法和构造函数等。以下是 Java 反射的详细讲解&#xff0c;包括其原理、使用场景、优缺点以及如何使用反射。 1. 反射的…...

Linux Shell编程--数组

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除&#xff01; 一、简介 Shell 脚本中的数组允许你存储多个值&#xff0c;并可以通过索引访问它们。Shell 中的数组是一维的。 二、声明数组 在Shell…...

sheng的学习笔记-AI-k近邻学习(kNN)

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 什么是k近邻学习 k近邻&#xff08;k-Nearest Neighbor&#xff0c;简称kNN&#xff09;学习是一种常用的监督学习方法&#xff0c;是一种基本的分类与回归方法。 分类问题&#xff1a;对新的样本&#xff0c;根据其 k 个…...

ShardingSphere之ShardingProxy集群部署

文章目录 介绍使用Zookeeper进行集群部署统一ShardingJDBC和ShardingProxy配置通过Zookeeper注册中心同步配置直接使用ShardingProxy提供的JDBC驱动读取配置文件 介绍 开发者手册 在conf/server.yaml配置文件中有下面这一段配置&#xff0c;就是关于集群部署的 mode: # typ…...

同态加密和SEAL库的介绍(六)BGV 方案

前面介绍 BFV 和 CKKS 加密方案&#xff0c;这两者更为常用。并且也解释了 Batch Encoder 和 级别的概念&#xff0c;这对接下来演示 BGV 会很有帮助。 一、BGV简介 BGV (Brakerski-Gentry-Vaikuntanathan) 方案 是一种基于环学习同态加密&#xff08;RLWE&#xff09;问题的加…...

uniapp微信小程序 canvas绘制圆形半透明阴影 createCircularGradient函数不支持透明度部分解决方案

背景 我需要在微信小程序中&#xff0c;用canvas绘制一个圆形钟表&#xff0c;在ui设计图中&#xff0c;有一部分阴影&#xff0c;这里我节选一下&#xff1a; 即深色发黑的部分 canvas通用阴影绘制 由于canvas中并不支持css那样简单的方式为圆形添加阴影或高光&#xff0c…...