C++/GoLang如何實(shí)現(xiàn)自底向上的歸并排序
前言
上一篇文章寫了一個(gè)自頂向下的歸并排序,把一個(gè)完整的數(shù)組不斷二分,然后再合并。其實(shí)換一種思路:把數(shù)組中相鄰的N個(gè)元素看成是已經(jīng)二分好了的,直接進(jìn)行合并,就省掉了二分那一步驟

C++實(shí)現(xiàn):
template<typename T>
void mergeSortButton2Top(T arr[], int n) {
for (int size = 1; size <= n; size += size) {
for (int i = 0; i+size < n; i+=2*size) //對(duì)[i,i+size-1]和[i+size,i+2*size-1]進(jìn)行歸并
__merge(arr, i, i + size - 1, min(i + size + size - 1,n-1));// arr left mid right 如果i+2*size>n了,越界了,就取n-1
}
}
template<typename T>
void __merge(T arr[], int left, int mid, int right) { //將arr[left,mid] 和 arr[mid+1,right] 兩部分進(jìn)行歸并
T *tmp=new T[right-left+1];
for (int i = left; i <= right; i++)
tmp[i - left] = arr[i]; //先把a(bǔ)rr(需要合并的左右片段) 復(fù)制給tmp
int i = left, j = mid + 1; // i 做為左半部分的指針 j作為右半部分的指針
for (int k = left; k <= right; k++) {
if (i > mid) { // 左半部分 已經(jīng)合入完了,將右半部分剩下的 全部合入
arr[k] = tmp[j - left];
j++;
}
else if (j > right) { // 右半部分 已經(jīng)合入完了,將左半部分剩下的 全部合入
arr[k] = tmp[i - left];
i++;
}
else if (tmp[i - left] < tmp[j - left]) {
arr[k] = tmp[i - left];
i++;
}
else {
arr[k] = tmp[j - left];
j++;
}
}
delete[] tmp;
}
int main() {
int arr[9] = { 1,5,6,78,12,5,1,12,54 };
mergeSortButton2Top(arr,9);
for (int i = 0; i < 9; i++) {
cout << arr[i]<<" ";
}
return 0;
}
GoLang實(shí)現(xiàn):
func mergeSortButton2Top(arr [] int) {
var lenth int = len(arr)
for size := 1; size <= lenth; size += size {
for i := 0; i+size < lenth; i += 2 * size { //對(duì)[i,i+size-1]和[i+size,i+2*size-1]進(jìn)行歸并
merge(arr, i, i+size-1, int(math.Min(float64(i+2*size-1), float64(lenth-1))))// arr left mid right 如果i+2*size>n了,越界了,就取n-1
}
}
}
func merge(arr []int, left, mid, right int) {
// 將要合并的部分做個(gè)拷貝
var tmp []int = make([]int, right-left+1)
for i, j := left, 0; i <= right; i++ {
tmp[j] = arr[i]
j++
}
// i做為左半部分的指針 j作為右半部分的指針
var i, j int = left, mid+1
for k := left; k <= right; k++ {
if i > mid { // 左半部分 已經(jīng)合入完了,將右半部分剩下的 全部合入
arr[k] = tmp[j-left]
j++
} else if j > right { // 右半部分 已經(jīng)合入完了,將左半部分剩下的 全部合入
arr[k] = tmp[i-left]
i++
} else if tmp[i-left] > tmp[j-left] {
arr[k] = tmp[j-left]
j++
} else {
arr[k] = tmp[i-left]
i++
}
}
}
用golang對(duì)兩種歸并排序進(jìn)行計(jì)時(shí),觀察性能:
func createRandomArray(count int) []int {
rand.Seed(time.Now().UnixNano())
var arr [] int = make([]int, 0)
for i := 0; i < count; i++ {
arr = append(arr, rand.Intn(100))
}
return arr
}
func main() {
count := 10000
arr := createRandomArray(count)
var arr2 []int = make([]int, count)
copy(arr2, arr)
start := time.Now()
mergeSort(arr, 0, len(arr)-1)
fmt.Println("自頂向下歸并排序 用時(shí):", time.Since(start))
start = time.Now()
mergeSortButton2Top(arr2)
fmt.Println("自底向上歸并排序 用時(shí):", time.Since(start))
}
//輸出:
//自頂向下歸并排序 用時(shí): 4.997ms
//自底向上歸并排序 用時(shí): 3.9987ms
因?yàn)樽缘紫蛏仙倭硕帜莻€(gè)步驟,性能要優(yōu)于自頂向下的歸并排序
總結(jié)
到此這篇關(guān)于C++/GoLang如何實(shí)現(xiàn)自底向上的歸并排序的文章就介紹到這了,更多相關(guān)C++/GoLang自底向上的歸并排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)兩個(gè)有序數(shù)組的合并
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)兩個(gè)有序數(shù)組的合并,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
c語(yǔ)言實(shí)現(xiàn)向上取整計(jì)算方法
這篇文章主要介紹了c語(yǔ)言實(shí)現(xiàn)向上取整計(jì)算方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
基于Matlab實(shí)現(xiàn)水波倒影特效的制作
這篇文章主要介紹了如何利用Matlab制作出水波倒影的特效,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下2022-03-03
c++實(shí)現(xiàn)值機(jī)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了c++實(shí)現(xiàn)在線值機(jī)系統(tǒng)程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C語(yǔ)言一看就懂的選擇與循環(huán)語(yǔ)句及函數(shù)介紹
函數(shù)是一個(gè)功能模塊,它把實(shí)現(xiàn)某個(gè)功能的代碼塊包含起來(lái),并起一個(gè)函數(shù)名,供別人調(diào)用,如printf函數(shù),如system函數(shù)。是程序運(yùn)行當(dāng)中包裝起來(lái)的一個(gè)步驟;選擇與循環(huán)是編程中最常用的結(jié)構(gòu),本篇文章用最簡(jiǎn)單的文字帶你了解它們2022-04-04
Eclipse對(duì)printf()不能輸出到控制臺(tái)的快速解決方法
Eclipse對(duì)printf()不能輸出到控制臺(tái)的快速解決方法。需要的朋友可以過來(lái)參考下,希望對(duì)大家有所幫助2013-10-10
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08

