十四、数据机构---堆排序

来源:互联网 发布:ubuntu 14.04上安装qq 编辑:程序博客网 时间:2024/05/22 06:52
   1、堆是一种重要的数据结构,为一棵完全二叉树,
    底层一般用数组存储数据。假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。
    其任何一非叶结点满足性质:
    Key[i]<=Key[2i+1]&&Key[i]<=Key[2i+2]
    或者
    Key[i]>=Key[2i+1]&&Key[i]>=Key[2i+2]
    即任何一非叶结点的关键字不大于或者不小于其左右孩子结点的关键字。
    堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&Key[i]>=Key[2i+2]称为大顶堆,满足Key[i]<=Key[2i+1]&&Key[i]<=Key[2i+2]称为小顶堆。有上述性质可知大顶堆的顶堆的关键字肯定是所有关键字中最大的,小顶堆的顶堆关键字是所有关键字中最小的。


    
 2、所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小),且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。


    堆排序的大致步骤如下:
        1.将初始待排序关键字序列(R[0],R[1]...R[n-1])构建成大顶堆,此堆为初始的无序区;
        2.将堆顶元素R[0]与最后一个元素R[n-1]交换,此时得到新的无序区(R[0],R[1]...R[n-2])和新的有序区(R[n-1]),且满足R[0,1...n-2]<=R[n-1];
        3.由于交换后新的堆顶R[0]可能违反堆的性质,因此需要对当前无序区(R[0],R[1]...R[n-2])调整为新堆,然后再次将R[0],与无序区最后一个元素交换,新的无序区(R[0],R[1]...R[n-3])和新的有序区(R[n-2],R[n-1]).不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。


        由于步骤2的交换可能破坏了最大对的性质,第0不再是最大元素,需要调用maxHeap调整堆(沉降法),如果需要重复步骤2
    堆排序最重要的算法就是maxHeap,该函数假设一个元素的两个子节点都满足最大堆的性质(左右子树都是最大堆),只有跟元素可能违反最大堆性质,那么把该元素以及左右结点的最大元素找出来,如果该元素已经最大,那么整棵树都是最大堆,程序退出,否则交换跟元素与最大元素的位置,继续调用maxHeap原最大元素所在的子树。

相关代码:

public class ArrayUtils {
public static void printArray(int[] array) {  
        System.out.print("{");  
        for (int i = 0; i < array.length; i++) {  
            System.out.print(array[i]);  
            if (i < array.length - 1) {  
                System.out.print(", ");  
            }  
        }  
        System.out.println("}");  
    }  


    public static void exchangeElements(int[] array, int index1, int index2) {  
        int temp = array[index1];  
        array[index1] = array[index2];  
        array[index2] = temp;  
    }  
}

public class HeapSort {
public static void main(String[] args) {  
        int[] array = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3 };  


        System.out.println("Before heap:");  
        ArrayUtils.printArray(array);  


        heapSort(array);  


        System.out.println("After heap sort:");  
        ArrayUtils.printArray(array);  
    }  


    public static void heapSort(int[] array) {  
        if (array == null || array.length <= 1) {  
            return;  
        }  


        buildMaxHeap(array);  


        for (int i = array.length - 1; i >= 1; i--) {  
            ArrayUtils.exchangeElements(array, 0, i);  


            maxHeap(array, i, 0);  
        }  
    }  


    private static void buildMaxHeap(int[] array) {  
        if (array == null || array.length <= 1) {  
            return;  
        }  


        int half = array.length / 2;  
        for (int i = half; i >= 0; i--) {  
            maxHeap(array, array.length, i);  
        }  
    }  


    private static void maxHeap(int[] array, int heapSize, int index) {  
        int left = index * 2 + 1;  
        int right = index * 2 + 2;  


        int largest = index;  
        if (left < heapSize && array[left] > array[index]) {  
            largest = left;  
        }  


        if (right < heapSize && array[right] > array[largest]) {  
            largest = right;  
        }  


        if (index != largest) {  
            ArrayUtils.exchangeElements(array, index, largest);  


            maxHeap(array, heapSize, largest);  
        }  
    }   
}