實現堆排、快排、歸並


春招的時候已經總結過這三個復雜的排序算法了,但是,當時還是有些不解,關於排序算法,冒泡,直接插入,簡單選擇都是很簡單的,只要了解思想就可以寫出來。

這三個算是比較復雜的了。(代碼已測)


 

(一)快排

快排考的是最多次的。之前看大神寫的算法很簡單,思想也很好。就一直用他的思想去思考快排了。

就是挖坑法。

拿走第一個元素作為標兵元素,即挖坑,然后從后面找一個比它小的填坑,然后又形成一個坑,再從前面找一個比標兵大的填坑,又形成一個坑。……最后一個坑填入標兵就好。

然后就是遞歸了。再在標兵左邊排序,右邊排序。

void QSort(int* num, int start, int end) {
    if(num == NULL||start >= end)
        return;
    int tmp = num[start];
    int i = start, j = end;
    while (i<j) {
        while (i<j&&num[j]>tmp) {
            j--;
        }
        if (i<j)
            num[i++] = num[j];
        while (i<j&&num[i]<tmp) {
            i++;
        }
        if (i<j)
            num[j--] = num[i];
    }
    num[i] = tmp;
    QSort(num, start, i - 1);
    QSort(num, i + 1, end);
}

歸並:

歸並的思想就是分治-組合。

先divide,然后merge。

divide的思想比較簡單,找到middle,再划分A[start,,,,,middle],A[middle+1...end]

對於左邊在遞歸划分,划分直至只剩一個元素,然后再merge。merge的時候需要一個臨時數組。merge的時候是A[first...middle]和A[middle+1……end]合並。

對於右邊在遞歸划分,划分直至只剩一個元素,然后再merge。

左邊和右邊都有序了,然后再將兩個數組合並為一個數組。最后整個數組都有序了。(先處理左邊,再處理右邊)

void merge(int* A, int start, int middle, int last, int *tmp) {

    int i1 = start, j1 = middle;
    int i2 = middle+1, j2 = last;
    int index = 0;
    while (i1<=j1&&i2<=j2) {
        if (A[i1]<=A[i2])
            tmp[index++] = A[i1++];
        else tmp[index++] = A[i2++];
    }
    while (i1 <= j1) {
        tmp[index++] = A[i1++];
    }
    while (i2 <= j2) {
        tmp[index++] = A[i2++];
    }
    for (int i = 0; i<index; i++) {
        A[start + i] = tmp[i];
    }
    return;
}
void divide(int* A, int start, int end, int* tmp) {
    if (start<end) {
        int middle = (start + end) / 2;
        divide(A, start, middle, tmp);
        divide(A, middle+1, end, tmp);
        merge(A, start, middle, end, tmp);
    }
}
void mergesort(int* A, int size) {
    if (A == NULL || size == 0 || size == 1)
        return;
    int* tmp = new int[size];
    divide(A, 0, size - 1, tmp);
    delete[] tmp;
    return;
}

 


堆排序:(我覺得好難啊)

堆排序(以最大堆為例子):
1.首先要構建一個最大堆(從size/2-1位置開始維護堆,葉子節點默認已經是一個最大堆了,維護到根節點,則已經構成一個最大堆)
2.交換根節點(此時根節點是最大值),和最后一個節點,破壞了最大堆的性質,此時繼續維護最大堆(維護最大堆的過程就是類似直接插入排序,找到維護點合適插入的位置,保證最大堆性質不被破壞就好)
3.循環交換最后一個節點和根節點,每次維護最大堆的規模減一(找到最大,找到次大,次次大……),到最后到根節點,也就排序完成了

 

void swap(int& a, int& b) {
    a ^= b;
    b ^= a;
    a ^= b;
}
void HeapAdjust(int* A, int size, int start) {
    int i = start;
    int j = 2 * i + 1;
    int tmp = A[i];
    while (j <= size) {
        if (j + 1 <= size&&A[j + 1]>A[j])
            j++;
        if (A[j] <= tmp)
            break;
        A[i] = A[j];
        i = j;
        j = 2 * i + 1;
    }
    A[i] = tmp;
    return;
}

void CreateHeap(int* A, int size) {
    for (int i = size / 2 - 1; i >= 0; i--)
        HeapAdjust(A, size - 1, i);
}

void HeapSort(int* A, int size) {
    if (A == NULL || size == 0 || size == 1)
        return;
    CreateHeap(A, size);
    for (int i = size - 1; i >= 1;) {
        swap(A[0], A[i--]);
        HeapAdjust(A, i, 0);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM