資料結構和設計模式03(排序)

2021-07-03 22:58:15 字數 4137 閱讀 2619

首先看一下各大排序演算法的時間空間複雜度:

1.快速排序

偽**如下

void quick_sort (int a, int p, int r)  

}

其中,partion()函式是重點,主要思想如下圖。

注意:返回值是位置(下標),因為快排是就地排序,所以函式引數為原來陣列,輸出還是原來陣列(排好序)。

上圖的主要在於:1)遞迴函式終止條件p;

2)用i,j來記錄每次排序乙個元素後,大於key和小於關鍵字的尾部位置。

理解以上兩點程式設計很容易,此處略。

2.氣泡排序

關鍵:每次兩兩比較,不滿足不等式,則交換位置(由此可知是雙重for迴圈解決問題),所以每次只能選出乙個最大(或者最小)。理解原理後,**也很簡單,略。示意例子如下:

原始待排序陣列| 6 | 2 | 4 | 1 | 5 | 9 |

第一趟排序(外迴圈)

第一次兩兩比較6 > 2交換(內迴圈)

交換前狀態| 6 | 2 | 4 | 1 | 5 | 9 |

交換後狀態| 2 | 6 | 4 | 1 | 5 | 9 |

第二次兩兩比較,6 > 4交換

交換前狀態| 2 | 6 | 4 | 1 | 5 | 9 |

交換後狀態| 2 | 4 | 6 | 1 | 5 | 9 |

第三次兩兩比較,6 > 1交換

交換前狀態| 2 | 4 | 6 | 1 | 5 | 9 |

交換後狀態| 2 | 4 | 1 | 6 | 5 | 9 |

第四次兩兩比較,6 > 5交換

交換前狀態| 2 | 4 | 1 | 6 | 5 | 9 |

交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |

第五次兩兩比較,6 < 9不交換

交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |

交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |

第二趟排序(外迴圈)

第一次兩兩比較2 < 4不交換

交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |

交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |

第二次兩兩比較,4 > 1交換

交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 | 

交換後狀態| 2 | 1 | 4 | 5 | 6 | 9 |

...第三趟排序(...)

第四趟排序(外迴圈)無交換

第五趟排序(外迴圈)無交換

排序完畢,輸出最終結果1 2 4 5 6 9

3.希爾(shell)排序

希爾排序shell sort是基於插入排序

的一種改進,同樣分成兩部分,

第一部分,希爾排序介紹

第二部分,如何選取關鍵字,選取關鍵字是希爾排序的關鍵

第一塊希爾排序介紹

準備待排陣列[6 2 4 1 5 9]

首先需要選取關鍵字,例如關鍵是3和1(第一步分成三組,第二步分成一組),那麼待排陣列分成了以下三個虛擬組:

[6 1]一組

[2 5]二組

[4 9]三組

看仔細啊,不是臨近的兩個數字分組,而是3(分成了三組)的倍數的數字分成了一組,

就是每隔2個數取乙個,每隔2個再取乙個,這樣取出來的數字放到一組,

把它們當成一組,但不實際分組,只是當成一組來看,所以上邊的"組"實際上並不存在,只是為了說明分組關係

對以上三組分別進行插入排序

變成下邊這樣

[1 6] [2 5] [4 9]

具體過程:

[6 1]6和1交換變成[1 6]

[2 5]2與5不動還是[2 5]

[4 9]4與9不動還是[4 9]

第一趟排序狀態演示:

待排陣列:[6 2 4 1 5 9]

排後陣列:[1 2 4 6 5 9]

第二趟關鍵字取的是1,即每隔0個取乙個組成新陣列,實際上就是只有一組啦,隔一取一就全部取出來了嘛

此時待排陣列為:[1 2 4 6 5 9]

直接對它進行插入排序

還記得插入排序

怎麼排不(就是玩撲克插入牌)?複習一下

[1 2 4]都不用動,過程省略,到5的時候,將5取出,在前邊的有序陣列裡找到適合它的位置插入,就是4後邊,6前邊

後邊的也不用改,所以排序完畢

順序輸出結果:[1 2 4 5 6 9]

第二塊希爾排序的關鍵是如何取關鍵字,因為其它內容與插入排序一樣

增量的取值規則為第一次取總長度的一半,第二次取一半的一半,依次累推直到1為止,剛從下文中看到的這一段描述,感謝!

3.選擇排序:

選擇排序的思想非常直接,不是要排序麼?那好,我就從所有序列中先找到最小的,然後放到第乙個位置。之後再看剩餘元素中最小的,放到第二個位置……以此類推,就可以完成整個的排序工作了。可以很清楚的發現,選擇排序是固定位置,找元素。相比於插入排序的固定元素找位置,是兩種思維方式。不過條條大路通羅馬,兩者的目的是一樣的。

4.歸併排序

原理:將原序列劃分為有序的兩個序列,然後利用歸併演算法進行合併,合併之後即為有序序列。

要點:歸併、分治(分治很簡單,注意終止條件,合併是重點)

void mergesort(node l, int m, int n)

}

5.基排序原理:將數字按位數劃分出n個關鍵字,每次針對乙個關鍵字進行排序,然後針對排序後的序列進行下乙個關鍵字的排序,迴圈至所有關鍵字都使用過則排序完成。

要點:對關鍵字的選取(先排低位,後排高位),元素分配收集。

6.堆排序

堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從r[1...n]中選擇最大記錄,需比較n-1次,然後從r[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。

堆排序的重點:就地排序,

下標的推算關係(下面的例子都是堆頂下標為1開始)

parent(i)

return |_ i/2 _|;

left(i)

return 2*i;

right(i)

return 2*i + 1;

給定乙個陣列a[1...n];則

a[( |_ n/2 _| +1)...n]
全是樹中的葉子。明白以上兩點很重要,下面介紹保持堆的性質:

void max_heapify(int *a, int heap_size, int i)   //i 為待處理保持性質的結點下標

if(r < heap_size && a[largest] < a[r]) //右孩子數值大

if(largest != i)

}

基本思路,從下標i開始,比較a[i],left[i]和right[i],選出最大的值作為父節點,被交換的子節點再一次迭代(如果沒有進行交換,演算法停止)。

有了保持堆的性質,則對堆的每乙個非葉子節點,從下往上呼叫max_heapify則就建立乙個堆。

void build_max_heap(int *a, int array_size, int heap_size)

}

建立了堆後,就可以進行堆排序了:根節點和堆尾節點(葉子)交換位置,然後呼叫max_heapify,重複這個過程。

資料結構1 排序

就算複習再緊張,也要動手實踐資料結構中的基本演算法,徹底理解演算法的本質。不要讓任何理由成為不程式設計的藉口。從快速排序開始,將演算法問題一一攻克。複習提綱 基本資料結構 棧和佇列,陣列和鍊錶 樹和二叉樹 二叉查詢樹 平衡二叉樹 雜湊表 排序演算法 選擇排序 氣泡排序和快速排序 堆和堆排序 計數排序...

資料結構 07 排序

簡單的排序方法 氣泡排序 選擇排序 插入排序 希爾排序。先進的排序方法 歸併排序 快速排序 堆排序 基數排序。1.演算法思想 每次在未排序的元素中兩兩比較找最大值,邊找邊從後往前儲存 未排序.第i大 第2大 第1大 一般情況,整個氣泡排序只需進行 k 1 k氣泡排序結束的條件是 在某一趟排序過程中沒...

資料結構7 排序

理解選擇排序的不穩定性 選擇排序 氣泡排序 插入排序 public int charusort int intarr for int i 1 i intarr.length i return intarr 正確性檢測 test public void sorttest system.out.prin...