程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> [C++]排序模板(含C++模板代碼)

[C++]排序模板(含C++模板代碼)

編輯:關於C++

排序模板

一、插入排序

特點:stable sort、In-place sort 最優復雜度:當輸入數組就是排好序的時候,復雜度為O(n),而快速排序在這種情況下會產生O(n^2)的復雜度。 最差復雜度:當輸入數組為倒序時,復雜度為O(n^2) 插入排序比較適合用於“少量元素的數組”。

偽代碼:

image

C++模板:

template 
void Insertion_Sort(T *array, size_t length) {
    if (length <= 1) {
        return;
    } else {
        for (int i = 1; i != length; i++) {
            int j = i - 1;
            T key = array[i];
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key;
        }
    }
}

證明算法正確性:

循環不變式:在每次循環開始前,A[1…i-1]包含了原來的A[1…i-1]的元素,並且已排序。

初始:i=2,A[1…1]已排序,成立。

保持:在迭代開始前,A[1…i-1]已排序,而循環體的目的是將A[i]插入A[1…i-1]中,使得A[1…i]排序,因此在下一輪迭代開 始前,i++,因此現在A[1…i-1]排好序了,因此保持循環不變式。

終止:最後i=n+1,並且A[1…n]已排序,而A[1…n]就是整個數組,因此證畢。

二、冒泡排序

特點:stable sort、In-place sort 思想:通過兩兩交換,像水中的泡泡一樣,小的先冒出來,大的後冒出來。 最壞運行時間:O(n^2) 最佳運行時間:O(n^2)(當然,也可以進行改進使得最佳運行時間為O(n))

偽代碼:

image

C++模板:

template 
void Bubble_Sort(T *array, size_t length) {
    for (int i = 0; i != length - 1; i++) {
        for (int j = 0; j + i != length - 1; j++) {
            if (array[j] > array[j + 1]) {
                T temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
}

證明算法正確性:

運用兩次循環不變式,先證明第4-6行的內循環,再證明外循環。

內循環不變式:在每次循環開始前,A[j]是A[j…n]中最小的元素。

初始:j=n,因此A[n]是A[n…n]的最小元素。
保持:當循環開始時,已知A[j]是A[j…n]的最小元素,將A[j]與A[j-1]比較,並將較小者放在j-1位置,因此能夠說明A[j-1]是A[j-1…n]的最小元素,因此循環不變式保持。
終止:j=i,已知A[i]是A[i…n]中最小的元素,證畢。

接下來證明外循環不變式:在每次循環之前,A[1…i-1]包含了A中最小的i-1個元素,且已排序:A[1]<=A[2]<=…<=A[i-1]。

初始:i=1,因此A[1..0]=空,因此成立。
保持:當循環開始時,已知A[1…i-1]是A中最小的i-1個元素,且A[1]<=A[2]<=…<=A[i-1],根據內循環不變式,終止時A[i]是A[i…n]中最小的元素,因此A[1…i]包含了A中最小的i個元素,且A[1]<=A[2]<=…<=A[i-1]<=A[i]
終止:i=n+1,已知A[1…n]是A中最小的n個元素,且A[1]<=A[2]<=…<=A[n],得證。

在算法導論思考題2-2中又問了”冒泡排序和插入排序哪個更快“呢?

一般的人回答:“差不多吧,因為漸近時間都是O(n^2)”。
但是事實上不是這樣的,插入排序的速度直接是逆序對的個數,而冒泡排序中執行“交換“的次數是逆序對的個數,因此冒泡排序執行的時間至少是逆序對的個數,因此插入排序的執行時間至少比冒泡排序快

三、選擇排序

特性:In-place sort,unstable sort。 思想:每次找一個最小值。 最好情況時間:O(n^2)。 最壞情況時間:O(n^2)。

偽代碼:

image

C++模板:

template 
void Selection_Sort(T *array, size_t length) {
    for (int i = 0; i != length; i++) {
        int min = i;
        for (int j = i + 1; j != length; j++) {
            if (array[min] > array[j]) {
                min = j;
            }
        }
        T temp = array[i];
        array[i] = array[min];
        array[min] = temp;
    }
}

證明算法正確性:

循環不變式:A[1…i-1]包含了A中最小的i-1個元素,且已排序。

初始:i=1,A[1…0]=空,因此成立。
保持:在某次迭代開始之前,保持循環不變式,即A[1…i-1]包含了A中最小的i-1個元素,且已排序,則進入循環體後,程序從 A[i…n]中找出最小值放在A[i]處,因此A[1…i]包含了A中最小的i個元素,且已排序,而i++,因此下一次循環之前,保持 循環不變式:A[1..i-1]包含了A中最小的i-1個元素,且已排序。
終止:i=n,已知A[1…n-1]包含了A中最小的i-1個元素,且已排序,因此A[n]中的元素是最大的,因此A[1…n]已排序,證畢。

四、歸並排序

特點:stable sort、Out-place sort 思想:運用分治法思想解決排序問題。 最壞情況運行時間:O(nlgn) 最佳運行時間:O(nlgn)

分治法介紹:分治法就是將原問題分解為多個獨立的子問題,且這些子問題的形式和原問題相似,只是規模上減少了,求解完子問題後合並結果構成原問題的解。
分治法通常有3步:Divide(分解子問題的步驟) 、 Conquer(遞歸解決子問題的步驟)、 Combine(子問題解求出來後合並成原問題解的步驟)。
假設Divide需要f(n)時間,Conquer分解為b個子問題,且子問題大小為a,Combine需要g(n)時間,則遞歸式為:
T(n)=bT(n/a)+f(n)+g(n)

算法導論思考題4-3(參數傳遞)能夠很好的考察對於分治法的理解。

就如歸並排序,Divide的步驟為m=(p+q)/2,因此為O(1),Combine步驟為merge()函數,Conquer步驟為分解為2個子問題,子問題大小為n/2,因此:
歸並排序的遞歸式:T(n)=2T(n/2)+O(n)

而求解遞歸式的三種方法有:

(1)替換法:主要用於驗證遞歸式的復雜度。 (2)遞歸樹:能夠大致估算遞歸式的復雜度,估算完後可以用替換法驗證。 (3)主定理:用於解一些常見的遞歸式。

偽代碼:

image

C++模板:

template 
void Merge(T *sourceArray, T *temp, int Start_Index, int Mid_Index, int End_Index) {
    int i = Start_Index, j = Mid_Index + 1, k = Start_Index;
    while (i != Mid_Index + 1 && j != End_Index + 1) {
        if (sourceArray[i] > sourceArray[j]) {
            temp[k++] = sourceArray[j++];
        } else {
            temp[k++] = sourceArray[i++];
        }
    }
    while (i != Mid_Index + 1) {
        temp[k++] = sourceArray[i++];
    }
    while (j != End_Index + 1) {
        temp[k++] = sourceArray[j++];
    }
    for (int i = Start_Index; i != End_Index + 1; i++) {
        sourceArray[i] = temp[i];
    }
}

template 
void Merge_Sort(T *sourceArray, T *temp, int Start_Index, int End_Index) {
    if (Start_Index < End_Index) {
        int Mid_Index = (Start_Index + End_Index) / 2;
        Merge_Sort(sourceArray, temp, Start_Index, Mid_Index);
        Merge_Sort(sourceArray, temp, Mid_Index + 1, End_Index);
        Merge(sourceArray, temp, Start_Index, Mid_Index, End_Index);
    }
}

C++ 鏈表的歸並排序法:

// 鏈表的歸並排序。
void LinkedList::sort(void) {
    if (this->size() > 1) {
        node* fast = this->head;
        node* slow = this->head;
        LinkedList li_left;
        LinkedList li_right;

        li_left.head = this->head;
        while (fast != NULL && fast->next != NULL) {
            li_left._size++;
            fast = fast->next->next;
            slow = slow->next;
        }
        li_left.tail = slow->prev;
        li_left.tail->next = NULL;

        li_right.head = slow;
        li_right.head->prev = NULL;
        li_right.tail = this->tail;
        li_right._size = this->_size - li_left._size;

        this->head = NULL;
        this->tail = NULL;

        li_left.sort();
        li_right.sort();

        node* pointer_left = li_left.head;
        node* pointer_right = li_right.head;

        node* pointer_head = NULL;
        node* pointer_tail = NULL;

        while (pointer_left != NULL && pointer_right != NULL) {
            node* temp;
            if (pointer_left->data <= pointer_right->data) {
                temp = pointer_left;
                pointer_left = pointer_left->next;
            } else {
                temp = pointer_right;
                pointer_right = pointer_right->next;
            }
            if (pointer_head == NULL) {
                pointer_head = pointer_tail = temp;
            } else {
                pointer_tail->next = temp;
                temp->prev = pointer_tail;
                pointer_tail = temp;
            }
            pointer_head->prev = NULL;
            pointer_tail->next = NULL;
        }

        while (pointer_left != NULL) {
            pointer_tail->next = pointer_left;
            pointer_left->prev = pointer_tail;
            pointer_tail = pointer_left;
            pointer_left = pointer_left->next;
        }

        while (pointer_right != NULL) {
            pointer_tail->next = pointer_right;
            pointer_right->prev = pointer_tail;
            pointer_tail = pointer_right;
            pointer_right = pointer_right->next;
        }

        this->head = pointer_head;
        this->tail = pointer_tail;

        li_left.head = li_left.tail = NULL;
        li_right.head = li_right.tail = NULL;
}

舉例說明:

image

問:歸並排序的缺點是什麼?<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPrTwo7rL+8rHT3V0LXBsYWNlIHNvcnSjrNLytMvP4LHIv+zFxaOs0OjSqrrctuC27s3itcS/1bzkoaM8L3A+DQo8cD7OyqO6zqrKssO0uemyosXF0PKxyL/sy9nFxdDywv2jvzwvcD4NCjxwPrTwo7rL5Mi7vaW9/Li01NO2yNK70fmjrLWryse56bKixcXQ8rXEz7XK/bHIv+zFxbTzoaM8L3A+DQo8cD7OyqO6ttTT2rnpsqLFxdDy09DKssO0uMS9+KO/PC9wPg0KPHA+tPCjur7NysfU2sr91+mzpLbIzqpryrGjrNPDsuXI68XF0PKjrNLyzqqy5cjrxcXQ8srKus+21NChyv3X6cXF0PKho9Tay+O3qLW8wtvLvL+8zOIyLTHW0L3pydzBy6GjuLTU07bIzqpPKG5rK25sZyhuL2spKSCjrLWxaz1PKGxnbinKsaOsuLTU07bIzqpPKG5sZ24pPC9wPg0KPGgzIGlkPQ=="五快速排序">五、快速排序

算法介紹:

設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(通常選用數組的第一個數)作為關鍵數據,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一趟快速排序。值得注意的是,快速排序不是一種穩定的排序算法,也就是說,多個相同的值的相對位置也許會在算法結束時產生變動。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素作為關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j–),找到第一個小於key的值A[j],將A[j]和A[i]互換;
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;
5)重復第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令循環結束)。

QUICK_SORT(A,p,r)
if p

C++模板:

template 
void Quick_Sort(T *array, int Start_Index, int End_Index) {
    if (End_Index >= Start_Index) {
        int first = Start_Index;
        int last = End_Index;
        T key = array[first];
        while (first < last) {
            while (first < last && array[last] >= key) {
                last--;
            }
            array[first] = array[last];
            while (first < last && array[first] <= key) {
                first++;
            }
            array[last] = array[first];
        }
        array[first] = key;
        Quick_Sort(array, Start_Index, first - 1);
        Quick_Sort(array, first + 1, End_Index);
    }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved