研究出一個排序算法,比qsort快320%!!!!!

新快排的核心思想有四點:

1.  基於快排的二分對比;

2.  二分對比的同時用最小的代價讓數組趨於有序,這樣中間值大概率位於中間位置上,二分對比取中間值作基準值效率是最優的;

3.  二分對比的同時用最小的代價檢查右邊是否有逆序,如果右邊非逆序則可跳過右邊的判斷;

4.  用循環取代遞歸調用;

 

新快排的步驟:

1.   設置左指針i、右指針j、中位指針p;

2.   取中位指針指向的元素爲基準數s;

3.   判斷左指針指向的元素是否小於基準數,小於,則循環判斷下一項是否比當前項小,是則交換,不是則循環第3步;

4.   判斷左指針指向的元素是否大於基準數,大於,則交換左指針i與中位指針p所指的元素;

5    判斷右指針指向的元素是否大於基準數,大於,則循環判斷下一項是否比當前項大,是則交換,不是則循環第5步;

6.   判斷右指針指向的元素是否小於基準數,小於,則交換右指針j與左指針i所指的元素;

7.   循環1至7步,直到i>j;

 

代碼如下( 注:如果彙編級優化,效率還可大幅提高)

#include "stdafx.h" 
#include <algorithm>
#include <ctime>

using namespace std;
#define MAX_SIZE 10000
#define TEST_TIMES 1000
#define  vksize 1000

// 新快速排序算法(新快排)
// 參數: 區間表起始,區間表結尾;  區間表格式: 起始位置1,結束位置1,起始位置2,結束位置2 .... 
void  xsort(int **r, int **x) {
	static int *i, *j, *p;  // 左指針,右指針,軸項指針
	static int **k = x; int **o = r;  // 起始暫存,結尾暫存  
	static int s;   // 關鍵字	 
	static bool b;  // 標記軸右邊是否有交換位置; 

	while (r >= o) {
		i = *r;
		j = *(r + 1);
		while (i < j) { // >=2 個元素 
			p = j - ((j - i) >> 1); // 取中間值爲軸項(偏右邊)   
			s = *p;
			b = false;
			do {
				// 要點:
				// 1. 關鍵字s始終在 *i與*j之間,起到擋板作用,免去i,j比較的同時,也可防止i\j過頭
				// 2. 相鄰兩項判斷,逆序就反轉;
				// 3. 如果右邊沒有一次交換,則右邊爲有序,b作爲標記;
				while (*i < s) { register int vs = *i; i++; while (vs > *i) { *(i - 1) = *i; i++; }; if (*(i - 1) != vs) *(i - 1) = vs; }   
				// *i>=s
				if (*i > s) { *p = *i; *i = s; b = true; }
				// *i==s 
				while (*j > s) { register int vs = *j; j--; while (vs < *j) { *(j + 1) = *j; j--; }; if (*(j + 1) != vs) { *(j + 1) = vs; b = true; } }
				// *i==s  *j<=s
				if (*j < s) { *i = *j; *j = s; b = true; }
				// *i>=s
				p = j;
				++i;
			} while (i < j);

			while (--j > *r && *j == s);
			if (b) {
				i = p;
				while (++i < *(r + 1) && *i == s);

				if (i < *(r + 1)) { // 右邊執行
					if (j > *r) { // 左邊暫存
						// 區間暫存不夠用時,把空間壓縮一半;   
						if ((r + 3) > k) { // x>=o + 3
							if (k < x) { // 有折半
								*o = *k;
								*k = *x;
							} else { // 沒折半
								k = x - ((x + 1 - o) >> 1);
								*k = *o;
								*(o + 1) = *(r + 1);
								*(r + 1) = j;
								r = o;
								*r = i;
								j = *(r + 1);
								continue;  // 下一次循環; 
							}
						}
						*(r + 3) = *(r + 1);
						*(r + 1) = j;
						r++; r++;
					}
					*r = i;
					j = *(r + 1);
					continue;  // 下一次循環; 
				}
			}
			if (j > *r) {
				*(r + 1) = j;
				i = *r;
				continue;  // 下一次循環;
			}
			break;
		};
		r--; r--;
	};
}
inline int cmp(const void *a, const void *b) {
	return(*(int *)a - *(int *)b);
} 

int main()
{  
	LARGE_INTEGER  num;
	long long start, end;
	double freq;
	QueryPerformanceFrequency(&num);
	freq = num.QuadPart;
	 
	srand((unsigned)time(NULL));
	int d1[MAX_SIZE],d2[MAX_SIZE],d3[MAX_SIZE];
	int * VK[vksize];
	long long sum;
	int i;
	for (int times = 0; times < TEST_TIMES; ++times)
	{
		sum = 0;
		for (i = 0; i <MAX_SIZE; ++i)
		{
			d1[i] = rand() % MAX_SIZE;
			// d1[i] = i;
			d2[i] = d1[i];
			d3[i] = d1[i];
			sum += d1[i];
		}
		QueryPerformanceCounter(&num);
		start = num.QuadPart;
		VK[0] = d1;
		VK[1] = &d1[MAX_SIZE - 1];
		xsort(VK, &VK[vksize - 1]); 
		QueryPerformanceCounter(&num);
		end = num.QuadPart; 
		for (i = 0; i < MAX_SIZE - 1; ++i)
		{
			sum -= d1[i];
			if (d1[i] > d1[i + 1])
			{
				printf("algorithm failed\n");
				for (int j = 0; j < MAX_SIZE - 1; ++j)
				{
					printf("%d,", d1[j]);
				}
				printf("%d", d1[MAX_SIZE - 1]);
				return 1;
			}
		}
		sum -= d1[i];
		printf("xsort: %f,%lld  ", ((double)(end - start)) / freq,sum);

		QueryPerformanceCounter(&num);
		start = num.QuadPart;
		qsort(d2, MAX_SIZE, sizeof(d2[0]), cmp);
		QueryPerformanceCounter(&num);
		end = num.QuadPart;
		printf("qsort: %f;   ", ((double)(end - start)) / freq);

		QueryPerformanceCounter(&num);
		start = num.QuadPart;
		sort(d3, d3 + MAX_SIZE);
		QueryPerformanceCounter(&num);
		end = num.QuadPart;
		printf("sort: %f \n", ((double)(end - start)) / freq);	
	}  

	getchar(); 
	return 0;
} 

採用隨機數組測試:

採用有序數組測試 :

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章