101.【C语言】数据结构之二叉树的堆实现 下

news2024/12/23 23:15:43

目录

1.堆删除函数HeapPop

一个常见的错误想法:挪动删除

正确方法

设计堆顶删除函数HeapPop

解析向下调整函数AdjustDown

向下调整最多次数

向下调整的前提

代码实现

2.测试堆删除函数

运行结果

3.引申问题

运行结果

4.练习

分析

代码

执行过程图

运行结果


承接100.【C语言】数据结构之二叉树的堆实现 上文章

1.堆删除函数HeapPop

尾删没有任何意义,删头才有意义(即删堆顶),删除之后要调整二叉树,仍然符合大根堆的性质

拿上图举例,现删除堆顶元素50

一个常见的错误想法:挪动删除

即{50,30,8,5,12,0,2,15,3}变成{30,8,5,12,0,2,15,3}

将{30,8,5,12,0,2,15,3}画成二叉树会发现既不是大根堆也不是小根堆

此错误方法不仅效率低下还将父子兄弟之间的关系全部弄乱了

因此禁止使用挪动删除!

正确方法

让堆顶元素和数组的最后一个元素进行交换(Swap函数),接着删除最后一个元素(ps->size--),再向下调整

设计堆顶删除函数HeapPop

堆顶能删除的前提:堆不能是空的(调用HeapEmpty函数检验)

空堆检查函数HeapEmpty

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

交换函数Swap

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a,php->size,0);
}

解析向下调整函数AdjustDown

核心思想

左孩子和右孩子哪一个大,parent就换哪个,重复前述步骤直到满足大根堆或小根堆的性质

以下面这个为例说明

835ce423296641c2add5b98f83402f3f.png

384ad47ca9314a0da1892db952184bc3.png 经过两次向下调整后,变成大根堆6ea34274685747ad87b4d8f45aceac2a.png

向下调整最多次数

最坏情况是调整到叶节点,即log_2 N

向下调整的前提

左右子树为堆,

代码实现

一开始默认为左孩子,如果右孩子值大于左孩子,则进行调整

void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

提问

上述代码写的有没有问题?

答:if (a[child + 1] > a[child])有潜在的问题,可能会越界访问

child+1可能会大于或等于n

细节分析

改成下面这样行吗?

if (a[child + 1] > a[child] && child+1 < n)

不行,要遵循&&的运算规则:先左后右,因此上方代码会先判断a[child + 1] > a[child]再判断child+1 < n,可能会先越界访问,之后判断child+1 < n就无效了

因此改为

if (child+1 < n && a[child + 1] > a[child])

2.测试堆删除函数

main.c中写入以下代码,之后下断点至return 0;

#include "Heap.h"
int main()
{
	HP hp;
	HeapInit(&hp);
	HeapPush(&hp, 1);
	HeapPush(&hp, 3);
	HeapPush(&hp, 0);
	HeapPush(&hp, 5);
	HeapPush(&hp, 8);
	HeapPush(&hp, 12);
	HeapPush(&hp, 2);
	HeapPush(&hp, 5);
	HeapPush(&hp, 30);
	HeapPush(&hp, 50);

	while (!HeapEmpty(&hp))
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}

	return 0;
 }

备注:只要堆没有删空while (!HeapEmpty(&hp))就继续执行,这里要强调的点是:堆顶永远是堆中最大的数,因此只有删了堆顶,堆顶下面最大的数才能上去

运行结果

625d4ea62d074a95b574443449bc8c8d.png

显然进行了堆排序

3.引申问题

若要打印上方排好序的堆中的前k个数(k<=n),代码怎么写?

答:稍加改动即可

	int k = 0;
	scanf("%d", &k);
	while (!HeapEmpty(&hp)&&k--)
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}

运行结果

f04e34b7e2254d3ebd1b8b4a901eb4ac.png

4.练习

给一个乱序数组,设计一个排序函数HeapSort,要求建立大根堆,写出代码

要求:不另外开辟空间

代码模板

??? HeapSort(??????)
{
    //??????
}

int main()
{
	int arr[] = { 1,4,2,5,7,2,6,8,9,2 };
	HeapSort(??????);
	return 0;
}

分析

在无序堆(既不是大根堆也不是小根堆)上建立大根堆,则需要对数组中的每一个元素进行向上调整

,则可写循环

代码

向上调整建堆

void HeapSort(int* arr, int n)
{
	for (int i = 1; i < n; i++)
	{
		AdjustUp(arr, i);
	}
}
int main()
{
	int arr[] = { 1,4,2,5,7,2,6,8,9,2 };
	int size = sizeof(arr)/sizeof(arr[0]);
	HeapSort(arr,size);
	return 0;
}

执行过程图

运行结果

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

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

相关文章

数据结构(Java版)第二期:包装类和泛型

目录 一、包装类 1.1. 基本类型和对应的包装类 1.2. 装箱和拆箱 1.3. 自动装箱和自动拆箱 二、泛型的概念 三、引出泛型 3.1. 语法规则 3.2. 泛型的优点 四、类型擦除 4.1. 擦除的机制 五、泛型的上界 5.1. 泛型的上界的定义 5.2. 语法规则 六、泛型方法 6.1…

【pyspark学习从入门到精通14】MLlib_1

目录 包的概览 加载和转换数据 在前文中&#xff0c;我们学习了如何为建模准备数据。在本文中&#xff0c;我们将实际使用这些知识&#xff0c;使用 PySpark 的 MLlib 包构建一个分类模型。 MLlib 代表机器学习库。尽管 MLlib 现在处于维护模式&#xff0c;即它不再积极开发…

【CSP CCF记录】201903-1第16次认证 小中大

题目 样例1输入 3 -1 2 4 样例1输出 4 2 -1 样例1解释 4 为最大值&#xff0c;2 为中位数&#xff0c;−1 为最小值。 样例2输入 4 -2 -1 3 4 样例2输出 4 1 -2 样例2解释 4 为最大值&#xff0c;(−13)21为中位数&#xff0c;−2为最小值。 思路 本题两个注意点&#xff0…

P8692 [蓝桥杯 2019 国 C] 数正方形:结论,组合数学

题目描述 在一个 NNNN 的点阵上&#xff0c;取其中 44 个点恰好组成一个正方形的 44 个顶点&#xff0c;一共有多少种不同的取法&#xff1f; 由于结果可能非常大&#xff0c;你只需要输出模 10971097 的余数。 如上图所示的正方形都是合法的。 输入格式 输入包含一个整数 …

Elasticsearch客户端在和集群连接时,如何选择特定的节点执行请求的?

大家好&#xff0c;我是锋哥。今天分享关于【Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f; 100…

【题解】—— LeetCode一周小结46

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结45 11.切棍子的最小成本 题目链接&#xff1a;1547. 切棍子的最…

AI社媒引流工具:解锁智能化营销的新未来

在数字化浪潮的推动下&#xff0c;社交媒体成为品牌营销的主战场。然而&#xff0c;面对海量的用户数据和日益复杂的运营需求&#xff0c;传统营销方法显得力不从心。AI社媒引流王应运而生&#xff0c;帮助企业在多平台中精准触达目标用户&#xff0c;提升营销效率和效果。 1.…

Python 使用 Selenuim进行自动化点击入门,谷歌驱动,以百度为例

一、首先要下载谷歌驱动 1.&#xff08;打开谷歌浏览器 - 设置 - 关于谷歌&#xff0c;查看谷歌浏览器版本&#xff0c;否则不对应无法调用&#xff0c;会提示&#xff1a;selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This versio…

C语言-指针作为函数返回值及二级指针

1、指针作为函数返回值 c语言允许函数的返回值是一个指针&#xff08;地址&#xff09;我们将这样的函数称为指针函数&#xff0c;下面的例子定义一了一个函数strlong&#xff08;&#xff09;&#xff0c;用来返回两个字符串中较长的一个&#xff1a; 1. #include <stdio…

实时数据开发 | 怎么通俗理解Flink容错机制,提到的checkpoint、barrier、Savepoint、sink都是什么

今天学Flink的关键技术–容错机制&#xff0c;用一些通俗的比喻来讲这个复杂的过程。参考自《离线和实时大数据开发实战》 需要先回顾昨天发的Flink关键概念 检查点&#xff08;checkpoint&#xff09; Flink容错机制的核心是分布式数据流和状态的快照&#xff0c;从而当分布…

再次讨论下孤注一掷

在孤注一掷中的黑客技术里面&#xff0c;简单介绍了电影孤注一掷中用的一些"黑科技"&#xff0c;这里继续讨论下&#xff0c;抛弃这些黑科技&#xff0c;即使在绝对公平的情况下&#xff0c;你也一样赢不了赌场 相对论有一个假设就是光速不变&#xff0c;这里也有个…

微信小程序技术架构图

一、视图层1.WXML&#xff08;WeiXin Markup Language&#xff09; 这是微信小程序的标记语言&#xff0c;类似于 HTML。它用于构建小程序的页面结构。例如&#xff0c;通过标签来定义各种视图元素&#xff0c;如<view>&#xff08;类似于 HTML 中的<div>&#xff…

GaussDB 华为高斯数据库

GaussDB 是华为推出的一款企业级分布式数据库&#xff0c;旨在为企业提供高效、可靠、安全的数据库服务。GaussDB 基于华为在数据库领域的多年积累&#xff0c;结合人工智能技术和分布式架构&#xff0c;支持多种场景的数据存储与管理需求&#xff0c;是云计算、大数据、人工智…

redis工程实战介绍(含面试题)

文章目录 redis单线程VS多线程面试题**redis是多线程还是单线程,为什么是单线程****聊聊redis的多线程特性和IO多路复用****io多路复用模型****redis如此快的原因** BigKey大批量插入数据测试数据key面试题海量数据里查询某一固定前缀的key如果生产上限值keys * &#xff0c;fl…

C++从零到满绩——入门基础and类和对象(上)

目录 1>>前言 2>>函数重载 3>>引用 3.1>>引用的概念 3.2>>引用三大特性 3.3>>引用的使用 3.4>>const引用 3.5>>指针与引用的关系 4>>inline内联函数 5>>nullptr 6>>类和对象&#xff08;上&#…

DDPM与DDIM中的采样

在深度生成模型中&#xff0c;采样&#xff08;Sampling&#xff09;指的是根据模型生成新样本的过程。在扩散模型&#xff08;Diffusion Models&#xff09;中&#xff0c;采样的关键是从高斯噪声逐步还原出原始数据。让我们分别探讨 DDPM 和 DDIM 的采样过程&#xff0c;以及…

python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改

Two-Step Vertification required&#xff1a; Please enter the mobile app OTPverification code: 01.因为巡检的服务器要双因子认证登录&#xff0c;也就是登录堡垒机时还要输入验证码。这对我的巡检查服务器的工作带来了不便。它的机制是每一次登录&#xff0c;算一次会话…

【Web前端】创建我的第一个 Web 表单

Web 开发中&#xff0c;表单是不可或缺的组成部分。无论是用户注册、登录还是反馈收集&#xff0c;表单都是与用户交互的重要方式。 什么是 Web 表单&#xff1f; Web 表单是一种用于收集用户输入数据的界面元素。它们允许用户在浏览器中输入信息并提交这些信息到服务器。Web …

JavaWeb后端开发知识储备2

目录 1.HttpClient 2.微信小程序开发 3.Spring Cache 1.HttpClient 简单来说&#xff0c;HttpClient可以通过编码的方式在Java中发送Http请求 2.微信小程序开发 微信小程序的开发本质上是前端开发&#xff0c;对于后端程序员来说了解即可 3.Spring Cache Spring Cache 是…

力扣刷题--21.合并两个有序链表

I am the best &#xff01;&#xff01;&#xff01; 题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2…