排序算法(3)—优先队列,堆排序

in 数据结构 with 0 comment

本文主要讨论基于二叉堆数据结构的优先队列的实现以及衍生的堆排序
实现优先队列还可以使用栈,队列等数据结构,在此略
文章最后附有堆排序完整代码

优先队列

1. 主要解决问题

有时候比不需要元素全部有序,操作时,我们可能只需要处理最大(最小)的元素
二叉堆的优先队列主要是高效(对数级别)实现删除最大元素,和插入元素操作。

对于其他数据结构的优先队列的实现:队列(删除最古老元素)以及栈(删除最新元素)类似

2. 二叉堆的概念

 1).当二叉树的每个节点都小于它的父结点,则称为堆有序。
 2).二叉堆中,位置为k的结点,父结点为不大于k/2的整数,子结点为2k和2k+1
 3).一颗大小为N的二叉树的高度不大于lgN的整数。

3. 二叉堆的两个重要操作

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

 堆的有序状态因为某个结点变得比他的父结点更大,而打破有序状态,则需要交换它与它的父结点来重新实现有序堆。
 
    private void swim(int k)
    {
        while(k>1 && less(k/2,k))
        {
            exch(k/2,k); //交换arr[k/2]和arr[k]元素位置
            k = k/2;     //第一次比较交换后,后面的结点仍要交换
        }
    }

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

 堆的有序状态因为某个结点比它的子结点更小而打破,则需要交换它与它的子结点中较大来实现有序堆。
 
    private 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);
            k = j;
        }
    }

4. 基于二叉堆的优先队列实现

1).插入元素

 将新元素添加到数组末尾,增加堆的大小,并让这个新元素上浮到合适位置。
    public void insert(T v)
    {
        arr[++N] = v;
        swim(N);
    }

2).删除最大元素

 从数组的顶端删除最大元素,并将,并且将堆中最后一个元素放到顶端(此时有序堆被打破),减小堆大小,并让这个元素下沉到合适位置。
 
    public T delMax()
    {
        T del = arr[1];
        exch(1,N--);
        arr[N+1] = null; //防止对象游离
        sink(1);
        return del;
    }

复杂度

 对于一个含有N个元素的堆优先队列,插入元素不超过(lgN+1)次比较
 删除元素的操作不超过2lgN次比较

5. 堆排序

    **1).思想:**
 将原始数组重新组织放进堆中,在下沉排序阶段,按递减顺序一次取得元素并得到排序结果
 **2).实现:**
 
    public static void HeapSort(Comparable[] arr)
    {
        int N = arr.length;
        for(int k = N/2; k>=1; k--)
            sink(arr,k,N);
        while(N>1)
        {
            Hexch(arr,1,N--);
            sink(arr,1,N);
        }
    }

3).复杂度:

     时间复杂度:NlogN
     空间复杂度:1

4).堆排序特点:

    目前所知的唯一同时最优利用时间和空间的排序方法—最坏的情况下也能保证使用~NlgN次比较的额外空间。
    所以堆排序适用于空间十分紧张的时候(嵌入式系统等)。

堆排序完整代码:

package sort;
/**
  * @author : luoz
  * @date time:2016年9月4日 上午12:10:48 
**/
public class HeapSort {
    
    //数组索引从零开始,而二叉树从1开始,所以传入参数-1,下同.
    private static boolean Hless(Comparable[] a,int i,int j)
    {
        return a[i-1].compareTo(a[j-1])<0;
    }
    
    private static void Hexch(Comparable[] a,int i,int j)
    {
        Comparable t = a[i-1];
        a[i-1] = a[j-1];
        a[j-1] = t;
    }
    
    //sink()以a[],N作为参数,其他不变.
    private static void sink(Comparable[] a,int k,int N)
    {
        while(2*k <= N)
        {
            int j = 2*k;
            if(j<N && Hless(a,j,j+1)) 
                j++;
            if(!Hless(a,k,j))
                break;            
            Hexch(a,k,j);
            k = j;
        }
    }
    /**
     * 传入数组arr,N为数组长度.    
     * @param arr
     */
    public static void heapSort(Comparable[] arr)
    {
        int N = arr.length;
        for(int k = N/2; k>=1; k--)
            sink(arr,k,N);
        while(N>1)
        {
            Hexch(arr,1,N--);
            sink(arr,1,N);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        Comparable[] HeapArray = {"A","C","E","D","K","Z"};        
        heapSort(HeapArray);        
        for(Comparable a : HeapArray)
            System.out.println(a);        
    }

}

算法第四版


内容原创,转载注明出处
Responses