1. 程式人生 > >對只含0,1,2三種元素的陣列設計一種O(n)時間的排序演算法

對只含0,1,2三種元素的陣列設計一種O(n)時間的排序演算法

針對只含0,1,2三種元素的陣列的一種O(n)時間的排序演算法

1. 問題重述
給定一個整型陣列,陣列中的元素只有三種:0,1,2,例如:[1 ,2 ,0 ,0 ,2 ,1 ,2 ,1 ,1 ,0 ,2 ,2 ,1 ,0 ],試設計一個時間複雜度為O(n),空間複雜度為O(1)的演算法,將陣列變換為如下的形式:
Before…
1 2 0 0 2 1 2 1 1 0 2 2 1 0
After…
0 0 0 0 1 1 1 1 1 2 2 2 2 2
2.演算法思想
設定三個標記指標:iZero, iOne, iTwo

  • 令iZero從前往後遍歷,指向第一個非0的位置,iTwo從後往前遍歷,指向第一個非2位置;
  • 然後iOne從iZero開始往後遍歷:遇到0就和iZero交換,iZero++;遇到1則iOne++;遇到2就和iTwo交換,iTwo向前滑動到下一個非2的位置,交換後還要重新檢查iOne的值;直到iOne與iTwo相遇整個變換過程結束。一次遍歷,複雜度是O(n),因為每次操作使得陣列更為有序,不像快速排序需要重複比較,所以效率更高一些.

3.Java程式碼實現

/*思路:
 * 設定三個標記指標:iZero, iOne, iTwo
 * 令iZero從前往後遍歷,指向第一個非0的位置,iTwo從後往前遍歷,指向第一個非2位置然後iOne從iZero開始往後遍歷:
 * 遇到0就和iZero交換,iZero++;遇到1則iOne++;遇到2就和iTwo交換,iTwo向前滑動到下一個非2的位置,交換後還
 * 要重新檢查iOne的值;直到iOne與iTwo相遇。一次遍歷,複雜度是O(n),因為每次操作都是的陣列更為有序,所以效率高一些.
 * Before...
 *1 2 0 0 2 1 2 1 1 0 2 2 1 0 
 *After...
 *0 0 0 0 1 1 1 1 1 2 2 2 2 2 
 */
public class Order {
	public int arr[] = {1,2,0,0,2,1,2,1,1,0,2,2,1,0};
	public int iLength;
	public int iZero, iOne, iTwo;//這三個量表示表示含有0,1,2的各自的數量
	void swap(int x, int y)
	{
		int temp = arr[x];
		arr[x] = arr[y];
		arr[y] = temp;
	}

	void sort()
	{       //希望最左邊是0,從前往後找0
		while(arr[iZero] ==0)
		{
			iZero++;
			iOne++;
		}
		 //希望最右邊是2,從後往前找2
		while(arr[iTwo] == 2)
		{
			iTwo--;
		}
		while(iOne<=iTwo) //想要當前指標與末尾指標相遇
		{      //iOne本質上相當於是當前指標
			//arr[iOne]==2則交換到右邊去,想要iOne指向一個從前向後的為1的位置
			if (arr[iOne]==2) 
			{
				swap(iOne,iTwo);
				//想要iTwo指向一個從後向前的非2的位置
				iTwo--;
				//交換後如果存在arr[iTwo]==2則從後向前移至非2的位置
				while(arr[iTwo]==2)
				{
					iTwo--;
				}
			}
			//arr[iOne]==1只移動不交換
			while(arr[iOne]==1) 
			{
				iOne++;
			}
			//arr[iOne]==0則交換到左邊去,想要iOne指向一個從前向後的為1的位置
			if (arr[iOne]==0)
			{
				swap(iOne, iZero);
				iZero++;
				iOne++;
			}
		}
	}

	public static void main(String[] args) {
		Order order = new Order();
		order.iLength = order.arr.length;
		order.iZero=0;
		order.iOne=0;
		order.iTwo=order.iLength-1;

		System.out.println("Before...");
		for (int i=0;i<order.iLength;i++)
		{
			System.out.print(order.arr[i]+" ");
		}
		order.sort();
		System.out.println("\nAfter...");
		for (int i=0;i<order.iLength;i++)
		{
			System.out.print(order.arr[i]+" ");
		}
	}
}