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

本文介绍了堆排序中的最小堆及其在优先级队列中的应用。通过《算法导论》中的实现,展示了如何使用最小堆构建优先级队列。以PKU JudgeOnline的2312题——Battle City为例,详细阐述了如何利用最小堆进行代价一致搜索,解决坦克到达目的地的最短步数问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值