堆排序

堆排序(heapsort)是一种原地(in place)排序算法, 它的时间复杂度是O(nlgn). 堆数据结构不只是在堆排序中有用,它还可以构成一个有效的优先队列。

堆数据结构是一种数组对象,它可以被视为一颗完全二叉树。如图:

 

      A

heap-size是放在A中堆的元素个数。根据数组节点的索引,我们可以分别推测节点i的父节点和孩子节点的索引位置

PARENT(i)

  return low_round(i/2);

LEFT(i)

  return 2i;

RIGHT(i)

  return 2i+1;

二叉堆有两种:大根堆和小根堆。大根堆是指除了根以外的每个节点i,有A[PARENT(i)]>=A[i]。也就是说父节点的大小大于其孩子节点的大小。同理可得小根堆:A[PARENT(i)]<=A[i].

对于一种数据结构来说,向其内插入数据或者删除数据都要保持此数据结构的性质。堆数据结构也是这样的,为了保持堆的性质,下面介绍对最大堆进行操作的重要的子程序 MAX-HEAPIFY

一、保持堆的性质  

假定以LEFT(i) 和RIGHT(i)为根的两颗二叉树都是大根堆,但这时A[i]可能小于其子女,这样就违反了大根堆的性质。 MAX-HEAPIFY就是让A[i]在大根堆中“下降”,使得以i为根的子树满足大根

堆的性质。

下面贴出伪码:

MAX-HEAPIFY(A, i)
 1 l ← LEFT(i)
 2 r ← RIGHT(i)
 3 if l ≤ heap-size[A] and A[l] > A[i]
 4    then largest ← l
 5    else largest ← i
 6 if r ≤ heap-size[A] and A[r] > A[largest]
 7    then largest ← r
 8 if largest ≠ i
 9    then exchange A[i] <-> A[largest]
10         MAX-HEAPIFY(A, largest) 

下图是把4调整到最底层,一趟操作。

堆排序_第1张图片

 由上图,我们很容易看出,初始构造出一最大堆之后,在元素A[i],即16,大于它的俩个子结点4、10,满足最大堆性质。所以,i下调指向着4,小于,左子14,所以,调用MAX-HEAPIFY,4与其子,14交换位置。但4处在了14原来的位置之后,4小于其右子8,又违反了最大堆的性质,所以再递归调用MAX-HEAPIFY,将4与8,交换位置。于是,满足了最大堆性质,程序结束。

二、建堆

  建堆可以使用MAX-HEAPIFY程序自底向上地来将一个数组A[1,...,n]变成一个大根堆。过程BUIDL-MAX-HEAP是对树中的每一个非叶子节点调用一次MAX-HEAPIFY。因为二叉堆是一颗完全二叉树,所以它的叶子节点索引是:A[(round(n/2)+1,... ..., n)]

BUILD-MAX-HEAP(A)
1  heap-size[A] ← length[A]
2  for i ← |_length[A]/2_| downto 1
3       do MAX-HEAPIFY(A, i)   

下图是堆的构造过程,首先把数组初始化为一颗完全二叉树,然后调整树的性质。如图:

堆排序_第2张图片

 

三、堆排序算法

    堆排序算法是利用堆的性质,首先交换根节点和最后一个叶子节点的值,然后减小堆的大小,这样就挑选出来数组中最大的一个元素,然后迭代这个过程。

HEAPSORT(A)   
BUILD-MAX-HEAP(A)  
2 for i ← length[A] downto 2
3    do exchange A[1] <-> A[i]
4       heap-size[A] ← heap-size[A] - 1
5       MAX-HEAPIFY(A, 1) 

 n-1次调用MAX-HEAPIFY,所以,O(n*lgn)


堆排序算法的演示过程(通过,顶端最大的元素与最后一个元素不断的交换,交换后又不断的调用MAX-HEAPIFY重新维持最大堆的性质,最后,一个一个的,从大到小的,把堆中的所有元素都清理掉,也就形成了一个有序的序列。这就是堆排序的全部过程。)

堆排序_第3张图片

四、下面列出堆排序的java代码:

 

package heapSort;

import java.util.Arrays;

public class HeapSort {
    
    public HeapSort(){};
    private static int heap_size;
    
    
    public int LEFT(int i){
        return 2*i+1;
    }
    
    public int RIGHT(int i){
        return 2*i+2;
    }
    
    public int PARENT(int i){
        return (i-1)/2;
    }
    
    public void exchange(int[] A, int i, int j){
        
        int temp = A[i];
        A[i]=A[j];
        A[j]=temp;
    }
    public void MAX_HEAPIFY(int[] A, int i){
        int l= LEFT(i);
        int r= RIGHT(i);
        int largest;
        
        if(l< heap_size && A[l]>A[i])
            largest = l;
        else
            largest = i;
                
        if(r < heap_size && A[r]>A[largest])
            largest=r;
        
        if(largest != i){
            exchange(A, i, largest);            
            MAX_HEAPIFY(A, largest);
        }
    
                
    }
    
    public void BUILD_MAX_HEAP(int[] A){
        heap_size=A.length;
        for(int i = (A.length-1)/2; i>= 0; i--){
            MAX_HEAPIFY(A, i);            
        }
    }
    
    public void HEAPSORT(int[] A){
        BUILD_MAX_HEAP(A);
        System.out.println(Arrays.toString(A));
        for(int i = A.length-1; i>=0; i--){
            exchange(A, 0, i);
            
            heap_size= heap_size-1;
            if(heap_size>1){
                MAX_HEAPIFY(A,0);
            }
//            System.out.println(i);
//            System.out.println(Arrays.toString(A));
        }
        
        System.out.println(Arrays.toString(A));
    }
    
    public int HEAP_MAXIMUM(int[] A){
        return A[0];
    }
    

    
    public static void main(String[] args){
        int A[]= new int[]{4,1,3,2,16,9,10,14,8,7};
        HeapSort arr = new HeapSort();        
        arr.HEAPSORT(A);
        
    }

}

 

 

你可能感兴趣的:(堆排序)