排序演算法分析【五】:歸併排序(附Python&C++代碼),演算法分析python
歸併排序:將兩個已經排序的串列合并成一個串列的操作。
演算法原理
先看動態圖:
演算法描述如下:
演算法實現Python版:
#-*- encoding: utf-8 -*- def merge_sort(list_one, list_two): # 歸併排序 list_merge = [] i = 0; j = 0 while i < len(list_one) and j < len(list_two): if list_one[i] <= list_two[j]: list_merge.append(list_one[i]) i += 1 else: list_merge.append(list_two[j]) j += 1 print 'i = {}, j = {}'.format(i, j) print list_merge while i < len(list_one): list_merge.append(list_one[i]) i += 1 while j < len(list_two): list_merge.append(list_two[j]) j += 1 return list_merge list_one = [1, 3, 5, 6, 8, 10, 12, 13]list_two = [2, 4, 7, 9, 11, 14, 15, 16, 17, 18]print merge_sort(list_one, list_two)結果為:
>>> ================================ RESTART ================================>>> i = 1, j = 0[1]i = 1, j = 1[1, 2]i = 2, j = 1[1, 2, 3]i = 2, j = 2[1, 2, 3, 4]i = 3, j = 2[1, 2, 3, 4, 5]i = 4, j = 2[1, 2, 3, 4, 5, 6]i = 4, j = 3[1, 2, 3, 4, 5, 6, 7]i = 5, j = 3[1, 2, 3, 4, 5, 6, 7, 8]i = 5, j = 4[1, 2, 3, 4, 5, 6, 7, 8, 9]i = 6, j = 4[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]i = 6, j = 5[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]i = 7, j = 5[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]i = 8, j = 5[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13][1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]>>>
C++版:
#include <iostream>using namespace std;void print (int st_bf[], size_t size){ for (size_t i = 0; i < size; i++) { cout<< st_bf[i] << " "; } cout<< endl;}void merge_sort(int *list_one, size_t len_list_one, int *list_two, size_t len_list_two){ // 歸併排序 // 申請空間 int list_merge[len_list_one+len_list_two]; size_t i = 0, j = 0, k = 0; // k儲存合并後的長度 for ( ; (i<len_list_one) and (j<len_list_two); ++k){ if (list_one[i] <= list_two[j]){ list_merge[k] = list_one[i++]; } else { list_merge[k] = list_two[j++]; } cout << "i = " << i << ", j = " << j << ", k = " << k << endl; print(list_merge, k+1); } // 以下複製尾部大元素序列 while (i < len_list_one) list_merge[k++] = list_one[i++]; while (j < len_list_two) list_merge[k++] = list_two[j++]; cout << "i = " << i << ", j = " << j << ", k = " << k << endl; print(list_merge, k);}int main(){ int list_one[] = {1, 3, 5, 6, 8, 10, 12, 13}; int list_two[] = {2, 4, 7, 9, 11, 14, 15, 16, 17, 18}; size_t len_list_one = sizeof(list_one)/sizeof(list_one[0]); size_t len_list_two = sizeof(list_two)/sizeof(list_two[0]); merge_sort(list_one, len_list_one, list_two, len_list_two); return 0;}結果同上,不在貼出。
本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原創。還有未涉及的,會不定期更新,有錯誤請指正。
如果你看到這篇博文時發現沒有不完整,那是我為防止爬蟲先發布一半的原因,請看原作者Blog。
如果這篇博文對您有協助,為了好的網路環境,不建議轉載,建議收藏!如果您一定要轉載,請帶上尾碼和本文地址。
插入排序,選擇排序,快速排序,歸併排序的原理都是是什?哪個要記憶體量最大?
baike.baidu.com/view/58783.htm
排序是電腦內經常進行的一種操作,其目的是將一組“無序”的記錄序列調整為“有序”的記錄序列。
內部排序和外部排序:
若整個排序過程不需要訪問外存便能完成,則稱此類排序問題為內部排序;
反之,若參加排序的記錄數量很大,整個序列的排序過程不可能在記憶體中完成,則稱此類排序問題為外部排序。
內部排序的過程是一個逐步擴大記錄的有序序列長度的過程。
內排序的方法有許多種,按所用策略不同,可歸納為五類:插入排序、選擇排序、交換排序、歸併排序和分配排序。
其中,插入排序主要包括直接插入排序和希爾排序兩種;選擇排序主要包括直接選擇排序和堆排序;交換排序主要包括氣(冒)泡排序和快速排序。
一、冒泡排序
已知一組無序資料a[1]、a[2]、……a[n],需將其按升序排列。首先比較a[1]與a[2]的值,若a[1]大於a[2]則交換兩者的值,否則不變。再比較a[2]與a[3]的值,若a[2]大於a[3]則交換兩者的值,否則不變。再比較a[3]與a[4],以此類推,最後比較a[n-1]與a[n]的值。這樣處理一輪後,a[n]的值一定是這組資料中最大的。再對a[1]~a[n-1]以相同方法處理一輪,則a[n-1]的值一定是a[1]~a[n-1]中最大的。再對a[1]~a[n-2]以相同方法處理一輪,以此類推。共處理n-1輪後a[1]、a[2]、……a[n]就以升序排列了。
優點:穩定,比較次數已知;
缺點:慢,每次只能移動相鄰兩個資料,移動資料的次數多。
二、選擇排序
已知一組無序資料a[1]、a[2]、……a[n],需將其按升序排列。首先比較a[1]與a[2]的值,若a[1]大於a[2]則交換兩者的值,否則不變。再比較a[1]與a[3]的值,若a[1]大於a[3]則交換兩者的值,否則不變。再比較a[1]與a[4],以此類推,最後比較a[1]與a[n]的值。這樣處理一輪後,a[1]的值一定是這組資料中最小的。再將a[2]與a[3]~a[n]以相同方法比較一輪,則a[2]的值一定是a[2]~a[n]中最小的。再將a[3]與a[4]~a[n]以相同方法比較一輪,以此類推。共處理n-1輪後a[1]、a[2]、……a[n]就以升序排列了。
優點:穩定,比較次數與冒泡排序一樣;
缺點:相對之下還是慢。
三、插入排序
已知一組升序排列資料a[1]、a[2]、……a[n],一組無序資料b[1]、b[2]、……b[m],需將二者合并成一個升序數列。首先比較b[1]與a[1]的值,若b[1]大於a[1],則跳過,比較b[1]與a[2]的值,若b[1]仍然大於a[2],則繼續跳過,直到b[1]小於a數組中某一資料a[x],則將a[x]~a[n]分別向後移動一位,將b[1]插入到原來a[x]的位置這就完成了b[1]的插入。b[2]~b[m]用相同方法插入。(若無數組a,可將b[1]當作n=1的數組a)
優點:穩定,快;
缺點:比較次數不一定,比較次數越少,插入點後的資料移動越多,特別是當資料總量龐大的時候,但用鏈表可以解決這個問題。
四、縮小增量排序
由希爾在1959年提出,又稱希爾排序(shell排序)。
已知一組無序資料a[1]、a[2]......餘下全文>>
歸併排序演算法
兩種歸併排序演算法的實現:二路歸併排序和基本歸併排序(虛擬消除遞迴的二路歸併排序)
#define ARRAY_SIZE 1024
int B[1024]; //使用一個全域變數,避免歸併排序中每次都重新申請和釋放空間造成的開銷
template <typename T>
void Merge(T A[], int l, int m, int h)
{
int i = l;
int j = m+1;
int k = 0;
while(i<=m&&j<=h)
{
if(A[i]<A[j])
{
B[k++] = A[i];
i++;
}
else
{
B[k++] = A[j];
j++;
}
}
while(i<=m)
{
B[k++] = A[i++];
}
while(j<=h)
{
B[k++] = A[j++];
}
for(i=l; i<=h; i++)
{
A[i] = B[i-l];
}
}
//二路歸併排序的實現
template <typename T>
void MergeSort(T a[], int l, int h)
{
int m = (h+l)/2;
if(l>=h)
{
return;
}
if(l+1==h)
{
if(a[l]>a[h])
{
std::swap(a[l], a[h]);
}
return;
}
MergeSort(a, l, m);
MergeSort(a, m+1, h);
Merge(a, l, m, h);
}
//將a經過步長s歸併到b中,n表示數組的大小
template <typename T>
void Merge2(T a[], T b[], int s, int n)
{
int m = 0;
//從頭至尾按照步長s進行相鄰資料的合并
for(int i=0; i<n; i+=2*s)
{
int j = i; //合并的第一組數的起始位置
int k = i+s; //合并的第二組數的起始位置
int jE = i+s; //合并的第一組數的起始位置
int kE = i+2*s; //合并的第二組數的起始位置
while((j<jE)&&(k<kE)&&j<n && k<n)
{
if(a[j]<a[k])
{
b[m++] = a[j];
......餘下全文>>