日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序员面试系列——合并排序(递归实现)

發布時間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员面试系列——合并排序(递归实现) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

合并排序基本思想

合并排序,或者叫歸并排序,在算法思想中屬于分治法。對于一個需要排序的數組,合并排序把它一分為二,并對每個子數組遞歸排序,然后把這兩個排好序的子數組合并為一個有序數組。

本文要介紹兩種實現,都是基于遞歸(自頂向下)。這兩種實現沒有本質的差別,第二種只是為了節省內存,提高效率。

第一種實現

假設A數組是要排序的數組。
1. 把A數組的前半部分復制到B數組,把A數組的后半部分復制到C數組
2. 對B數組和C數組分別排序(遞歸);之后,B數組和C數組已經有序
3. 把數組B和C合并,成為有序數組A(見函數__merge)

C語言代碼如下。

/** 將兩個有序數組b和c合并為一個有序數組a* b是第一個非降序數組的首地址,長度是len_b* c是第二個非降序數組的首地址,長度是len_c* a指向輸出數組的首地址* 注意:a數組需要調用者分配空間,且a數組不能與b或者c重疊*/void __merge(int *a, int *b, int len_b, int *c, int len_c) {int i = 0; // b的下標int j = 0; // c的下標int k = 0; // a的下標int len = len_b + len_c; //計算出a數組的長度while(i < len_b && j < len_c) //&&的優先級更低 {if(b[i] <= c[j])a[k++] = b[i++];elsea[k++] = c[j++];}if(i == len_b) //說明b已經處理完memcpy(a+k, c+j, (len-k)*sizeof(int));else //說明c已經處理完memcpy(a+k, b+i, (len-k)*sizeof(int)); }

上面的這個函數完成“合二為一”的工作,即把非降序的B和C合并為非降序的A.

/** a是數組首地址,數組長度為len* 將數組a按照非降序排列*/ void merge_sort(int *a, int len) {if(len==1) //遞歸出口return;int len_b = len/2;int len_c = len - len_b;int *temp = (int *)malloc(sizeof(int)*len);//為數組b和c分配空間if(temp == NULL){printf("malloc failed\n");return;}memcpy(temp, a, len*sizeof(int));int *b = temp;int *c = temp+len_b; //以上三行完成了復制和拆分merge_sort(b,len_b); //遞歸調用,對數組b排序merge_sort(c,len_c); //遞歸調用,對數組c排序__merge(a, b, len_b, c, len_c); //合并b和cfree(temp);}

merge_sort這個函數才是歸并排序的主函數。

為了更好地理解,我畫了一幅示意圖。此圖體現出遞歸出口(即遞歸結束條件)是數組長度等于1.

merge_sort函數在設計上的不足之處是內存開銷大,也費時間(malloc函數用多了會影響性能)。

因為要為數組B和數組C分配空間,然后分別排序(因為是遞歸,所以又要分配與釋放),排序完畢后再把二者合并到A數組,此時數組B和數組C的空間才可以釋放。

可否改進一下呢?可以看看第二種實現。

第二種實現

假設A數組是要排序的數組。
1. 先分配一段內存(這里叫temp),其大小和數組A一樣大
2. 把A數組一分為二,前半部分稱為B數組,后半部分稱為C數組
3. 對B數組和C數組分別排序(遞歸);排序時,借助temp(借助的原因請看4和5)
4. 把數組B和C合并為有序數組,合并的結果在temp中。(利用函數__merge)
5. 把temp的內容拷貝到數組A
6. 釋放temp

這樣做的特點是一次分配,反復利用,最后釋放。優點是省內存,效率高。

C語言代碼如下。

/**內部函數*temp是一段內存的首地址,由調用者分配和釋放*/ void __merge_sort(int *a, int len, int *temp) {if(len==1) //遞歸出口return;int len_b = len/2;int len_c = len - len_b;int *b = a;int *c = a+len_b; //把數組a原地拆分為b和c__merge_sort(b,len_b,temp); //對數組b排序,借助內存temp__merge_sort(c,len_c,temp); //對數組c排序,借助內存temp__merge(temp, b, len_b, c, len_c); //合并b和c到tempmemcpy(a,temp,len*sizeof(int)); //復制temp到數組a }/**這種寫法只需要申請一次空間,節省內存,效率更高*/ void merge_sort(int *a, int len) {int *temp = (int *)malloc(sizeof(int)*len);if(temp == NULL){printf("malloc failed\n");return;}__merge_sort(a,len,temp); //此函數實現見上文free(temp); }

測試

注意,以上代碼需要包含的頭文件是

#include <string.h> //memcpy函數用這個頭文件 #include <stdlib.h> //malloc和free函數用這個頭文件

測試代碼如下。

#include <stdio.h>/**此函數為了測試用,功能是打印數組*a是數組首地址*len是數組長度*/ void print_array(int *a, int len) {int i=0;for(i=0; i<len; ++i)printf("%d ",a[i]);printf("\n"); }//測試函數 int main(void) {int a[10]={9,8,5,3,2,9,-1,-1,7,1,}; //10個數merge_sort(a,10); //按照非降序排列print_array(a,10); //打印排序后的數組return 0; }

運行結果是:

-1 -1 1 2 3 5 7 8 9 9

—–歡迎斧正—–


【參考資料】
《算法設計與分析基礎(第3版)》(清華大學出版社)

總結

以上是生活随笔為你收集整理的程序员面试系列——合并排序(递归实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。