都說貪小便宜吃大虧,但吃虧是福,那不就是貪小便宜吃大福了嗎
一、并歸排序 MergeSort
1.基本思想
2.實現(xiàn)原理
3.代碼實現(xiàn)
4.歸并排序的特性總結(jié)
二、非遞歸并歸排序?qū)崿F(xiàn)
三、完結(jié)撒?
–?–?–?–?–?–?–?–?–?–?–?–?–?–?–?-正文開始-?–?–?–?–?–?–?–?–?–?–?–?–?–?–?–
一、并歸排序 MergeSort
1.基本思想
歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。歸并排序核心步驟:
2.實現(xiàn)原理
其實先還是運用了遞歸大事化小的原理,假設(shè)我們要對數(shù)組arr[i]進行排序,我們可以將該數(shù)組均分為兩個數(shù)組(從中間劃分)arr[0] ~ arr[i/2],arr[i/2+1] ~ arr[i],要使arr數(shù)組有序可以先將arr[0] ~ arr[i/2]和arr[i/2+1] ~ arr[i]有序,而arr[0] ~ arr[i/2]和arr[i/2+1] ~ arr[i]有序之后可以從頭到尾比較兩個數(shù)組范圍內(nèi)的每一個值,按照要求所排的順序往新開辟的另一個數(shù)組tmp中拷貝,最后再從tmp數(shù)組中拷貝到arr數(shù)組中完成排序,這就是歸并過程。
而要想arr[0] ~ arr[i/2]和arr[i/2+1] ~ arr[i]有序,可以先讓arr[0] ~ arr[i/4]和arr[i/4+1]~arr[i/2]有序,arr[i/2+1] ~ arr[mini](中間位置)和arr[mini+1] ~ arr[i]有序,而arr[0] ~ arr[i/4]有序就需要…
這樣就可以用遞歸來實現(xiàn),數(shù)組一直向下遞歸“分割”,當(dāng)數(shù)組被分為一個數(shù)據(jù)的時候就可以返回進行合并
所以把并軌排序遞歸實現(xiàn)按照二叉樹來看,完成排序的核心要求就是遞歸“分割”后,要實現(xiàn)上層數(shù)組有序就先要實先下層數(shù)組也為有序,完成最后一層數(shù)據(jù)有序向上回溯即可完成整個數(shù)組有序
返回合并過程動態(tài)圖解:
3.代碼實現(xiàn)
void _MergeSort(int* a, int begin, int end, int* tmp)
{
if (begin == end)
{
return;
}
int min = (end + begin) / 2;
_MergeSort(a, begin, min, tmp);
_MergeSort(a, min+1, end, tmp);
//并歸
int begin1 = begin, end1 = min;
int begin2 = min + 1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
memcpy(a+begin, tmp+begin, sizeof(int)*(end - begin + 1));//注意
}
//并歸排序 O(N*logN)
void MergeSort(int* a, int n)
{
assert(a);
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
tmp = NULL;
}
4.歸并排序的特性總結(jié)
1. 歸并的缺點在于需要O(N)的空間復(fù)雜度,歸并排序的思考更多的是解決在磁盤中的外排序問題。
2. 時間復(fù)雜度:O(N*logN)
3. 空間復(fù)雜度:O(N)
4. 穩(wěn)定性:穩(wěn)定
二、非遞歸并歸排序?qū)崿F(xiàn)
對于歸并的非遞歸實現(xiàn)我們直接利用循環(huán)就可以解決。
我們可以將要并歸排序的數(shù)組直接看成1個數(shù)據(jù)為一組往下進行并歸,并歸后再兩個數(shù)據(jù)為一組往下進行并歸,直到將數(shù)組并歸完成為止,見下圖:
此過程與遞歸過程中的回溯過程一樣,只是不再需要進行遞歸分解
這個看起來容易,但實現(xiàn)起來并不簡單,我們需要注意許多細節(jié)在這里
如何通過一次循環(huán)來完成一層數(shù)據(jù)的并歸呢?
以第一層一個數(shù)據(jù)為一組為例,我們先要完成對數(shù)據(jù)的控制,開始我們就先要控制10,6一起進行并歸,而后再控制7,1進行并歸,直到第一層結(jié)束為止
完成上述代碼實現(xiàn)之后,我們只需在上述代碼外再套一層循環(huán)來控制gap,即可實現(xiàn)整個代碼邏輯
但需要注意的是并不是所有數(shù)據(jù)最終都會“組隊成雙”實現(xiàn)歸并,如下:
上面數(shù)組中最后一組便是一個例子
我們把每次組隊并歸的兩組中,第一組的隊頭為begin1,隊尾為end1,第二組的隊頭為begin2,隊尾為end2
因為begin1不可能越界,那么出現(xiàn)上面問題一共有三種情況:
1.end1越界
當(dāng)end1越界的話,那么表示這次組隊肯定是沒有第二組,并且第一組也部分越界,而第一組如果是一個數(shù)據(jù)的好不用進行并歸排序,如果超過一個數(shù)據(jù)說明在之前已經(jīng)并歸排序完畢,數(shù)據(jù)也是有序的,所以也不再需要進行并歸排序。end1越界直接跳出循環(huán)不進行并歸排序即可。
2.begin2越界
當(dāng)begin2越界,情況其實與end1越界一樣,不同的可能就是第一組數(shù)據(jù)都沒有越界,沒有第二組數(shù)據(jù),這時也不需要進行并歸排序,直接跳出循環(huán)即可。
3.end2越界
當(dāng)end2越界,表明有第一組數(shù)據(jù),第二組數(shù)據(jù)越界,此時只要將第二組數(shù)據(jù)的范圍縮小到原數(shù)組的隊尾即可,也就是end2 = n - 1,然后再將兩組數(shù)據(jù)進行并歸排序即可(并歸排序的實現(xiàn)只要求所給的兩組數(shù)據(jù)有序,不要求數(shù)據(jù)數(shù)量是否相等)。
代碼實現(xiàn):文章來源:http://www.zghlxwxcb.cn/news/detail-844823.html
//并歸排序非遞歸
void MergeSortNonR(int* a, int n)
{
assert(a);
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
int gap = 1;
while (gap < n)
{
for (int j = 0; j < n; j+=gap*2)
{
int begin1 = j, end1 = begin1 + gap - 1;
int begin2 = begin1 + gap, end2 = begin2 + gap - 1;
if (end1 >= n || begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
int i = j;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
memcpy(a + j, tmp + j, sizeof(int) * (end2 - j + 1));
}
gap *= 2;
}
free(tmp);
tmp = NULL;
}
三、完結(jié)撒?
如果以上內(nèi)容對你有幫助不妨點贊支持一下,以后還會分享更多編程知識,我們一起進步。
最后我想講的是,據(jù)說點贊的都能找到漂亮女朋友?文章來源地址http://www.zghlxwxcb.cn/news/detail-844823.html
到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)進階篇 之 【并歸排序】(遞歸與非遞歸實現(xiàn))詳細講解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!