對一億個數據排序時間少於1秒排序算法WaveSort

    前言:乾貨乾貨,作者偶然在工作中悟出來了一種排序算法,聽標題就很牛逼,下面開始一一讓大家瞭解此算法。

一、首先我們直接與現有的排序算法:快速排序、C++庫裏的Sort、計數法桶排序進行速度對比

1、如圖所示,這就是測試所需要的數據和方法。

2、用1000個升序數據進行排序,小於幾毫秒我就不寫了,直接寫毫秒

C++Sort時間爲:2ms,快排:2ms,波浪:1ms,桶排1ms,桶排永遠都很快,它是消耗空間獲取速度的,如果不懂桶排可以先去學習下。

3、1000個升序數據,然後隨機打亂1000次,注意打亂是指隨機1000個位置,然後每個位置的數也隨機,所以最後出來的數據大多數可能都是有點順序的。

C++Sort時間爲:2ms,快排:1ms,波浪:1ms,桶排1ms

3、用10000個升序數據進行排序

C++Sort時間爲:7ms,快排:127ms,波浪:1ms,桶排1ms

4、10000個升序數據,然後隨機打亂10000次

C++Sort時間爲:16ms,快排:2ms,波浪:45ms,桶排1ms

4、一百萬個升序數據

C++Sort時間爲:968ms,快排:作者等不下去了,波浪:3ms,桶排15ms,有序作者的O(n)的,快排O(N^2),到這裏其實作者的排序算法作用還沒很好體現,下面開始就露出水面了。

5、一百萬個升序數據,隨機打亂10000次

C++Sort時間爲:973ms,快排:等不下去,波浪:220ms,桶排14ms

5、一百萬個升序數據,隨機打亂一百萬次

C++Sort時間爲:994ms,快排:等不下去,波浪:656ms,桶排15ms

6、一千萬個升序數據

C++Sort時間爲:等不下去,快排:等不下去,波浪:23ms,桶排140ms

6、一千萬個升序數據,隨機打亂一千萬次

C++Sort時間爲:12s,快排:等不下去,波浪:666ms,桶排139ms

7、一億萬個升序數據

C++Sort時間爲:等不下去,快排:等不下去,波浪:226ms,桶排1391ms

7、一億萬個升序數據,隨機打亂1次

C++Sort時間爲:等不下去,快排:等不下去,波浪:224ms,桶排1370ms

 

8、一億萬個升序數據,隨機打亂一萬次

C++Sort時間爲:等不下去,快排:等不下去,波浪:430ms,桶排1378ms

9、一億萬個升序數據,隨機打亂一百萬次

C++Sort時間爲:等不下去,快排:等不下去,波浪:868ms,桶排1409ms

10、一億萬個升序數據,隨機打亂億萬次

C++Sort時間爲:等不下去,快排:等不下去,波浪:868ms,桶排1397ms

11、一億萬個升序數據,隨機打亂一億萬次,波浪的空間複雜度是O(1),不管多少次,波浪空間複雜度都是O(1),遞歸次數2,其實遞歸是1,因爲加了優化多了個函數還沒介紹,後面介紹。

從以上測試表明作者的波浪是不是屌爆了,是的,其實波浪算法也是有優缺點的,如果讀者有認真讀或許已經猜到了。

優點:如果數據越有序速度越快,平均時間複雜度O (nlogn),最快O(n),最慢O(n^2)

缺點:很亂的一組數據非常不友好,它跟快排是相反的,快排越亂越快,但是好處是快排超過百萬數據就算很亂也要排很久

波浪就算1億個數據,只要不要亂到完全無序還有點秩序都非常快。

二、波浪算法優化    

       假設在一億個數據中被改變了幾百萬或幾千萬數據,這時的數據雖然還有點點秩序但其實很亂了,這個時候如果用快速排序先排N遍到有點秩序了再用波浪排就會提高速度,下面作者表演針對這類數據的優化操作。

      1、一億萬個升序數據,隨機打亂一億次,進行在波浪排序前先快速排序遞歸10000遍,第三個參數就是快排遞歸幾遍。

           優化前:886ms,優化後:539ms,

   

2、一億萬個升序數據,隨機打亂一百萬次

           優化前:913ms,優化後:565ms,

3、一億萬個升序數據,隨機打亂十萬次

           優化前:869ms,優化後:764ms,

4、一億萬個升序數據,隨機打亂一萬次

           優化前:445ms,優化後:1456ms,

5、十萬個升序數據,隨機打亂十萬次

           優化前:445ms,優化後:106ms,

測試所得:此類優化作者已經測試只適用於數據超過10萬,數據低於10萬時快排遞歸次數設置爲0合適,並且數據被打亂小於100000都不要使用哪怕一次遞歸快排。

總結:波浪非常適用有秩序的數據組中改變一些值導致無序的數據組進行排序,如果你有一股已排序數據,當其中一個或多個數據發生改變導致秩序變化時,這時候波浪就是最好選擇。、

三、實現原理

        下面是以升序排序爲例,index會一直往右邊移動,當發現當前元素大於下一個元素時,這時將下一個元素往回滾動並與每一個元素比較,比它大的都往後面挪動一次,直到找到等於或小於它的元素時就將它放到該元素後面,然後index繼續右移判斷,就這樣以此類推。

     數據3、4、2、5、7、10、4,波浪排序比較13次,快速排序比較23

源碼:

int counts = 0;
int Prob = 0;
class WaveSort
{
public:
	template<class T>
	static void SortFaser(T *arr, int left, int right)
	{
		if (left < right)
		{
			if (counts++ >= Prob)
				return;
			int tmp = Tmp(&*arr, left, right);
			SortFaser(&*arr, left, tmp - 1);
			SortFaser(&*arr, tmp + 1, right);
		}
	}
	template<class T>
	static int Tmp(T * arr, int left, int right)
	{
		T tmp = arr[left];
		while (left < right)
		{
			while (left < right && tmp <= arr[right])
			{
				right--;
			}
			arr[left] = arr[right];

			while (left < right && tmp >= arr[left])
			{
				left++;
			}
			arr[right--] = arr[left];

		}
		arr[left] = tmp;
		return left;
	}
	template<class T>
	static void Sort(T * arr,const int nLen,int FaserCount)
	{
		Prob = FaserCount;//快排遞歸次數

		SortFaser(arr, 0, nLen - 1);
		if(nLen <= 1) 
		{
			return;
		}

		T oCompareItem;

		int nEnd = -1;
		int eIndex = -1;
		int bIndex = -1;
		bool isOne = true;
		while(true)
		{
			/*
			for(int i = 0; i < 16; i++)
			{
				cout<<arr[i]<<" ";
			}
			cout<<endl;*/
			//找到第一個小於自己前一個元素的元素
			for(eIndex = eIndex + 1; eIndex < nLen - 1; eIndex++)
			{
				if(arr[eIndex] > arr[eIndex + 1])
				{
					oCompareItem = arr[eIndex + 1];
					nEnd = eIndex;
					break;
				}	
			}

			//不需要排序或已經到結尾了
			if(nEnd == -1 || eIndex == nLen - 1)
			{
				return;
			}
			arr[nEnd + 1] = arr[nEnd--];

			isOne = true;
			//把前面大於自己的元素往後移動一位
			for(bIndex = nEnd; bIndex >= 0; bIndex--)
			{
				if(arr[bIndex] > oCompareItem)
				{
					arr[bIndex + 1] = arr[bIndex];
				}
				else
				{
					arr[bIndex + 1] = oCompareItem;
					isOne = false;
					break;
				}	
			}
			if(isOne)
			{
				arr[0] = oCompareItem;
			}
		}	
	}
};

完整工程文件

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