二叉树(2)——堆的实现

  •   堆表面是数组,内核是完全二叉树/满二叉树
  •   在插入删除的时候要注意操作过后堆是否还是一个堆,要进行交换等操作。(向上调整
  •   逻辑上控制二叉树,物理上控制数组!!!

接下来我们用【小堆】来介绍堆的代码实现。

Heap.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int HPDataType;//定义堆结构体
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
int HeapSize(HP* php);
bool HeapEmpty(HP* php);

Heap.c

HeapInit初始化

void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}

HeapDestroy销毁

void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}

HeapPush插入数据

  • 这里要注意在一个堆后插入一个数,这个堆是否还是堆的问题。所以要将插入的数和他的父亲进行比较。
  • 同时要考虑,如何使一个随机的数组排列成堆?这个问题在test.c中就可解决。

Swap函数实现

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}

AdjustUp函数实现

  • 理解判断条件:child > 0
  • 首先比较插入的数和它的父亲,然后进行判断。
  • 若满足判断条件,就交换两个数的位置,并让child向上调整到parent的位置,让parent向上调整到它的父亲的位置,依此类推。
void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (parent >= 0) 不能这样写,因为parent不可能<0while (child > 0) //用child判断{if (a[child] < a[parent]){Swap(&a[child], &a[parent]);//往上走child = parent;parent = (child - 1) / 2;//child = (child - 1) / 2;//parent = (parent - 1) / 2;}else{break;}}
}

HeapPush函数实现

  • 时间复杂度为O(logN),也就是高度次。
void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

HeapPop删除数据 

  • 删除根
  • 不能用挪动覆盖法,堆会彻底乱掉,且时间复杂度是O(N)。
  • 方法:首尾交换再尾删,然后向下调整。 这样左右子树依旧是小堆。时间复杂度为O(logN)。
  • 如何判断叶子? 叶子*2+1>size

Swap函数实现

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}

AdjustDown函数实现

  • 越界问题:这里要注意在while里一定要加上【child+1<size】这个判断条件,因为如果child是完全二叉树叶子的左孩子,而且没有右孩子的情况,那么【if (a[child + 1] < a[child])】这个child+1就会越界。
void AdjustDown(int* a, int size, int parent)
{//假设左孩子小,如果事实是右孩子小,那么就更新childint child = parent * 2 + 1;while (child+1 < size && child < size){if (a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}

HeapPop函数实现

void HeapPop(HP* php)
{assert(php);assert(php->size > 0);//首尾交换Swap(&php->a[0], &php->a[php->size - 1]);//删除php->size--;//向下调整AdjustDown(php->a, php->size, 0);
}

 HeapTop取堆顶元素

HPDataType HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}

HeapSize堆元素个数

int HeapSize(HP* php)
{assert(php);return php->size;
}

 HeapEmpty判断是否为空

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

Test.c

首先测试一下插入。

  • ⭐要注意这里使用了for循环,将数组中的数一个一个插入,然后排列成堆。这样就能保证这个数组是一个堆啦!
int main()
{int a[] = { 4,6,2,1,5,8,2,9};HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); ++i){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n");return 0;
}

测试取数组中前k个小的元素。

  • 这里先将数组里的数据排列成一个小堆,然后用while循环, 取一个堆顶元素删一个。
int main()
{int a[] = { 4,6,2,1,5,8,2,9};HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); ++i){HeapPush(&hp, a[i]);}int k = 3;while (k--){printf("%d\n", HeapTop(&hp));HeapPop(&hp);}return 0;
}

输出小堆

int main()
{int a[] = { 4,6,2,1,5,8,2,9};HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); ++i){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n");return 0;
}

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

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

相关文章

DockerUI如何部署结合内网穿透实现公网环境管理本地docker容器

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

vue基本语法总结大全

vue基本语法 文章目录 vue基本语法基本用法内容渲染指令属性绑定指令使用js表达式事件绑定指令条件渲染指令v-else和v-else-if指令列表渲染指令v-for中的key 组件化开发安装详细讲解 第三方组件1. 组件间的传值2. element-ui介绍3. 组件的使用4. 图标的使用 Axios网络请求1. Ax…

LeetCode、198. 打家劫舍【中等,一维线性DP】

文章目录 前言LeetCode、198. 打家劫舍【中等&#xff0c;一维线性DP】题目及分类思路线性DP&#xff08;一维&#xff09; 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注…

Redis核心技术与实战【学习笔记】 - 25.Redis 支撑秒杀场景的关键技术

简述 秒杀是一个非常经典的活动场景&#xff0c;比如&#xff0c;在双 11、618 等电商促销活动中&#xff0c;都会有秒杀场景。秒杀场景的业务特点是限时限量&#xff0c;业务系统要处理瞬时的大量高并发请求&#xff0c;而 Redis 就经常被用来支撑秒杀活动。 秒杀场景包含多…

代码随想录算法训练营第二十七天|39. 组合总和、40. 组合总和 II、131. 分割回文串。

39. 组合总和 题目链接&#xff1a;组合总和 题目描述&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这…

PMP证书可以挂靠吗?

PMP证书的意义并不是为了挂靠&#xff0c;而是实际项目管理中的使用。 在考证人的质疑中总会有一个质疑就是“我所考的证书能挂靠吗&#xff1f;”其实PMP认证和其他认证一样只是证明你所掌握的专业知识的一个证明&#xff0c;无法有挂靠作用&#xff0c;千万不要相信那些说PM…

流浪动物救助|基于Springboot的流浪动物救助平台设计与实现(源码+数据库+文档)

流浪动物救助平台目录 目录 基于Springboot的流浪动物救助平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、动物信息管理 3、商品评论管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设…

华清作业day53

1.c代码&#xff1a; #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> struct msgbuf{long in…

2.5消息队列实现进程之间通信

send.c #include<myhead.h>//定义消息类型 struct msgbuf {long int mtype; //消息类型char mtext[1024]; //消息正文内容 };//宏定义一个消息大小 #define MSGSIZE sizeof(struct msgbuf)-sizeof(long int) int main(int argc, const char *argv[]) {//1、创建key值以…

【数据结构与算法】(10)基础数据结构 之 堆 建堆及堆排序 详细代码示例讲解

目录 2.9 堆建堆习题E01. 堆排序E02. 数组中第K大元素-Leetcode 215E03. 数据流中第K大元素-Leetcode 703E04. 数据流的中位数-Leetcode 295 2.9 堆 以大顶堆为例&#xff0c;相对于之前的优先级队列&#xff0c;增加了堆化等方法 public class MaxHeap {int[] array;int siz…

浅谈交换原理(1)——概述

一、什么是交换 在通信系统中&#xff0c;我们所认知的最简单的通信方式就是点对点通信&#xff0c;但是当有多个终端需要进行相互通信时&#xff0c;点对点通信就具有一定的局限性&#xff0c;如下图所示&#xff1a; 我们如果想要做到全互连方式两两相连&#xff0c;假设终端…

04. 【Linux教程】安装 Linux 操作系统

通过前面的小节学习&#xff0c;我们已经对 Linux 操作系统有了简单的了解&#xff0c;同时也在 Windows 下安装了虚拟机软件 VMware &#xff0c;那么本节课我们就介绍下如何使用虚拟机软件安装 Linux 操作系统。 通过第一小节的学习我们知道 Linux 有很多的发行版本&#xf…