1. 程式人生 > >計數排序的簡單實現

計數排序的簡單實現

計數排序的原理比較簡單,但是很巧妙。有點類似於桶排序,但是有一些區別。

具體思想是,給定一個數組,先統計各個元素出現的次數,用元素的值做下標,得到一個新的陣列。然後掃描這個陣列,對於陣列的每個下標,如果它對應的值不為零,說明原來陣列中就有幾個這樣的值。由於下標的天然遞增,依次將這些值展開就得到了排序後的陣列。

但是計數排序有它的侷限性,首先如果想用陣列統計各個元素出現的次數,它的值必須是正整數。如果你想用map來統計次數的話,那麼就無法保證下標的遞增特性。(某些語言的map實現可能會自動按照下標排序,但複雜度就是另一回事了)。

最後,計數排序的複雜度是O(n+k),n為元素個數,k為最大值。程式碼如下:

// countSort.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;

vector<int> countSort(vector<int>& v)
{
	//找到最大值
	int max = -1000000;
	for (auto i : v)
		if (i >= max)
			max = i;
	
	//掃描一遍,記錄各元素出現的次數
	vector<int> c;
	c.resize(max + 1);
	for (auto i : v)
		c[i]++;

	//對出現的每個元素,按照其出現的次數,依次展開到目標陣列
	vector<int> ans;
	for (int i = 0; i < c.size(); i++)
	{
		if (c[i] != 0)
		{
			int temp = c[i];
			while (temp--)
				ans.push_back(i);
		}
	}
	return ans;
}

int main()
{
	vector<int> a = { 8,2,4,9,3,6,100 };
	auto ans=countSort(a);
	for (auto i : ans)
		cout << i << endl;
	system("pause");
	return 0;
}

執行結果:


上面是按照我自己對計數排序的理解所寫的程式碼。

CLRS中採用了另外一種方法。在的得到每個數出現次數的陣列後,將這個陣列的每個數加上它前面的一個數。這樣得到的新陣列中,每個元素表示小於等於某個數(也就是下標)的個數。舉個栗子,比如說小於等於5的個數為6,則不管有幾個總共有幾個5,總會有最後一個5排在第5位(下標從0開始),這樣算上剩下的小於等於5的那些數,總共達到了6個。這個地方稍微有點繞,不過這就是CLRS上關於計數排序的關鍵所在。因此我們可以用這個性質對原始陣列中的元素再做一遍掃描,找到每個數的正確位置。程式碼如下:

// countSort.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;

vector<int> countSort(vector<int>& v)
{
	//找到最大值
	int max = -1000000;
	for (auto i : v)
		if (i >= max)
			max = i;
	
	//掃描一遍,記錄各元素出現的次數
	vector<int> c;
	c.resize(max + 1);
	for (auto i : v)
		c[i]++;

	
	//對出現的每個元素,按照其出現的次數,依次展開到目標陣列
	vector<int> ans;
	for (int i = 0; i < c.size(); i++)
	{
		if (c[i] != 0)
		{
			int temp = c[i];
			while (temp--)
				ans.push_back(i);
		}
	}
	return ans;
}

vector<int> countSort1(vector<int>& v)
{
	//找到最大值
	int max = -1000000;
	for (auto i : v)
		if (i >= max)
			max = i;

	//掃描一遍,記錄各元素出現的次數
	vector<int> c;
	c.resize(max + 1);
	for (auto i : v)
		c[i]++;

	//小於等於每個數的個數
	for (int i = 1; i < c.size(); i++)
		c[i] += c[i - 1];

	vector<int> ans;
	ans.resize(v.size());
	//for (int i = v.size() - 1; i >= 0; i--)
	for(int i=0;i<v.size();i++)
	{
		ans[c[v[i]] - 1] = v[i]; //例如小於等於某個數的個數為m,則這個數應該被放在第m-1位
		--c[v[i]]; //同時,因為已經放置好了一個該數,所以計數值應該減一
	}
	return ans;
}

int main()
{
	vector<int> a = { 8,2,4,9,3,6,100 };
	auto ans=countSort1(a);
	for (auto i : ans)
		cout << i << endl;
	system("pause");
	return 0;
}