堆排序(heapsort)

圖片描述

古巷悠悠歲月深,青石老街印舊痕
今夜小樓聽風雨,不見當年傘下人git

前言

堆排序是排序算法中的一種,算法時間複雜度是O(n log(n))。這裏主要介紹堆的構建以及怎樣經過heapify操做完成堆排序。代碼是用C語言完成的,算法不難,你們能夠本身用其餘語言實現一下。github

什麼是堆(Heap)

Heap須要知足兩個條件:算法

1.Complete Binary Tree :須要是一顆徹底二叉樹
2.Parent > Children:父節點的值必定要大於子節點的值

什麼是徹底二叉樹api

生成節點的順序是從上往下、從左往右依次生成數組

以下圖所示:
圖片描述函數

父節點的值大於子節點的值ui

以下圖所示:
圖片描述spa

怎麼樣用代碼表示堆

1.假設先有這樣一顆徹底二叉樹,它已是一個堆了code

圖片描述

2.1 咱們按照從上往下、從左往右的順序對每一個節點數字進行編號,
2.2 咱們能夠用一個一維數組表示排序

圖片描述

2.3 使用數組的下標來表示一個徹底二叉樹的好處就是從任何一個節點出發我均可以經過計算來拿到這個節點的父節點和子節點

圖片描述

構建堆

1.假設拿到了一堆數字:10 4 3 5 1 2,這些數字放在了一顆徹底二叉樹上面,以下圖所示:

圖片描述

2.heapify:

把徹底二叉樹調整成堆,咱們把這種操做起個名字叫:heapify

1.第一次heapify操做:把4(父節點)、十、3這三個子節點進行比較,找到最大值和父節點進行交換
交換後以下圖:

圖片描述

2.第二次heapify操做,把4(父節點)、五、1這三個子節點進行比較,找到最大值和父節點進行交換
交換後以下圖:

圖片描述

3.這樣咱們就生成了一個堆:知足徹底二叉樹、父節點值大於子節點的值

123步的代碼實現:

void swap(int *tree, int max, int i) {
        int temp = tree[i];
        tree[i] = tree[max];
        tree[max] = temp;
    }
    
    /**
     對一個二叉樹進行heapify操做
    
     @param tree 表示二叉樹的數組
     @param n 二叉樹的節點個數
     @param i 表示要對哪一個節點進行heapify操做
     */
    void heapify(int *tree, int n, int i) {
        if (i >= n) { // 遞歸函數出口
            return;
        }
        // 找到i節點的兩個子節點
        int c1 = i*2 + 1;
        int c2 = i*2 + 2;
        // 找個三個節點的最大值 假設i是最大值
        int max = i;
        if(c1 < n && tree[c1] > tree[max]) { // c1 < n 表示節點下面沒有子節點
            max = c1;
        }
        if (c2 < n && tree[c2] > tree[max]) {
            max = c2;
        }
        if (max != i) { // max != i b若是i已是最大值了就不用交換了
            swap(tree, max, i);
            heapify(tree, n, max);//max節點繼續heapify
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree[] = {4,10,3,5,1,2};
            int n = 6;
            heapify(tree, n, 0);
            
            for (int i = 0; i < n; i++) {
                printf("%d\n", tree[i]);
            }
        }
        return 0;
    }

輸出結果:
圖片描述

4.若是一棵徹底二叉樹的節點的值都是亂序,咱們就能夠從倒數第二層開始往上對每一個節點進行heapify,流程以下:
1.
圖片描述

2.
圖片描述

3.
圖片描述

4.
圖片描述

代碼實現:

void buildHeap(int *tree, int n) {
        int lastNode = n-1;
        int parent = (lastNode-1)/2;
        for (int i = parent; i>=0; i--) {
            heapify(tree, n, i);
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree1[] = {2,5,3,1,10,4};
            int m = 6;
            buildHeap(tree1, m);
            for (int i = 0; i < m; i++) {
                printf("%d\n", tree1[i]);
            }
        }
        return 0;
    }

輸出結果:

圖片描述

畫出樹結構:

圖片描述

堆排序 heapsort

1.假設有一棵樹是堆的結構,因此父節點大於子節點,且根節點是最大的

圖片描述

2.首先第一步,根節點和最後一個節點交換,這樣最大節點就跑到最後一位

圖片描述

3.第二步把最後一位節點砍斷

圖片描述

4.由於剛剛作了第一步的交換,咱們就破壞了堆結構,因此咱們要作heapify,以此類推

代碼實現:

void heapSort (int *tree, int n) {
        buildHeap(tree, n);
        for (int i = n-1; i>=0; i--) {
            swap(tree, i, 0);// 交換更節點和末位節點
            heapify(tree, i, 0); //破壞堆結構後作heapify操做
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree[] = {2,5,3,1,10,4};
            int m = 6;
            heapSort(tree, m);
            for (int i = 0; i < m; i++) {
                printf("%d\n", tree[i]);
            }
        }
        return 0;
    }

輸出結構:

圖片描述

源碼地址

連接描述

相關文章
相關標籤/搜索