常用基本排序演算法

2021-09-18 02:16:26 字數 4151 閱讀 8039

擷取自:

演算法複雜度:

擷取自:

文章參考了:

所需輔助空間最多:歸併排序

所需輔助空間最少:堆排序

平均速度最快:快速排序

不穩定:快速排序,希爾排序,堆排序。

氣泡排序應該屬於最簡單的排序演算法了。氣泡排序其實就是通過比較相鄰位置的元素大小,如果左邊比右邊大,就交換位置,繼續比較,實際上就是每輪比較都得出乙個最大值(或者最小值)。然後通過n-1輪比較,就能得出乙個排好序的序列(通過設定乙個flag,當陣列基本有序的時候其實不一定需要比較到n-1輪)。

具體**:

// 1.氣泡排序

// 其實就是通過比較相鄰位置的元素大小,如果左邊比右邊大,就交換位置,繼續比較,實際上就是每輪比較都得出乙個最大值(或者最小值)

// 然後通過n-1輪比較,就能得出乙個排好序的序列(通過設定乙個flag,當陣列基本有序的時候其實不一定需要比較到n-1輪)

public static void bubblesort(int a) }}

}

快速排序簡單來講就是我們選定乙個數,然後比它小的都放在它左邊,大於等於它的都放在它右邊,那麼這個時候對這個數來講他的位置已經排到了正確的地方了,接下來要做的就是在它的左右兩邊分別再進行類似操作。

具體**如下:

// 2.快速排序

// a為待排序的陣列,l,r為陣列下標(l:left,r:right)

// 該函式的作用是對陣列a從下標「l」到下標「r」這部分進行排序

// 注意,當我們呼叫此方法的時候1應該傳0,r應該傳a.length - 1

public static void quicksort(int a, int l, int r)

a[i] = a[j];

// 從左往右尋找第乙個大於等於x的那個數

while (i < j && a[i] <= x)

a[j] = a[i];

}// 將數值x插入到其應該位於的位置(此時i==j,當然也可以用a[j] = x)

a[i] = x;

// 現在我們只是找到了乙個數所屬的位置,接下來我們需要在其兩邊分別再次進行類似尋找

// 進行遞迴呼叫

quicksort(a, i + 1, r);

quicksort(a, l, i - 1);}}

直接插入排序就是我們不斷的將數插入乙個已經排好序的數列中,形成新的數列,當我們從第乙個(準確講應該是從第二個數)開始不斷插入,直到把所有的數都插入了進去,這是我們就得到了乙個有序的數列,或者說是陣列。

具體**:

// 3.直接插入排序

// 其實就是將元素乙個個插入乙個已經排好序了的序列中,形成新的有序序列,

// 剛開始排序的時候,我們實際上認為只有乙個元素的時候其本身是有序的,

// 通過比較第二個元素與第乙個元素的大小來決定插入其左邊或者右邊,以此類推...

public static void insertsort(int a)

// 將temp賦給j+1,是因為在迴圈中有「j--」,當不滿足的時候其實下標j已經個指向了我們需要插入位置的前乙個元素了

a[j + 1] = temp;}}

希爾排序又稱為減小增量排序,實際上就是「分組+直接插入排序」,我們將一組陣列分成一定的組,然後每組分別進行直接插入排序,這樣對每個組而言得到的都是排好了序的數列,然後我們再將分的組的數量逐漸減小,這樣每個組內相鄰元素的間隔也會減小(組數=組距),當然,這裡的組數比較通常的叫法叫「步長」,或者說是「gap」.組數會越來越小,當最後只有一組的時候,我們在經過一輪比較之後就將整個陣列排好序了(注意,當組距為1的時候還沒有排好)

具體**:

// 4.希爾排序(最小增量排序),它的本質其實就是「分組+直接插入排序」

// 希爾排序實際上就是不斷的減小步長(gap),其實就是組距,也就是乙個組內,兩個相鄰元素的間距,然後對每乙個組進行直接插入排序

// 這個gap=組距=組數

// 我們不斷的減小步長,當步長為1的時候,這時我們就只剩下乙個組了,而這時通過比較相鄰元素的大小,我們就可以得到

// 最終的有序序列

public static void shellsort(int a)

a[j + gap] = temp;}}

}

簡單選擇排序其實跟氣泡排序有點相似,也是每一趟比較都能得到乙個最大或者最小值,只不過氣泡排序是依次進行相鄰元素的比較並且交換,來實現類似生活中「冒泡」的效果,而簡單選擇排序的不同點就在於,雖然它也進行依次比較,但是它並不是頻繁的進行交換操作,而是不斷的記下已經比較過的數中的最大值的下標,比較的時候就是通過這個下標代表的值來進行比較,最後把那個得到最大值賦值給該趟比較的陣列的最後後一位,如此迴圈n-1次(改進的話可能需要的次數更少),就可以講乙個陣列排好序。

具體**:

// 5.簡單選擇排序

// 在要排序的一組數中,選出最小的乙個數與第乙個位置的數交換;

// 然後在剩下的數當中再找最小的與第二個位置的數交換,如此迴圈到倒數第二個數和最後乙個數比較為止。

public static void selectsort(int a)

}if (minid != i-1) }}

二叉樹,顧名思義乙個節點最多只能有兩個子節點,而完全二叉樹就是除了最後一層之外,每一層個都是滿的,就是說除最後一層之外,剩餘節點組成的數是個滿二叉樹。而我們這裡要用到的堆,它就是乙個完全二叉樹。

我們從根節點開始,逐層(每層從左到右)開始編號,0,1,2,3,...這樣,我們就可以將乙個堆這種資料結構存放到乙個陣列中。如果某個節點的下標為i,那麼他的左根節點下標就為2i+1,右根節點就為2i+2,而我們常用到的堆為大頂堆(和小頂堆),大頂堆的定義簡單來講就是父節點的值總比其子節點的值要大。

好啦,至此我們就粗略的說完了這些簡單概念(沒學過的同學可以看下《資料結構》相關知識)

可能很多正在看這篇文章的同學跟我最初接觸堆排序的時候的一樣,有個相同的疑惑:這堆排來排去有什麼用,也沒見陣列有序,不久得到了乙個最大值嘛...對,重點就在這個最大值。聽我給你細細道來...

那麼接下來我們就來具體看下堆排序的思想及具體實現步驟:

1.由給定的陣列構建乙個大頂堆,這時我們其實就已經得到了這個陣列中最大值了(下標為0的那個元素,也就是堆頂元素,或者說根節點)

最大值?回想一下氣泡排序和簡單選擇排序,有沒有發現什麼相同點?對的,那兩個也是最大值。其實這裡跟那兩個算分的思想也有點相同,也是每次都獲取到乙個最大值。不同點嘛,看下一條..

2.將那個最大值和陣列的最後乙個元素交換位置

此時最後乙個元素就變成了最大值了

3.將最後乙個元素(現在已經為最大值了)之前的這些元素組成的陣列重新構造乙個大頂堆(因為順序已經發生了變化)

4.如此迴圈,一次次取出最大值,並且重新構造大頂堆,最終也就實現了陣列的排序

具體**:

public class heapsort 

}/**

* 構建堆的過程

* * @param arr

* 需要進行排序的陣列

* @param i

* 需要以該下標表示的節點為堆頂元素,構建大頂堆

* @param n

* 陣列的長度

*/private static void heapadjust(int arr, int i, int n)

// 將當前節點的值和其子節點中值最大的節點進行比較,如果小於最大子節點中最大值,就教過二者交換

if (arr[current] < arr[child]) }}

// 交換陣列中兩個元素的位置

public static void swap(int arr, int index1, int index2)

}

基本排序排序演算法

時空複雜度 氣泡排序 時間o n 2 額外空間o 1 插入排序 時間o n 2 額外空間o 1 選擇排序 時間o n 2 額外空間o 1 基數排序 時間o k n k logn max 額外空間o n 臨時儲存 o b 記數,b為基的大小 記數排序 時間o n k 額外空間o k 希爾排序 時間o ...

基本排序排序演算法

時空複雜度 氣泡排序 時間o n 2 額外空間o 1 插入排序 時間o n 2 額外空間o 1 選擇排序 時間o n 2 額外空間o 1 基數排序 時間o k n k logn max 額外空間o n 臨時儲存 o b 記數,b為基的大小 記數排序 時間o n k 額外空間o k 希爾排序 時間o ...

基本排序演算法

將要排序的物件分作兩部份,乙個是已排序的,乙個是未排序的,從後端未排序部份選擇乙個最小值,並放入前端已排序部份的最後乙個,例如 排序前 70 80 31 37 10 1 48 60 33 80 1 80 31 37 10 70 48 60 33 80 選出最小值1 1 10 31 37 80 70 ...