最優 o(n)
最差 o(n^2)
平均 o(n^2)
空間 o(1)
穩定排序
插排的思路是保證遍歷到每個元素時,該元素前面的序列都是有序的。基於這個前提,我們將遍歷到的新元素和它前面的序列相比對,然後將這個元素插入到適當的位置,使得這個包含新元素的序列也是有序的。雖然外層遍歷只要o(n)時間,但是因為找到新元素的適當位置後要將之後的所有元素後移,所以最差時間是o(n^2)。
public
class
insertionsort
extends
comparable>
// 較大的元素都後移了一位,這裡只要插入這個新元素,則新序列還是有序的
array[j]=tmp;
}return
array;}}
最優 o(n)
最差 o(n^2)
空間 o(1)
不穩定排序
插排的乙個優化是希爾排序,在原本的插入排序中,我們選擇以乙個乙個往後看等待插入的元素。然而插入排序有這麼乙個性質,即如果序列有序程度越高,則時間複雜度越低。所以希爾排序利用了這個性質,先通過較大的步長進行一次插入排序(不再是乙個乙個往後找待插元素,而是隔乙個或者隔n/2個元素來找),這樣每次子插排都能將序列變得更有序一點,而且因為步長一開始很大,所以要遍歷的數少,時間複雜度也很低。後來步長變小了,要遍歷的數變多了,但陣列也更有序了,時間複雜度也降低了。當然n/2^i這個步長序列不是最好的,最好的步長序列能使最差複雜度降低至o(n(logn)^2)
public
class
shellsort
a[j]=tmp;}}
return a;}}
最優 o(n^2)
最差 o(n^2)
平均 o(n^2)
空間 o(1)
不穩定排序
選排的思路和插排相反,插排是搜尋有序序列找到合適的位置,選排則是搜尋剩餘的無序序列選擇出其中最大(或最小)的,並將這個被選擇的數放到無序序列的首部。需要注意的是。將這個數放到首部時,用的是交換的方法。因為無論如何都要遍歷完子串行,所以時間複雜度至少是o(n^2)
public
class
selectionsort
extends
comparable>
// 將這個最小的交換到無序序列的首部
if (minindex != i)
}return a;}}
最優 o(nlogn)
最差 o(nlogn)
平均 o(nlogn)
空間 o(n)
穩定排序
歸併排序是典型的分治法。基本思路是將乙個較長陣列一分為二,我們將它的左右兩半部分分別排好序,然後將這有序的兩部分合併起來,這樣較長陣列也是有序的了。因為兩半部分都是有序的,所以合併只需要同時遍歷一下兩半部分,看誰較小(大)就把誰先塞進陣列就可以了。根據這個思路,我們不停的二分、二分,這樣二分到盡頭肯定只有乙個數的陣列,那它肯定是有序的,然後我們將兩個只有乙個數的陣列合併,只要比較下這兩個數就行了。這樣就返回了乙個有兩個數的有序陣列,然後再一直合併、合併、直到合併出整個陣列。不過,在合併兩個子陣列時,要先用乙個臨時陣列存放,否則會修改兩個子陣列的資料(因為兩個子陣列實際上是原陣列的兩個子部分)。
public
class
mergesort
extends
comparable
super
t>>
return array;
}public
static
super t>> t sort(t a)
private
static
super t>> void
merge
(t a, t tmparray, int leftpos, int rightpos, int rightend)
// 如果左半部分沒有合併完(說明右半部分的數較小),將其合併進去
while(leftpos<=leftend)
// 如果右半部分沒有合併完(說明左半部分的數較小),將其合併進去
while(rightpos<=rightend)
// 將這個臨時陣列拷貝回原陣列
for(int i = 0;i
最優 o(nlogn)
最差 o(n^2)
平均 o(nlogn)
空間 o(logn)
不穩定排序
快速排序也是分治的思想,它先選取乙個樞紐值pivot,將整個陣列按照樞紐值的大小重新排列,比樞紐值小的放在左邊,比樞紐值大的放在右邊。然後,我們再分別對這左半部分和右半部分進行同樣的操作,這裡半個部分不一定有半個陣列的元素,要看具體有多少元素大於或小於樞紐值。一般情況下我們都選擇子陣列的第乙個值作為樞紐,簡化實現。最好還是能寫個隨機選擇樞紐值的函式。最差的情況下,每次選到的樞紐值都是最小(最大)的,所以每次分割出來的子陣列都只比當前整個陣列小1的長度,就會導致o(n^2)的複雜度。
public
class
quicksort
private
super t>> t sort(t a, int left, int right)
private
super t>> int
partition
(t a, int left, int right)
while(a[j].compareto(p)>0 && j>i);
//swap a[i] and a[j] to partition
while(i// 將右邊那個小於樞紐值的數和左邊那個大於樞紐值的數交換(第一次交換的是樞紐值本身)
swap(a,i,j);
// 找到下一對可以交換的元素
dowhile(a[i].compareto(p)<0);
dowhile(a[j].compareto(p)>0);
}//elements before j+1 are partitioned, so we need to partition next part start from j+1
return j+1;
}private
super t>> void
swap
(t a, int i, int j)
}
假設我們有1tb的資料需要排序,但是只有一台1gb記憶體的機器,請問如何排序?外部排序基於歸併排序的理念,以該題為例,為了計算方便我們假設tb/gb/mb是以1000換算的,而且記憶體也有1.001g空間:
將1tb資料分1000次讀入記憶體中,每次對1gb的資料進行排序,每次排序完將其作為乙個區塊結果存入磁碟中。
在記憶體中劃分1000個通道,每個通道讀入每個區塊前1mb的資料,可知每個1mb都是有序的。
對這1000個有序的1mb資料進行歸併。將結果存入乙個1mb的快取當中,每當這1mb快取滿的時候,將這1mb快取存入磁碟並清空。每當任何乙個1mb通道空時,我們將對應區塊的下1mb資料讀入這個通道。
持續執行步驟3直到所有區塊的資料都被讀完,這時候磁碟中就是1tb有序的資料了。
常見排序演算法
一.選擇排序 1.概念 每次從無序的子陣列裡面選擇最小的數,放在有序區的後面 既與無序區的首元素交換 不穩定排序 時間複雜度o n 2 輔助儲存o 1 2.實現 int selection sort int a,int len len為陣列元素個數 二.氣泡排序 1.概念 重複訪問數列n 1次,每次...
常見排序演算法
1 插入排序 直接插入排序,是一種最簡單的排序方法,它的基本操作是將乙個記錄插入到已排好序的有序表中,從而得到乙個新的 記錄數增1的有序表。初始 38 65 27 76 13 i 1 13 選13為監視哨並假設為乙個有序序列 i 2 13 38 待插入元素38 13 i 3 13 38 65 待插入...
常見排序演算法
排序演算法作為常用的基本演算法,今天就來總結一下各種經典排序演算法,這裡只貼出 對演算法的文字描述可以在課本或其它部落格上找到很多詳盡的敘述,這裡直接上 而不是常見演算法書上的偽 希望對正在努力學資料結構與演算法的朋友們有幫助 1 氣泡排序 void bubblesort t a,int n if ...