实用算法实践-第 3 篇 堆排序

【数据结构与算法】内部排序之三:堆排序(含完整源码) 堆排序、快速排序、归并排序(下篇会写这两种排序算法)的平均时间复杂度都为O(n*logn)。要弄清楚堆排序,就要先了解下二叉堆这种数据结构。本文不打算完全讲述二叉堆的所有操作,而是着重讲述堆排序中要用到的操作。比如我们建堆的时候可以采用堆的插入操作(将元素插入到适当的位置,使新的序列仍符合堆的定义)将元素一个一个地插入到堆中,但其实我们完全没必要这么做,我们有执行操作更少的方法,后面你会看到,我们基本上只用到了堆的删除操作,更具体地说,应该是删除堆的根节点后,将剩余元素继续调整为堆的操作。先来看二叉堆的定义 阅读详情

虽然堆排序算法是一个很漂亮的算法,但是在实际中,快排序的一个好的实现往往优于堆排序。尽管这样堆数据结构还有很大的用处,例如优先级队列。

3.1    最小堆

下面的程序就是按照《算法导论》最小堆的优先级队列的实现,修改几个小于号(大于号)可以轻易地将最小堆变成最大堆。

最小堆的一个用法实例是在Huffman编码中。

3.1.1   最小堆的优先级队列程序

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define maxNum     100000
#define MAX        0x7FFFFFFF
int minHeap[maxNum] = {0, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
int heapSize;
 
void minHeapify(int i)
{
     int l;
     int r;
     int min;
     int temp;
     l = i * 2;
     r = i * 2 + 1;
     min = i;
     if((l <=heapSize)&&
     (minHeap[l] < minHeap[min])){
         min = l;
     }
     if((r <=heapSize)&&
     (minHeap[r] < minHeap[min])){
         min = r;
     }
     if(min !=i)
     {
         temp = minHeap[min];
         minHeap[min] = minHeap[i];
         minHeap[i] = temp;
         minHeapify(min);
     }
}
void buildMinHeap()
{
     int i;
     for(i =heapSize / 2; i > 0; i--){
         minHeapify(i);
     }
}
int heapExtractMin()
{
     int min;
     if(heapSize< 1)
     {
         return0;
     }
     min = minHeap[1];
     minHeap[1] = minHeap[heapSize];
     heapSize--;
     minHeapify(1);
     return min;
}
void heapIncreaseKey(int i, int key)
{
     int temp;
     if(key <minHeap[i])
     {
         cout << "newkey is smaller than current key" << endl;
     }
     minHeap[i] = key;
     while(i> 1 && minHeap[i/2] > minHeap[i])
     {
         temp = minHeap[i];
         minHeap[i] = minHeap[i/2];
         minHeap[i/2] = temp;
         i = i / 2;
     }
}
void minHeapInsert(int key)
{
     heapSize++;
     minHeap[heapSize] = MAX;
     heapIncreaseKey(heapSize, key);
}
 
int main()
{
     int i;
     heapSize = 10;
     buildMinHeap();
}


3.2    最小堆实现优先队列

由于队列是不断地增删的,所以使用堆来实现优先队列是非常自然而令人愉快的事情。

3.2.1   实例

PKU JudgeOnline, 2312, Battle City.

3.2.2   问题描述

坦克大战中,一辆坦克可以在1步内走到一个没有东西的相邻位置。也可以在1步内打碎泥巴墙,但是不能打破铁墙,也不能过河。试问坦克从出发点到目的地的最少步数。

3.2.3   输入

34

YBEB

EERE

SSTE

00

3.2.4   输出

8

3.2.5   分析

这里很容易想到DFS算法。用DFS需要使用一个队列,该队列是标准的先进先出。但是这个题目的队列取要用优先级队列。优先级的级别和坦克初始出发点到该位置的距离成反比。故此优先队列可以用关于距离的最小堆来实现。

这里用到的方法实际上是代价一致搜索。

1.2.6   程序

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define maxNum     100000
#define MAX        0x7F7F7F7F
struct node{
     int key;
     int x;
     int y;
};
nodeminHeap[maxNum];
int heapSize;
void minHeapify(int i)
{
     int l;
     int r;
     int min;
     node temp;
     l = i * 2;
     r = i * 2 + 1;
     min = i;
     if((l <=heapSize)&&
     (minHeap[l].key < minHeap[min].key)){
         min = l;
     }
     if((r <=heapSize)&&
     (minHeap[r].key < minHeap[min].key)){
         min = r;
     }
     if(min !=i)
     {
         temp = minHeap[min];
         minHeap[min] = minHeap[i];
         minHeap[i] = temp;
         minHeapify(min);
     }
}
void buildMinHeap()
{
     int i;
     for(i =heapSize / 2; i > 0; i--){
         minHeapify(i);
     }
}
nodeheapExtractMin()
{
     node min;
     if(heapSize< 1)
     {
         cout << "ERROR:no more" << endl;
     }
     min = minHeap[1];
     minHeap[1] = minHeap[heapSize];
     heapSize--;
     minHeapify(1);
     return min;
}
void heapIncreaseKey(int i, int key)
{
     node temp;
     if(key >minHeap[i].key)
     {
         cout << "ERROR:new key is smaller than current key" << endl;
     }
     minHeap[i].key = key;
     while(i> 1 && minHeap[i/2].key > minHeap[i].key)
     {
         temp = minHeap[i];
         minHeap[i] = minHeap[i/2];
         minHeap[i/2] = temp;
         i = i / 2;
     }
}
void minHeapInsert(node temp)
{
     heapSize++;
     minHeap[heapSize] = temp;
     minHeap[heapSize].key = MAX;
     heapIncreaseKey(heapSize, temp.key);
}
#define EMPTY 'E'
#define RIVER 'R'
#define STEEL 'S'
#define TARGET     'T'
#define YOU   'Y'
#define BRICK 'B'
int adj[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
char map[302][302];
int calKey(int X, intY)
{
     switch(map[X][Y]){
         caseRIVER: return MAX;
         caseSTEEL: return MAX;
         caseBRICK: return 2;
         caseEMPTY: return 1;
         caseTARGET: return 1;
         caseYOU: return 1;
         default:return MAX;
     }
     return MAX;
}
int main()
{
     int M;
     int N;
     int i;
     int j;
     int youX;
     int youY;
     inttargetX;
     inttargetY;
     int x;
     int y;
     intdistance;
     node temp;
     node insertNode;
     boolvisited[302][302];
     char c;
     int min;
     while(scanf("%d%d", &M, &N)){
         if(M ==0 && N == 0)
         {
              break;
         }
         scanf("%c",&c);
         memset(visited, 0, sizeof(visited));
         memset(map, RIVER, sizeof(map));
         for(i =1; i <= M; i++){
              scanf("%s",&map[i][1]);
         }
         for(i =1; i <= M; i++){
              for(j= 1; j <= N; j++){
                   if(map[i][j]== YOU){
                       youX = i;
                       youY = j;
                   }elseif(map[i][j] == TARGET){
                       targetX = i;
                       targetY = j;
                   }
              }
         }
         heapSize = 0;
         insertNode.key = 0;
         insertNode.x = youX;
         insertNode.y = youY;
         minHeapInsert(insertNode);
         min = MAX;
         while(heapSize> 0){
              temp = heapExtractMin();
              if(temp.x== targetX&& temp.y == targetY)
              {
                   min = temp.key;
                   break;
              }
              for(i= 0; i < 4; i++){
                   x = temp.x + adj[i][0];
                   y = temp.y + adj[i][1];
                   distance = calKey(x, y);
                   if((visited[x][y]== 0)&&
                   (distance != MAX))
                   {
                       visited[x][y] = 1;
                       insertNode.key = temp.key+ distance;
                       insertNode.x = x;
                       insertNode.y = y;
                       minHeapInsert(insertNode);
                   }
              }
         }
         if(min!= MAX){
              cout << min << endl;
         }else{
              cout << "-1" << endl;
         }
     }
     return 1;
}

1.3    实例

PKU JudgeOnline, 2312, Battle City.

本文章欢迎转载,请保留原始博客链接http://blog.youkuaiyun.com/fsdev/article

【算法】堆排序 基础排序算法之一:堆排序。 阅读详情

相关推荐

【python算法系列四】堆排序算法

堆排序,就像它的名字一样,利用了堆的特性来进行排序。实现堆排序的思路是,把数组构建成一棵二叉树,并随着每次堆的变化更新堆顶的最大/最小值。堆排序的时间复杂度在所有情况下都是 O(nlgn),它也是一个不稳定的算法。在开始编写堆排序的程序之前,我们首先要了解“堆”的概念。 堆是一种数据结构,它是一种特殊的完全二叉树:如果这个堆是一个大顶堆(最大的元素在堆顶),那么每个节点上的元素都应该比它的子节点上的元素要大,最大的元素在根节点上;反之,如果是小顶堆,那么每个节点上的元素都应该比它的子节点小,最小的元素在根节

m0_70372647的博客 2379

堆排序(源码C)

思路: 堆排序主要分为俩个部分,一个是构建堆(主要的,根节点下的俩个子节点大小差距不一定,其子节点不一定按顺序排),另外一个是调整堆。 构建堆(第一个for循环,自下而上)之后,初步的顺序出来了,堆顶便是最大的值,我们将他定为老大,俩个子节点为老二,俩个老二分别代表俩个分支,他们分别是俩个分支中的最强者(一人之下万人之上的.........

长臂人猿的博客 1039

堆排序算法的实现

1、什么是堆 “(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树。树上的每一个节点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充”。这是算法导论里对堆的定义,说得很清晰明了,当然最好还是得上个图,所以这里就顺便也从算法导论里盗个图了。。。。 二叉堆可以分为两种形式,最大堆和最小堆。在这两种堆中,节点的值都要满足堆的性质,同时在最大堆中,除了根以外的所有节...

sh805499910的博客 1945

堆排序(HeapSort)

本文主要介绍堆排序算法(HeapSort),堆排序像合并排序而不像插入排序,堆排序的运行时间为O(nlgn);像插入排序而不像合并排序,它是一种原地(in place)排序算法。在任何时候,数组中只有常数个元素存储在输入数组以外,这样,堆排序就把插入排序和合并排序的优点结合起来。 堆排序还引入了另外一种算法设计技术,利用某种数据结构(在此算法中为“堆”)来管理算法执行中的信息。堆数据结构...

指尖飞舞 493

堆排序基础与实践:如何在Java中实现堆排序

堆排序(Heap Sort)是一种基于堆数据结构的排序算法。堆是一种特殊的完全二叉树,堆排序利用堆的性质通过一系列操作将数组元素按升序或降序排列。堆排序的时间复杂度为 O(n log n),是一种不稳定的排序算法,且其空间复杂度为 O(1),因此在某些场景下非常有用。

u012372850的专栏 1221

OpenRA引擎实战:如何从零开始搭建一个经典RTS游戏模组(附资源包)

本文详细介绍了如何利用开源游戏引擎OpenRA从零开始搭建经典RTS游戏模组。内容涵盖开发环境配置、资源管线处理、YAML规则定义、地图编辑与Lua脚本编写等全流程实战指南,并提供了资源包,帮助开发者和爱好者快速创建属于自己的即时战略游戏世界。

silver的专栏 904

C语言-数据结构-堆排序(heap sort)-源代码

1. 堆排序 堆排序的定义及思想可以参考百度百科:堆排序 用一句概括,堆排序就是一种改进的选择排序,改进的地方在于,每次做选择的时候,不单单把最大的数字选择出来,而且把排序过程中的一些操作进行了记录,这样在后续排序中可以利用,并且有分组的思想在里面,从而提高了排序效率,其效率为O(n*logn). 2. 源代码 堆排序中有两个核心的操作,一个是创建大顶堆(或者小顶堆,这里用的是大顶堆...

生命在于折腾! 1万+

【深度学习】tensorboard中的图片放到论文中

1. 利用tensorboard中的导出数据功能 选中左上角的标签,然后选择csv格式的数据下载即可。 左边的smoothing 数值不影响导出数据的大小。 2.tensorboard 图下标签介绍: 放大 Toggle y-axis log scale:将y轴对数化 Fit domain to data:如果拖动了图片等,再重新回到原始位置 Download Current Chart as SVG 3.用下载下来的csv数据来画图 第一幅图片:训练的平均长度 fig, ax1 = plt.sub

gaocui883的博客 1万+

排序算法:堆排序

关于排序算法中的堆排序的详细介绍,以及实现过程和时间复杂度的计算,附带图解。

Yikefore的博客 3454

博图V16与840D sl数控系统PLC编程实战指南

本文为西门子840D sl数控系统的PLC编程实战指南,详细介绍了如何使用博图V16软件配置编程环境。内容涵盖从项目创建、核心程序块(如DB、FB)解析到OB1主循环编程的完整流程,并提供了高级调试技巧与联调避坑指南,帮助工程师快速上手并高效完成系统集成与逻辑控制。

weixin_29193259的博客 527

[RK3568][Android11.0]Vold-DiskInfo:区分u盘和硬盘

测试平台 Platform: RK3568 OS: Android 11.0 需求描述 目前系统内部设备没有对硬盘(sata/usb移动硬盘)和u盘做区分,统一显示的为usb存储设备.目前有需求要在显示上有所区分。 解决方案 如何区分移动硬盘和U盘,见Android usb设备的检测及区分(sata硬盘、优盘及移动硬盘).主要就是检测removeable值,为0:硬盘,为1:u盘 解决补丁如下 From 572cf35c07f68c5cb5defe40c536dd9ad1b4648e Mon Sep 17

weixin_39966398的博客 1897

十大经典排序算法-堆排序算法详解

一、什么是堆排序 1.概念 堆排序(Heapsort)是利用二叉堆的概念来排序的选择排序算法,分为两种: 升序排序:利用最大堆进行排序 降序排序:利用最小堆进行排序 2.算法原理 给定一个最大堆如下图所示,以该最大堆进行演示堆排序 首先,删除堆顶元素10(即最大的元素),并将最后的元素3补充到堆顶,删除的元素10,放置于原来最后的元素3的位置 根据二叉堆的自我调整,第二大的元素9会成为二叉堆新的堆顶 删除元素9,元素8成为最大堆堆顶 删除元素8,元素7成为最大堆堆顶 依次删除最大元素,直至所有

qq_35344198的博客 1万+

DaVinciCFG实战:从ARXML配置到ADC代码生成全解析

本文详细解析了使用DaVinciCFG工具进行ADC模块配置的全过程,从ARXML文件处理到代码生成与集成。重点介绍了关键参数配置、ARXML语法规则、常见错误排查及代码优化技巧,帮助开发者掌握AUTOSAR架构下ADC驱动开发,提升汽车电子系统的可靠性。

f9g0h的博客 379

堆排序算法

一、堆排序算法基本思想 堆排序是利用堆数据结构而设计的一种排序算法,堆排序是一种选择排序,其最坏,最好,平均时间复杂度均为O(nlogn),同时也是不稳定排序。 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆, 如下图所示,其中大顶堆的性质**:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]** 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆,如下图所示,其中小顶堆性质:arr[i] <=

qq_44111805的博客 7774

有道龙虾LobsterAI vs. OpenClaw:对比与安装部署攻略

LobsterAI是"中国版OpenClaw",更注重易用性和中文场景适配;OpenClaw是技术极客的玩具,需要大量命令行操作。

lpfasd123的博客 2395

激光雷达与相机外参标定(附open3d python代码)

现在的激光雷达与相机的标定程序基本都是Ubuntu框架下面的,并且都是C++代码,需要安装的依赖也比较复杂,于是自己写了一个python版本的标定程序,依赖非常简单,Windows系统也可以运行。我这里用的大疆的雷达,点比较密集,更容易用我这种方法标定,旋转的16,32线的雷达也可以用这种方法标定,只是标定点会相对难选取一些。2 手动在点云上选取N个标定点(每个点都对应图像上的点,顺序也要一致)3 通过PNP方法计算出二者的旋转投影矩阵,也就是外参矩阵。1 手动在图像上面选取N个标定点。

三维点云技术探索 3412

必学排序算法——堆排序

堆排序算法是必须掌握的一种基础算法,在一些比较出名的竞赛acm、蓝桥杯,并且在一些公司面试题中都可能会出现,而且作为简单题我们必须要拿下,所以我们要引起重视,下面让我们来深入了解堆排序算法。堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。堆是一个近似完全二叉树的结构,分为最大堆和最小堆。在最大堆中,父节点的值总是大于或等于其子节点的值;而在最小堆中,父节点的值总是小于或等于其子节点的值。堆排序通常使用最大堆来升序排序数组,使用最小堆则可以降序排序数组。

ycs66的博客 3956

【Matlab算法】MATLAB实现的语音信号降噪算法(附MATLAB完整代码)

语音信号降噪是语音处理领域中的一个关键问题。在实际应用中,语音信号常常被各种环境噪声污染,这不仅影响了语音的质量,还可能导致后续处理(如语音识别)的性能下降。因此,开发有效的降噪算法对于提高语音通信质量、改善语音识别系统性能等具有重要意义。 本文将介绍并实现两种经典的语音信号降噪算法:谱减法和维纳滤波。这两种方法都是基于频域处理的技术,具有实现简单、计算效率高的特点。通过MATLAB实现这些算法,我们可以直观地比较它们的性能和降噪效果。

Albert_Lsk的博客 1329

C语言——快速排序算法——堆排序

堆是一个完全二叉树(Complete Binary Tree),其中每个节点的值都大于等于(或小于等于)其子节点的值,这被称为堆的性质。具体来说,如果每个节点的值都大于等于其子节点的值,我们称之为“最大堆”(Max Heap);如果每个节点的值都小于等于其子节点的值,我们称之为“最小堆”(Min Heap)。例如一个最大堆:堆通常使用数组来实现,其中每个元素对应堆中的一个节点。通过索引关系可以方便地找到父节点、左孩子和右孩子。

qq_34434522的博客 1281

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

堆排序每一趟的结果_八大排序-堆排序(手写堆排序)

闲聊最近看完一个电视剧,猪脚是胃无限和难忘鸡。比较奇怪的是整个电视剧没有讲爱得死去活来的男女之情反而讲的是男男之间纯纯的知己之情(基情),不过别说还挺好看。有种感觉就像:天下人负你又如何,我定然站你这边...让我想到了当今社会的一些人,这类人习惯权衡利弊后“战队”,或察言观色后随波逐流不顾真理事实。这部剧表达的三观就像一股清流,人生难得一知己,让我内心颇有触动。很喜欢胃无限说的一句话:管他熙熙攘攘...

weixin_39635432的博客 3848

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

堆排序算法实现

堆排序:结构逻辑上是完全二叉树,但是可以使用顺序存储来实现 一些二叉树的区别: 二叉树:度数最大为2并且每个子树也是二叉树 满二叉树:每层节点都是满的,没有空缺,也就是,叶子节点只能出现在最后一层 完全二叉树:限制条件比满二叉树弱化,只需要前k-1层是复合满二叉树结构,最后一层的叶子节点都靠左排列,右侧可以出出现连续缺失(一个学序列可以按照编号一一对应上满二叉树的节点编号) 排序二叉树: 二...

David的博客 5385

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

面试算法理解篇——堆排序的应用

前言 这篇仍然是面试笔试中的一篇小总结。再次申明:不足之处请各位不吝赐教。 堆排序算法 首先说说什么叫堆,以及和BST(二叉查找树,二叉排序树),AVL(平衡二叉树)的区别。 堆在内存中很常见,一般内存中分配都是以堆栈分配的(这里原谅渣渣我对jvm虚拟机还没有足够深的认识,这里不敢瞎说)。堆考的最多的有两种,最大堆和最小堆。简单来说: 最大堆:树的父亲节点比它的子结点大,即...

好大的小飞虫的博客 543
上一篇: 实用算法实践-第 2 篇 有序数组的二分查找
下一篇: 实用算法实践-第 4 篇 散列表
存储李希
博客等级 码龄15年 418粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值