算法之 排序算法 (三) Java

来源:互联网 发布:ubuntu 麒麟wineqq 编辑:程序博客网 时间:2024/04/28 08:28

1. 堆的定义

  n个元素的序列{K1...Kn}当且仅当满足以下关系

或者反过来大于时称之为堆

  若将和此序列对应的一维数组(即一维数组作此序列的存储结构)堪称一个完全二叉树,则堆的含义表明:完全二叉树中所有非终端结点的值均不大于(或不小于)其左右孩子节点的值。

  若在输出堆顶的最小值后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素中的次小值,如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。

注:在一个堆中,位置k的节点对应的父节点的位置为[k/2](除后最大正整数),他的两个子节点的值分别为2k和2k+1,则通过索引来计算树中的上下移动:从a[k]上移一层就令等k/2,向下一层则令k等于2k或者2k+1;


2. 堆的算法

  我们用长度为N+1的数组表示一个大小为的堆,因为pq[0]不使用,堆元素放在pq[1]至pq[N]中。

  在有序化的过程中,我们会遇到两种情况,当某个阶段的优先级上升(或是在堆底加入一个新的元素)时,我们需要由下至上恢复堆的顺序,当某个节点的优先级下降时(如:将根节点替换为一个较小的元素)时,我们需要由上至下恢复堆的顺序。我们需要通过如何实现这两种辅助操作,然后再用他们实现其他操作。

2.1 由下至上的堆有序化(上浮)

  如果堆的有序状态因为某个结点变得比它的父节点更大而被打破,那么我们就需要通过交换它和它的父节点来修复堆。交换后,这个结点比它的两个子节点都大,但是可能比它交换后的父节点还大,所有可以一遍一遍的用同样的方法进行维护秩序,将这个几点不断向上移动直到我们遇到一个更大的父节点。只要记住位置k的结点的父节点的位置是[k/2]。

上浮实现代码如下:

private void swim(int k){while(k>1&&less(k/2,k)){exch(k/2,k);}}

2.2 由上至下的堆有序化(下沉)

如果堆的有序状态因为某个结点变得比它的两个子节点或是其中之一更小而被打破,那么我们可以通过将它和它的两个子节点的较大者交换来恢复堆。位置k的结点对应的子节点位于2k和2k+1.

实现代码如下:

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

  • 插入元素:我们将新元素加到数组末尾,增加堆的大小并让这个新元素上浮到合适的位置。
  • 删除最大元素:我们从数组顶端删去最大的元素并将数组的最后一个元素放到顶端,减小堆的大小并让这个元素下沉到合适的位置


3.堆排序

3.1 堆的构造

从N个给定的元素构造一个堆有两种方式:

  从左至右遍历数组,用swim()保证扫描指针左侧的所有元素已经是一颗有序的完全树;

  从右至左用sink()函数构造子堆,数组的每个位置都已经是一个子堆的根节点,sink()对于这些子堆也适用,如果一个结点的两个子节点都已经是堆了,那么在该结点上调用sink可以将他们变成一个堆,这个过程会递归的建立起堆的秩序。开始时只需要扫描数组中一半的元素,因为我们可以跳过大小为1的子堆,最后我们在位置1上调用sink()方法,扫描结束。

3.2 算法实现

package rte;public class HeapSort {private void swim(int k,int[]a,int N){while(k>1&&less(k/2,k,a)){exch(k/2,k,a);}}private static void sink(int k,int[] a,int N){while(2*k<=N){int j=2*k;if(j<N&&less(j,j+1,a))j++;if(!less(k,j,a))break;exch(k,j,a);k=j;}}private static void exch(int k,int j,int[]a){int tmp = a[k-1];a[k-1]=a[j-1];a[j-1]=tmp;}private static boolean less(int i,int j,int []a){if(a[i-1]<a[j-1])return true;else return false;}public static void sort(int[]a){int N = a.length;for(int k=N/2;k>=1;k--){sink(k,a,N);}//构造堆               while(N>1){exch(1,N--,a);sink(1,a,N);}//堆排序}}



0 0
原创粉丝点击