對只含0,1,2三種元素的陣列設計一種O(n)時間的排序演算法
阿新 • • 發佈:2018-11-05
針對只含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]+" "); } } }