希尔排序与堆排序

1. 希尔排序

希尔排序也被称为“缩小增量排序”,其基本原理如下:

先将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序后”,最后再对所有元素进行一次直接插入排序。

希尔排序的具体步骤如下:

1)选择一个步长序列 t1,t2,...,tk ,满足 ti>tj(i<j),tk=1
2)按步长序列个数 k,对待排序序列进行 k 趟排序;
3)每趟排序,根据对应步长 ti ,将待排序序列分割成 ti 个子序列,分别对各个子序列进行直接插入排序。

程序示例如下;

public class SortShell {
    public static void shellSort(int[] array) {
        int length = array.length;
        int j, temp;
        for(int step = length/2; step > 0; step = step/2) {
            for(int i = step; i < length; i++) {
                temp = array[i];
                for(j = i - step; j >= 0; j -= step) {
                    if(temp < array[j]) {
                        array[j + step] = array[j];
                    }
                    else 
                        break;
                }
                array[j + step] = temp;
            }
        }
    }

    public static void main(String[] args) {
        int a[] = {5,4,9,8,7,6,0,1,3,2};
        shellSort(a);
        for(int i = 0;i <a.length; i++)
            System.out.print(a[i] + " ");
    }
}/* Output: 0 1 2 3 4 5 6 7 8 9 *///~

希尔排序的关键并不是随便地分组后各自排序,而是将相隔某个“增量”的记录组成一个子序列,实现跳跃式移动,使得排序的效率提高。

2. 堆排序

堆排序是一树形数据结构,在排序过程中,将 R[ 1 … n ] 看作一颗完全二叉树的顺序存储结构,利用完全二叉树中父结点和子结点之巅的内在关系来选择最小的元素。

堆一般分为大顶堆和小顶堆两种不同的类型。对于给定的 n 个记录的序列(r(1),r(2),…,r(n)),当且仅当满足条件(r(i)>=r(2i)且 r(i)>=r(2i+1),i = 1, 2 ,…, n)时称之为大顶堆,此时,堆顶元素必为最大值。对于给定的 n 个记录的序列(r(1),r(2),…,r(n)),当且仅当满足条件(r(i)<=r(2i)且 r(i)<=r(2i+1),i = 1, 2 ,…, n)时称之为小顶堆,此时,堆顶元素必为最小值。

堆排序的思想是:

对于给定的 n 个记录,初始时把这些记录看作一棵顺序存储的二叉树,然后将其调整为一个大顶堆,然后将堆的最后一个元素与堆顶元素(即二叉树的根节点)进行交换后,堆的最后一个元素即为最大记录;接着将前(n-1)个元素(即不包括最大记录)重现调整为一个大顶堆,再将堆顶元素与当前元素的最后一个元素进行交换后得到次大的记录,重复该过程直到调整的堆中只剩下一个元素时为止,该元素即为最小记录,此时可得到一个有序序列。

堆排序主要包括两个过程:

    (1)构建堆;
    (2)交换堆顶元素与最后一个元素的位置。

升序排序:构建大顶堆;交换堆顶元素与最后一个元素的位置。
降序排序:构建小顶堆;交换堆顶元素与最后一个元素的位置。

程序示例如下:

// 降序排序
public class SortHeap {
    public static void adjustMinHeap(int[] a, int pos, int len) {
        int temp, child;
        for(temp = a[pos]; 2*pos + 1 <= len; pos = child) {
            child = 2*pos + 1;
            if( child < len && a[child] > a[child+1] )
                child++;
            if( a[child] < temp )
                a[pos] = a[child];
            else
                break;
        }
        a[pos] = temp;
    }

    public static void MinHeapSort(int[] array) {
        int i;
        int len = array.length;
        for(i = len/2 - 1; i >= 0; i--) 
            adjustMinHeap(array,i,len-1);
        for(i = len - 1; i >= 0; i--) {
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            adjustMinHeap(array, 0, i-1);
        }
    }

    public static void main(String[] args) {
        int[] a = {5,4,9,8,7,6,0,1,3,2};
        MinHeapSort(a);
        for(int i = 0; i < a.length; i++)
            System.out.print(a[i] + " ");
    }
}/* Output: 9 8 7 6 5 4 3 2 1 0 *///~

堆排序方法对于记录较少的文件效果一般,但对于记录较多的文件还是很有效的,其运行时间主要耗费在创建堆和反复调整堆上。堆排序即使在最坏情况下,其时间复杂度也为O(nlogn)。

点赞