排序算法之計數排序

原理:

假設待排序序列沒有負數。對序列裏面的所有元素,確定比該元素小的元素有幾個。利用這個信息就能知道該元素應該放在哪個位置上。

舉例:

1 7 5 5 2 3 9 3 5 6
                     A序列(待排序)

0 1 1 2 0 3 1 1 0 1
                     B序列(統計待排序的序列元素對應B下標的個數)

然後我們對B序列相鄰兩個元素進行相加,相加後的數字放在下標較大的位置裏。

0 1 2 4 4 7 8 9 9 10
                    B序列(相加後的結果,用於表示比A中元素小的元素個數)

然後我們對A序列逆序便利一下,結果放在C序列裏面。

倒數第一個爲6,找到B序列下標爲6的位置,裏面的值爲8,說明這個元素應該排在第七個位置上。

              6    
                   C序列

B序列對應的第六個位置的元素-1。避免相同的數字。

0 1 2 4 4 7 7 9 9 10
                   B序列

倒數第二個爲5,找到B序列下標爲5的位置,裏面的值爲7,說明這個元素應該排在第六個位置上。

            5 6    
                   C序列

B序列對應的第五個位置的元素-1。

0 1 2 4 4 6 7 9 9 10
                     B序列

倒數第三個爲3,找到B序列下標爲3的位置,裏面的值爲4,說明這個元素應該排在第三個位置上。

      3     6    
                     C序列

B序列對應的第三個位置的元素-1。

0 1 2 3 4 6 7 9 9 10
                        B序列

倒數第四個爲9,找到B序列下標爲9的位置,裏面的值爲10,說明這個元素應該排在第九個位置上。

      3     5 6   9
                       C序列

B序列對應的第九個位置的元素-1。

0 1 2 3 4 6 7 9 9 9
                        B序列

倒數第五個爲3,找到B序列下標爲3的位置,裏面的值爲3,說明這個元素應該排在第二個位置上。

    3 3     5 6   9
                        C序列

B序列對應的第三個位置的元素-1。

0 1 2 2 4 6 7 9 9 9
                         B序列

倒數第六個爲2,找到B序列下標爲2的位置,裏面的值爲2,說明這個元素應該排在第一個位置上。

  2 3 3     5 6   9
                         C序列

B序列對應的第二個位置的元素-1。

0 1 1 2 4 6 7 9 9 9
                         B序列

倒數第七個爲5,找到B序列下標爲5的位置,裏面的值爲6,說明這個元素應該排在第五個位置上。

  2 3 3   5 5 6   9
                         C序列

B序列對應的第五個位置的元素-1。

0 1 1 2 4 5 7 9 9 9
                          B序列

倒數第八個爲5,找到B序列下標爲5的位置,裏面的值爲5,說明這個元素應該排在第四個位置上。

  2 3 3 5 5 5 6   9
                           C序列

B序列對應的第五個位置的元素-1。

0 1 1 2 4 4 7 9 9 9
                          B序列

倒數第九個爲7,找到B序列下標爲7的位置,裏面的值爲9,說明這個元素應該排在第八個位置上。

  2 3 3 5 5 5 6 7 9
                          C序列

B序列對應的第七個位置的元素-1。

0 1 1 2 4 4 7 8 9 9
                         B序列

倒數第十個爲1,找到B序列下標爲1的位置,裏面的值爲1,說明這個元素應該排在第零個位置上。

1 2 3 3 5 5 5 6 7 9
                         C序列(此時所有的元素已經排列完成)

B序列對應的第一個位置的元素-1。

0 0 1 2 4 4 7 8 9 9
                         B序列

代碼:

void CountSort(int a[], int nlen)
{
	int temp = a[0];
	for (int i = 0; i != nlen; ++i)
	{
		if (temp < a[i])
		{
			temp = a[i];
		}
	}
	int b_size = temp + 1;
	int *b = new int[b_size];
	for (int i = 0; i != b_size; ++i)
	{
		b[i] = 0;
	}
	for (int i = 0; i != nlen; ++i)
	{
		++b[a[i]];
	}
	for (int i = 1; i != b_size; ++i)
	{
		b[i] += b[i - 1];
	}
	int *c = new int[nlen];
	for (int i = nlen-1; i >= 0; --i)
	{
		c[--b[a[i]]] = a[i];
	}
	for (int i = 0; i != nlen; ++i)
	{
		a[i] = c[i];
	}
	delete[] b;
	b = nullptr;
	delete[] c;
	c = nullptr;
}


總結:

計數排序的思想很簡單,並且是已常量時間完成的排序,時間複雜度爲O(N),但是缺陷也很明顯,其一,必須是大於等於0的元素,當有數字爲負數的時候,可以給每個元素都加上一個正數,使得待排序序列爲正數,排完後再減去這個正數(前提不越界的情況下)。其二,該排序算法浪費了大量的空間來換取時間。例如有99999的元素,那麼B序列也應該有100000的長度。




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