堆排序實現(java實現)

首先我們要明確一下堆排序的概念,堆排序就是利用大根堆和小根堆來實現的一種排序方法。

那麼什麼是堆呢?堆(heap)也被稱爲優先隊列(priority queue)。隊列中允許的操作是先進先出(FIFO),在隊尾插入元素,在隊頭取出元素。而堆也是一樣,在堆底插入元素,在堆頂取出元素,但是堆中元素的排列不是按照到來的先後順序,而是按照一定的優先順序排列的。這個優先順序可以是元素的大小或者其他規則。如圖一所示就是一個堆,堆優先順序就是大的元素排在前面,小的元素排在後面,這樣得到的堆稱爲大根堆。大根堆中堆頂的元素是整個堆中最大的,並且每一個分支也可以看成一個大根堆。同樣的,我們可以定義小根堆,如圖二所示。

圖片和描述來自:https://blog.csdn.net/juanqinyang/article/details/51418629

而我們可以在數組中實現這種結構,我們這樣定義數在數組中的位置:(其中i是數的索引)

父節點的位置:(i-1)/2

左子節點的位置:2*i+1

右子節點的位置:2*i+2

於是上面的大根堆我們可以用數組表示爲:{12,8,10,6,4,7,9}

那麼在明白了堆的概念之後我們可以構建一個大根堆,按照概念:用插入的方式構建一個大根堆,把當前要插入的節點與之的父節點進行比較,如果比父節點大的話就和父節點進行交換,直到父節點大於當前節點或者當前節點就是根節點

private void insertMaxHeap(int[] nums) {
        for (int i = 0;i < nums.length;i++) {
            //把當前要插入的節點與之的父節點進行比較,如果比父節點大的話就與之進行交換,直到父節點大於當前節點或者到達頂點
            int parent = (i-1) >> 1;
            while (parent >= 0 && nums[i] > nums[parent]) {
                swap(nums,i,parent);
                i = parent;
                parent = (i-1) >> 1;
            }
        }
    }

構建完成之後,假設我們得到:{12,8,10,6,4,7,9}這樣的一個大根堆,這個時候我們如何完成排序呢,現在我們知道大根堆中的最大值一定是位於堆頂的元素,也就是"12",我們此時把12和9交換位置,讓12變成數組中的最後一位,並且永遠不動它的位置,那麼我們就完成了第一次“排序”,之後我們再利用{9,8,10,6,4,7}重新構建一個“大根堆”,那麼又可以找出位於堆頂的“10",再把10放到數組中12的前一位並保持它的位置不變即可。

 

1.構建一個大根堆

2.把堆頂的元素放到最後,並保持其永遠不變位置

3.用剩下的元素繼續構建大根堆

4.重複上面的操作直到數組完成排序

附上java代碼實現如下:

package com.company;

public class SortClass {
    //堆排序
    public void heapSort(int[] nums) {
        //首先要建立一個大根堆或者小根堆
        int length = nums.length;
        insertMaxHeap(nums);
        //每次將最大或者最小的值固定,然後將剩下的元素重新構建堆,再去選出最大或者最小的元素
        while (length > 1) {
            //把現在位於堆頂的元素固定到尾部
            swap(nums,0,length-1);
            length--;
            //繼續構建
            buildHeap(nums,0,length);
        }
    }
    private void swap(int[] nums,int x,int y) {
        int temp = nums[x];
        nums[x] = nums[y];
        nums[y] = temp;
    }
    private void buildHeap(int[] nums,int i,int length) {
        如果目前的結構已經基本上是一個大根堆或者小根堆了,只有剛替換的這個堆頂元素的位置不正確,則沒必要重新構建整個結構了,直接每次和兩個子節點中較大的交換位置即可
        int l = (i << 1) + 1;
        int r = (i << 1) + 2;
        while (l < length) {
            int maxIndex = i;
            if (nums[maxIndex] < nums[l]) {
                maxIndex = l;
            }
            if (nums[maxIndex] < nums[r] && r < length) {//注意確保右節點也在置換的範圍內
                maxIndex = r;
            }
            //如果父節點已經是最大的了,直接返回即可
            if (maxIndex == i) {
                return;
            }
            swap(nums,maxIndex,i);
            i = maxIndex;
            l = (i << 1) + 1;
            r = (i << 1) + 2;
        }
    }
    private void insertMaxHeap(int[] nums) {
        for (int i = 0;i < nums.length;i++) {
            //把當前要插入的節點與之的父節點進行比較,如果比父節點大的話就與之進行交換,直到父節點大於當前節點或者到達頂點
            int parent = (i-1) >> 1;
            while (parent >= 0 && nums[i] > nums[parent]) {
                swap(nums,i,parent);
                i = parent;
                parent = (i-1) >> 1;
            }
        }
    }
}
發佈了11 篇原創文章 · 獲贊 11 · 訪問量 7120
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章