排序之堆排序

  • 排序是將一串數據按照其某個或者某些關鍵字的大小進行遞增或遞減排列的操做我,一般指的排序是升序,排序方式是原地排序
  • 下面介紹下堆排序

堆排序

  • 原理:
    • 堆排序也是選擇出無序區間的最大值/最小值,將其放在無序區間的後面
    • 可是是經過遍歷獲取最大值/最小值,是經過建堆的方式來獲取無序區間中的最大值/最小值
    • 將堆頂元素和最後一個元素交換,而後對無序區間進行向下調整
    • 重複交換直至排序結束
  • 排升序須要建大堆
  • 排降序須要建小堆
  • 插入排序是一個不穩定的排序

實現方式

1.排升序,建大堆api

public static void heapSort(int[] array) {
                //將數組建成大堆
                heapify(array);
                for(int i = 0; i < array.length - 1; i++) {
                        //交換前
                        //無序區間[0, array.length - i);
                        //有序區間[array.length - i, array.length);

                        swap(array, 0, array.length - 1 - i);

                        //交換後
                        //無序區間[0, array.length - i - 1)
                        //有序區間[array.length - i - 1, array.length)
                        //無序區間的長度 array.length - i - 1
                        siftDown(array, array.length - i - 1, 0);
                }
        }

        private static void swap(int[] array, int i, int j) {
                int tmp = array[i];
                array[i] = array[j];
                array[j] = tmp;
        }

        private static void heapify(int[] array) {
                //array.length - 1 是堆的最後一個結點的下標,
                //則最後一個非葉子結點的下標就是 (array.length - 1 - 1) >>> 1
                for(int i = (array.length - 1 - 1) >>> 1; i >= 0; i--) {
                        siftDown(array, array.length, i);
                }
        }

        private static void siftDown(int[] array, int length, int index) {
                int left = (index << 1) + 1;

                while(left < length) {
                        int right = (index << 1) + 2;
                        int max = left;

                        //右結點存在且值比左節點的值大時,值最大的結點纔是右結點
                        if(right < length && array[right] > array[max]) {
                                max = right;
                        }

                        //若是須要調整的結點的值比子結點中值最大的結點的值都大時,向下調整結束
                        if(array[index] >= array[max]) {
                                break;
                        }

                        swap(array, index, max);

                        index = max;
                        left = (index << 1) + 1;
                }
        }

2.排降序,建小堆數組

public static void heapSort(int[] array) {
                //將數組建成小堆
                heapify(array);
                for(int i = 0; i < array.length - 1; i++) {
                        //交換前
                        //無序區間[0, array.length - i);
                        //有序區間[array.length - i, array.length);

                        swap(array, 0, array.length - 1 - i);

                        //交換後
                        //無序區間[0, array.length - i - 1)
                        //有序區間[array.length - i - 1, array.length)
                        //無序區間的長度 array.length - i - 1
                        siftDown(array, array.length - i - 1, 0);
                }
        }

        private static void swap(int[] array, int i, int j) {
                int tmp = array[i];
                array[i] = array[j];
                array[j] = tmp;
        }

        private static void heapify(int[] array) {
                //array.length - 1 是堆的最後一個結點的下標,
                //則最後一個非葉子結點的下標就是 (array.length - 1 - 1) >>> 1
                for(int i = (array.length - 1 - 1) >>> 1; i >= 0; i--) {
                        siftDown(array, array.length, i);
                }
        }

        private static void siftDown(int[] array, int length, int index) {
                int left = (index << 1) + 1;

                while(left < length) {
                        int right = (index << 1) + 2;
                        int min = left;

                        if(right < length && array[right] < array[min]) {
                                min = right;
                        }

                        if(array[index] <= array[min]) {
                                break;
                        }

                        swap(array, index, min);

                        index = min;
                        left = (index << 1) + 1;
                }
        }

性能分析

  • 時間複雜度:O(N*logN)
  • 空間複雜度:O(1)
  • 穩定性:不穩定
相關文章
相關標籤/搜索