雙調排序進階:對任意長度的序列排序(C語言)

雙調排序進階:對任意長度的序列排序(C語言)

996.icu LICENSE

  • 雙調排序回顧+進階
  • 進階雙調排序怎麼實現

閱讀之前注意:

本文閱讀建議用時:20min
本文閱讀結構如下表:

項目 下屬項目 測試用例數量
雙調排序回顧+進階 0
進階雙調排序怎麼實現 1

雙調排序回顧+進階

雙調排序是基於四元素排序發展起來的一種排序方法,單純的雙調排序適用於2的冪次方個元素的序列的排序。而選擇排序和冒泡排序都屬於三元素排序。
四元素排序的思想是這樣的,比如說有(3,2,1,4)這一個序列,我們要按照從小到大(升序)的順序來排序。
(3,2,1,4)–>(2,3)(4,1)–>(2,1)(4,3)–>(1,2)(3,4)。

以上過程可總結爲這樣的規律(實現整體升序):
第一步,序列等分,第一部分升序,第二部分降序
第二步,兩個子序列對應元素比較互換;
第三步,對兩個子序列均升序排序。1

經過個人的思考,我認爲原理可用下圖表示:
第一步的升序和降序是爲了找出一個等位值,第二步把兩個子序列對應位置的元素進行比較,找到這個等位值,把小於等位值的交換到第一個子序列,大於等位值的交換到第二個子序列,所以第三步中只需要分別對子序列進行排序即可實現整體的排序。

那麼對於不是2的冪次方個元素的序列,我們怎麼能採用雙調排序嗎?通常思路是:把序列補充爲有2的冪次方個元素,再採用雙調排序。顯然這種方法非常浪費空間,不建議使用。

我的思路是在原有排序思想上進行一小點的改動。
我們還是以最終實現整體升序爲例。因爲對於任意序列,要麼是奇序列,要麼是偶序列。對於奇序列,做以下改進:
第一步,還是等長劃分,但第二個序列會多一個元素,第一部分升序,第二部分降序;
第二步,兩個子序列對應元素比較互換,只是其中對應的元素,第二個序列是從第二個元素開始(即子序列一的1號元素對應子序列二的2號元素,子序列一的2號元素對應子序列二的3號元素… …);
第三步,對兩個子序列均升序排序。

其中關鍵步驟在於第二步,爲什麼比較的元素,對於第二個子序列應該從第二個元素開始算呢?

因爲在第二步中,我們是要把小於等位值的換到第一個子序列中,由於第二個子序列是降序排序的,所以最後一個元素(最小)很有可能被換到第一個子序列中。你可能會問,那麼第二個子序列的第一個元素不用考慮嗎?是的,不用考慮!

請你仔細想想,如果這第一個元素比等位值大,顯然應該留在第二個序列當中,如果比等位值小呢,我們換過去給子序列一的可都是比這個元素小的,可別忘了子序列二是降序排列的,而從子序列一中換過來的又都是比等位值大的(也就大於這個元素,即把子序列一中大於這個元素的都換到了子序列二)。因此經過第二步交換後,子序列一中不可能有元素大於子序列二的第一個元素。所以第三步還是兩個子序列均升序即可實現最終的升序。

進階雙調排序怎麼實現

我們在原有C程序的基礎上實現進階的雙調排序。
參考以下代碼:

#include<stdio.h>
#include<stdlib.h>
#define up 1
#define down 0
#define N 45

void generateNum(int *a,int num)
{
	for (int i = 0; i < num; i++){
		a[i] = rand() % 100;
	}
}

void compare(int *a, int *b, int type)
{
	int tmp = 0;
	if (type == up){
		if (*a > *b){
			tmp = *a;
			*a = *b;
			*b = tmp;
		}
	}
	else if (type == down){
		if (*a < *b){
			tmp = *a;
			*a = *b;
			*b = tmp;
		}
	}
	else
		printf("err,type\n");
}


void sort(int *a, int num, int type)
{
	if (num <= 1)
		return;
	int n = num / 2;
	sort(a, n, type);//升
	sort(a + n, n + num % 2, 1 - type);//降                                 
	for (int i = 0; i < n; i++)//中間過程
		compare(&a[i], &a[i + n + num % 2], type);
	sort(a, n, type);//升
	sort(a + n, n + num % 2, type);//升
}

void main()
{
	int *a = (int *)malloc(N*sizeof(int));
	generateNum(a, N);//生成隨機數組
	sort(a, N, up);//雙調排序
	for (int i = 0; i < N; i++)
		printf("%d ", a[i]);
	system("pause");
}

以上我增加了一個隨機生成數組的函數,而雙調排序的改進,僅僅只需要在sort()函數中加上num%2,即可實現對任意長度的序列進行排序。
代碼中sort()函數中的註釋:升與降對應第一步,中間過程對應第二步,升與升對應第三步。2

如果本文對你有幫助,不如請我一罐可樂吧 🍼
在這裏插入圖片描述


  1. 方法基於《GPU高性能運算之CUDA》–5.1.1. ↩︎

  2. 程序改進自上一篇博客《雙調排序思想及實現》. ↩︎

發佈了49 篇原創文章 · 獲贊 28 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章