算法2.4——优先队列与堆排序

  优先队列(Priority Queues)的使用和队列(删除最老的元素)以及栈(删除最新的元素)类似。举个实用例子:也就是从10亿个元素中选出最大的10个,有了优先队列,就只需要用一个能存储10个元素的队列即可。

  而二叉堆很好实现优先队列的基本操作。其中二叉堆是一组能够用队友徐的完全二叉树排序的元素。其中关于堆的算法,有上浮swim和下沉sink,另外一般来说A[0]不使用,直接使用A[1]。

  堆排序的实现

  实现堆排序需要解决两个问题:

    1.如何由一个无序序列建成一个堆?

    2.如何在输出堆顶元素之后,调整剩余元素成为一个新的堆? 

    第二个问题,一般在输出堆顶元素之后,视为将这个元素排除,然后用表中最后一个元素填补它的位置,自上向下进行调整:首先将堆顶元素和它的左右子树的根结点进行比较,把最小的元素交换到堆顶;然后顺着被破坏的路径一路调整下去,直至叶子结点,就得到新的堆。

  我们称这个自堆顶至叶子的调整过程为“筛选”。

  从无序序列建立堆的过程就是一个反复“筛选”的过程。

实例过程:

建立初始的堆结构如图:

然后,交换堆顶的元素和最后一个元素,此时最后一个位置作为有序区(有序区显示为黄色),然后进行其他无序区的堆调整,重新得到大顶堆后,交换堆顶和倒数第二个元素的位置:

重复上述步骤:

代码实现(java):

public class Heap {

private Heap() { }

public static void sort(Comparable[] pq) {
int N = pq.length;
for (int k = N/2; k >= 1; k--) //构造堆
sink(pq, k, N);
while (N > 1) { //交换修复堆
exch(pq, 1, N--);
sink(pq, 1, N);
}
}

private static void sink(Comparable[] pq, int k, int N) {
while (2*k <= N) {
int j = 2*k;
if (j < N && less(pq, j, j+1)) j++;
if (!less(pq, k, j)) break;
exch(pq, k, j);
k = j;
}
}

private static void exch(Object[] pq, int i, int j) {
Object swap = pq[i-1];
pq[i-1] = pq[j-1];
pq[j-1] = swap;
}

HeapSort算法分析:
  堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。

  堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。

时间: 2024-10-10 17:06:26

算法2.4——优先队列与堆排序的相关文章

《算法导论》— Chapter 6 堆排序

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

算法 排序NB二人组 堆排序 归并排序

参考博客:基于python的七种经典排序算法     常用排序算法总结(一) 序前传 - 树与二叉树 树是一种很常见的非线性的数据结构,称为树形结构,简称树.所谓数据结构就是一组数据的集合连同它们的储存关系和对它们的操作方法.树形结构就像自然界的一颗树的构造一样,有一个根和若干个树枝和树叶.根或主干是第一层的,从主干长出的分枝是第二层的,一层一层直到最后,末端的没有分支的结点叫做叶子,所以树形结构是一个层次结构.在<数据结构>中,则用人类的血统关系来命名,一个结点的分枝叫做该结点的"

白话经典算法系列之七 堆与堆排序

堆排序与高速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先解说下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是全然二叉树或者是近似全然二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)不论什么一个子节点的键值. 2.每一个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于不论什么一个子节点的键值时为最大堆.当父结点的键值总是小于或等于不论什么一个子节点的键值时为最小堆.下图展示一个最小堆

[2] 算法之路 - 选择之堆排序

题目: 选择排序法的概念简单,每次从未排序部份选一最小值,插入已排序部份的后端,其时间主要花费于在整个未排序部份寻找最小值,如果能让搜寻最小值的方式加 快,选择排序法的速率也就可以加快 Heap排序法让搜寻的路径由树根至最后一个树叶,而不是整个未排序部份,从而可以加快排序的过程,因而称之为改良的选择排序法. 整个堆排序的过程分建堆.取值.调整为新的堆三个过程.分别如下示:(以最小堆积树为例.关于HeapTree请参阅数据结构与算法) 建堆 - 算法 1.  加至堆积树的元素会先放置在最后一个树叶

算法导论 第6章 堆排序

堆数据结构实际上是一种数组对象,是以数组的形式存储的,但是它可以被视为一颗完全二叉树,因此又叫二叉堆.堆分为以下两种类型: 大顶堆:父结点的值不小于其子结点的值,堆顶元素最大 小顶堆:父结点的值不大于其子结点的值,堆顶元素最小 堆排序的时间复杂度跟合并排序一样,都是O(nlgn),但是合并排序不是原地排序(原地排序:在排序过程中,只有常数个元素是保存在数组以外的空间),合并排序的所有元素都被拷贝到另外的数组空间中去,而堆排序是一个原地排序算法. 1.在堆排序中,我们通常使用大顶堆来实现,由于堆在

算法导论 第6章 堆排序(简单选择排序、堆排序)

堆数据结构实际上是一种数组对象,是以数组的形式存储的,可是它能够被视为一颗全然二叉树,因此又叫二叉堆.堆分为下面两种类型: 大顶堆:父结点的值不小于其子结点的值,堆顶元素最大 小顶堆:父结点的值不大于其子结点的值,堆顶元素最小 堆排序的时间复杂度跟合并排序一样,都是O(nlgn),可是合并排序不是原地排序(原地排序:在排序过程中,仅仅有常数个元素是保存在数组以外的空间),合并排序的全部元素都被复制到另外的数组空间中去,而堆排序是一个原地排序算法. 1.在堆排序中,我们通常使用大顶堆来实现,因为堆

白话经典算法系列之七 堆与堆排序(转)

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先讲解下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值. 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆.当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆.下图展示一个最小堆: 由于其它几

最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小支撑树(minimum spanning tree)算法.给定一个无向图G,并且它的每条边均权值,则MST是一个包括G的所有顶点及边的子集的图,这个子集保证图是连通的,并且子集中所有边的权值之和为所有子集中最小的. 本节中介绍三种算法求解图的最小生成树:Prim算法.Kruskal算法和Boruvk

【算法与数据结构】图说堆排序

1.堆   一棵完全二叉树 大顶堆:所有非叶子节点元素均不小于其左右子树根节点的值 小顶堆:所有非叶子节点元素均不大于其左右子树根节点的值 2. 初始化堆 ①一组无序元素R[0, 1, ..., n - 1], 先按照顺序将该组无序元素构造为一棵完全二叉树 ②从该二叉树的第一个非叶子结点开始调整,然后调整前一个结点(一定是非叶子结点),依次直到调整完根节点 ③上一步一遍完成后,再来一遍,直到该完全二叉树符合一个堆的定义为止 测试数据:R[] = {16, 7, 3, 20, 17, 8}, 本组