1. 程式人生 > >計數排序的理解與實現

計數排序的理解與實現

    計數排序是一種非基於比較的排序演算法,其空間複雜度和時間複雜度均為O(n+k),其中k是整數的範圍。基於比較的排序演算法時間複雜度最小是O(nlogn)的。注意:計數排序對於實數的排序是不可行的(下面會解釋)。該演算法於1954年由 Harold H. Seward 提出。

    下面根據一個示例來講解,比如現在有個待排序的整數序列A={-1, 2, 0, 4, 3, 6, 5, 8, -2, 1, 3, 0, 3,6, 5, 2}。首先我們花O(n)的時間掃描一下整個序列,可以得到max=8,min=-2。然後我們建立一個新的陣列C,長度為(max-min+1)=11。

陣列C如下所示

    陣列index為0的元素記錄的值是-2出現的次數,依次index為1的元素記錄的是-1出現的次數。

    此時我們再掃描一下陣列A,比如對於-1,我們的操作是:-1-min=-1-(-2)=1;C[1]++。對於2,我們的操作是:2-(-2)=4;C[4]++。這樣我們又花了O(n)的時間。操作結果是:


    最後我們便可以輸出目標整數序列了,具體的邏輯是遍歷陣列C,比如C[0]=1,則輸出一次min+index即(-2+0)=-2;C[1]=1,則輸出一次-1;C[2]=2,則輸出兩次0,以此類推。目標序列為:

-2, -1, 0, 0, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 8

       分析可得,我們掃描了兩次陣列A,一次陣列C,所以計數排序的時間複雜度為2(n)+n+k(掃描陣列C的時間複雜度是n+k)。空間複雜度是:n+k(n是陣列A的空間,最後輸出目標整數序列時可以直接儲存在A中;k是陣列C的空間)。故其空間複雜度和時間複雜度均為O(n+k)。

       前面說了計數排序對於實數的排序是不可行的,這是因為我們無法根據最小值和最大值來確定陣列C的長度,比如0.1和0.2之間有無限個實數。但是如果限制實數精度,依然是可行的,比如說陣列A中的數字只保留5位小數。但是這已經不是實數了,相當於整數,因為相當於給原來陣列A的所有數都乘以10^5。

具體的Java程式碼如下所示(countSort1在空間上作了一點優化,countSort2是最原版的實現,countSort1是上述描述的實現)

public class CountSortTest {

	public static void main(String[] args) {
		
		int [] A = {-1, 2, 0, 4, 3, 6, 5, 8, -2, 1, 3, 0, 3, 6, 5, 2};
		int [] B = countSort2(A);
		for(int index = 0; index < B.length; index++)
			System.out.print(B[index] + "  ");
		System.out.println();
		countSort1(A);
		for(int index = 0; index < A.length; index++)
			System.out.print(A[index] + "  ");
		
	}
	
	private static void countSort1(int [] A) {
		int min = 0, max = 0;
		int [] C = null;
		for(int index = 0; index < A.length; index++) {
			if(A[index] < min) {
				min = A[index];
				continue;
			}
			if(A[index] > max)	max = A[index];
		}
		C = new int[max - min + 1];
		for(int index = 0; index < A.length; index++) {
			C[A[index] - min]++;
		}
		int a = 0;
		for(int index = 0; index < C.length; index++) {
			for(int count = 0; count < C[index]; count++){
				A[a++] = index + min;
			}
		}
	}
	
	private static int [] countSort2(int [] A) {
		int min = 0, max = 0;
		int [] C = null;
		int [] B = new int[A.length];
		for(int index = 0; index < A.length; index++) {
			if(A[index] < min) {
				min = A[index];
				continue;
			}
			if(A[index] > max)	max = A[index];
		}
		C = new int[max - min + 1];
		for(int index = 0; index < A.length; index++) {
			C[A[index] - min]++;
		}
		for(int index = 1; index < C.length; index++){
			C[index] = C[index] + C[index - 1];
		}
		for(int index = A.length - 1; index > -1; index--) {
			B[C[A[index] - min] - 1] = A[index];
			C[A[index] - min]--;
		}
		return B;
	}
}

程式執行結果:


相關推薦

計數排序理解實現

    計數排序是一種非基於比較的排序演算法,其空間複雜度和時間複雜度均為O(n+k),其中k是整數的範圍。基於比較的排序演算法時間複雜度最小是O(nlogn)的。注意:計數排序對於實數的排序是不可行的(下面會解釋)。該演算法於1954年由 Harold H. Sewar

排序演算法(八)迭代歸併排序理解實現

基本概念 歸併排序大量引用了遞迴,儘管在程式碼上比較清晰,容易理解,但這會造成時間和空間上的效能損耗 排序追求的就是效率,可以講遞迴轉化成迭代,改動後效能上就得到了進一步的提高。非遞迴的迭代方法避免了遞迴時深度為log2(n)的棧空間,空間知識用到申請歸併臨時用到的TR陣

快速排序挖坑法理解實現

自己實現的程式碼如下 package sort; /*快速排序 * 簡單理解為找位置排序,每趟排序都為閾值pivot找到其該放的位置,即其左邊的全都<=pivot,其右邊的全都>pivot; * 然後對左右兩邊分別遞迴執行之前的步驟; * 1 low

C++ 計數排序演算法的實現改進(含筆試面試題)

      計數排序侷限性比較大,演算法思想:假定輸入是有一個小範圍內的整數構成的(比如年齡等),利用額外的陣列去記錄元素應該排列的位置,思想比較簡單。       計數排序是典型的不是基於比較的排序

Java回調函數的理解實現

final task 任務 操作 回調函數 數通 except 接口回調 RoCE 回調函數,或簡稱回調,是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計允許了底層代碼調用在高層定義的子程序。 在Java裏面,我們使用接口來實現回調。舉個例子 所謂的回調,

UNIX中管道的理解實現

管道是什麼 首先來看一個命令: cat file1 file2 | sort cat表示讀取file1、file2中的資料,然後使用管道 |,將這些內容作為輸入,使用sort函式作為輸出,最後輸出在螢幕上。 管道做了什麼事 熟悉類UNIX系統的朋友一定經常

Hadoop MapReduce二次排序演算法實現之演算法解析

MapReduce二次排序的原理     1.在Mapper階段,會通過inputFormat的getSplits來把資料集分割成split public abstract class Input

Array.prototype.reduce 的理解實現

Array.prototype.reduce 是 JavaScript 中比較實用的一個函式,但是很多人都沒有使用過它,因為 reduce 能做的事情其實 forEach 或者 map 函式也能做,而且比 reduce 好理解。但是 reduce 函式還是值得去了解的。 reduce 函式可以對一個數組進行

KdTree理解實現(Java)

KdTree理解與實現(Java) 丟擲問題 KdTree簡介 原理簡介 程式碼實現 Point.java Rect.java KdTree.java 複雜度比較 結語 丟擲問題

GAN網路理解實現

一、GAN網路的基本理解 GAN(Generative Adversarial Net)又稱之為生成對抗網路,最少是由被稱作“GANs 之父”的”Lan GoodFellow在 2014年開創性地提出. 正如諸多介紹中表述的,GAN的思想是一種二人聯合博弈的思想

非極大值抑制(non-maximum suppression)的理解實現

RCNN 和微軟提出的 SPP_net 等著名的目標檢測模型,在演算法具體的實施過程中,一般都會用到 non-maximum suppress(非最大值抑制,抑制即忽略, 也即忽略那些值(IoU)高於提供的閾值的) 的機制。 引入 non-maximum

排序--堆排序分析實現

何為堆 一個數組序列我們可以將其用完全二叉樹或近似完全二叉樹(不是滿二叉樹的完全二叉樹)表示出來,當陣列下標為i時,它的父節點為(i-1)/2,左孩子為(2i+1),右孩子為(2i+2),這種對應關係說明陣列下標為0的地方也要儲存資料。(關於完全二叉樹和滿二叉

計數排序(c++實現

簡單計數排序: 假設待排序的陣列a中共有N個整數,並且已知陣列a中資料的範圍[0, MAX)。在桶排序時,建立容量為MAX的陣列r,並將陣列元素都初始化為0;。在排序時,遍歷陣列a,將陣列a的值,作為陣列r的下標。當a[i]被讀取時,就將r[a[i]]的值加1。例如,讀取到

計數排序的簡單實現

計數排序的原理比較簡單,但是很巧妙。有點類似於桶排序,但是有一些區別。 具體思想是,給定一個數組,先統計各個元素出現的次數,用元素的值做下標,得到一個新的陣列。然後掃描這個陣列,對於陣列的每個下標,如果它對應的值不為零,說明原來陣列中就有幾個這樣的值。由於下標的天然遞增,依

spring+mybatis通用dao層、service層的一些個人理解實現

1、現在的絕大多數web應用,通常都以action、service、dao三層去組織程式碼,這樣劃分結構很清晰,分工明確 2、一般情況下,我們會把事務控制在service層。 3、action和dao層,會使用一些框架技術。比如action層可能選擇有springmvc、struts等,dao層有hibe

深度學習(二十二)Dropout淺層理解實現

Dropout淺層理解與實現 作者:hjimce 一、相關工作     本來今天是要搞《Maxout Networks》和《Network In Network》的,結果發現maxout和dropo

Quartz理解實現

記錄關於Quartz定時排程任務的知識點,知識點主要分為兩個部分,第一個部分介紹Quartz,第二部分使用Quartz+Spring來配置使用Quartz的實際操作。 (一)Quartz知識點 Quartz是完全由java開發的一個開源的任務日程管理系統,“任務進度管理器

Unity 有限狀態機(Finite State Machine)的理解 實現簡單的可插拔(Pluggable)AI指令碼物件。

#Unity 有限狀態機(Finite State Machine)的理解 與 實現簡單的可插拔AI指令碼物件。   一般的遊戲AI都是使用狀態機的設計模式來實現的。發現官方有教程,就跟了一遍,這裡就總結一下。   先簡單說一下狀態模式。就是根據當前狀態

《演算法導論》中的計數排序的C++實現

#include<iostream> #include<vector> using namespace std; void CountSort(vector<int&

排序演算法之——計數排序(Java實現

        今天,我來講一講計數排序。計數排序與堆排序快速排序等排序不同,它是一種非比較排序,已經有人證明過,比較排序的時間下界是Ω(nlogn),但這個性質是不適用於計數排序的,因為它不是比較排序。他的時間是線性的。        計數排序假設n個輸入,每個都是介於0