1. 程式人生 > >《演算法導論》——計數排序

《演算法導論》——計數排序

《演算法導論》——計數排序

  1. 計數排序是一個非基於比較的排序演算法,該演算法於1954年由 Harold H. Seward 提出。它的優勢在於在對一定範圍內的整數排序時,它的複雜度為Ο(n+k)(其中k是整數的範圍),快於任何比較排序演算法。當然這是一種犧牲空間換取時間的做法,而且當O(k)>O(nlog(n))的時候其效率反而不如基於比較的排序(基於比較的排序的時間複雜度在理論上的下限是O(nlog(n)), 如歸併排序,堆排序)。

  2. 計數排序的基本思想為一組數在排序之前先統計這組數中其他數小於這個數的個數,則可以確定這個數的位置。例如要排序的數為 7 4 2 1 5 3 1 5;則比7小的有7個數,所有7應該在排序好的數列的第八位,同理3在第四位,對於重複的數字,1在1位和2位(暫且認為第一個1比第二個1小),5和1一樣位於6位和7位。

  3. 計數排序的實現辦法:
    首先需要三個陣列,第一個陣列記錄A要排序的數列大小為n,第二個陣列B要記錄比某個數小的其他數字的個數所以第二個陣列的大小應當為K(數列中最大數的大小),第三個陣列C為記錄排序好了的數列的陣列,大小應當為n。接著需要確定陣列最大值並確定B陣列的大小。並對每個數由小到大的記錄數列中每個數的出現次數。因為是有小到大通過出現次數可以通過前面的所有數的出現次數來確定比這個數小的數的個數,從而確定其位置。對於重複的數,每排好一個數則對其位置數進行減減操作,以此對完成其餘相同的數字進行排位。


計數排序虛擬碼計數排序虛擬碼
A為原始陣列,B為輸出陣列,C為臨時陣列。2~3行初始化臨時陣列.4-5行對A陣列中的數出現的次數進行統計,此時C中的值為索引在A中出現的次數。7-8行通過相加計算得到對每個i=0…K,有多少個元素小於等於i。10-11行將A中的元素放在B中對應的位置上。因為共有C[A[j]]個元素小於或等於A[j],所有的元素可能都不是互異的,所以放入正確的位置後要減一。


計數排序流程圖在這裡插入圖片描述


計數排序C++程式碼

#include "iostream"
using namespace std;

void Counting_Sort(int a[], int len,int* b, int k)
{
	
	int* temp = new int[k+1];//最大值為K,那麼temp中陣列最大下標應為K,個數由K+1個
	memset(temp, 0, sizeof(int)*(k+1));
	for (int i = 0; i < len; i++)//統計陣列a中各元素出現的次數
	{
		temp[a[i]]++;
	}
	for (int j = 1; j < k+1; j++)//temp中每個位置的值為陣列中小於等於當前位置索引的個數
	{
		temp[j] = temp[j] + temp[j - 1];
	}
	for (int m = 0; m < len; m++)
	{
		b[temp[a[m]]-1] = a[m]; //例如,放在b中的第4個位置,那麼在b中的索引應為b[3]
		temp[a[m]] --;
	}

	delete[] temp;
}

void main()
{
	int a[] = { 2,6,1,7,3,2,0 };
	int max = a[0];
	int length = sizeof(a) / sizeof(a[0]);
	int *des = new int[length];
	memset(des, 0, sizeof(int)*length);
	for (int i = 1; i < length; i++)//找到最大值
	{
		if (max < a[i])
			max = a[i];
	}
	Counting_Sort(a, length,des, max);
	for (int i = 0; i < length; i++)
		cout << des[i];
	cout << endl;
	delete [] des;
	system("pause");
}