三種常見排序方法
一、選擇排序法
1.1 可看可不看
在瞭解這三種排序演算法前,先解釋一個概念:牆(wall)。
- 在這三中排序演算法中,為了區分已排序序列與未排序序列,於是我們設定一堵牆把它們區分開來。
- 這堵牆的具體表現形式為它限制了排序的可操作範圍,在程式中表現為在迴圈中變數的取值範圍。
如:
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
//......
}
}
在這段程式碼中,隨著i的變化,每次j的初值都會發生變化,內層迴圈的次數也發生了變化。這個過程就像一堵無形的牆在不斷移動,從而限制了行動。(這個概念不急於理解,觀看以下內容,便不難理解)
1.2 演算法描述
1.2.1 演算法思想
選擇排序的基本思想是:每一趟在n-i+1(i=1,2,…n-1)個記錄中選取關鍵字最小的記錄作為有序序列中第i個記錄。
簡單來講,給定n個無序的數
第一趟:在這n個數中求得最小值,將其放在序列最左邊。
第二趟:在除第一個已排列好的數外的其它n-1個數繼續求最小值,放在第二個位置。
第三躺:在除已排列好的兩個數外的其它n-2個數中求最小值,放在第三個位置。
…
1.2.2 動圖演示
1.2.3 例子
以下例子中的 “{” 就相當於是牆,牆左邊是已排序部分,牆右邊是未排序部分。
0 | 初始序列:{ 49 27 65 97 76 12 38 } |
---|---|
1 | 12與49交換:12 { 27 65 97 76 49 38 } |
2 | 27不動 :12 27 { 65 97 76 49 38 } |
3 | 65與38交換:12 27 38 { 97 76 49 65 } |
4 | 97與49交換:12 27 38 49 { 76 97 65 } |
5 | 65與76交換:12 27 38 49 65 { 97 76 } |
6 | 97與76交換:12 27 38 49 65 76 97 |
1.2.4 流程圖
1.2.5 程式碼示例
void selection(int a[], int n)
{
int i, j, temp;
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
二、氣泡排序法
2.1演算法思想
1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2.對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最後一對。
3.在這一點,最後的元素應該會是最大的數。
4.針對所有的元素重複以上的步驟,除了最後一個。
5.持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較
2.2 動圖演示
2.3 例子
從左往右排序和從右往左排序都可行,以下例子為從右到左排序。
0 | 原始序列: { 23,78,45,8,32,56 } |
---|---|
1.1 | 45與8交換:{ 23 78 8 45 32 56 } |
1.2 | 78與8交換:{ 23 8 78 45 32 56 } |
1.3 | 23與8交換:8 { 23 78 45 32 56 } |
2 | 8 23 { 32 78 45 56 } |
3 | 8 23 32 { 45 78 56 } |
4 | 8 23 32 45 { 56 78 } |
5 | 8 23 32 45 56 78 |
2.4 流程圖
以下流程圖中出現的概念與上一張相同。
2.5 程式碼示例
void bubble(int a[], int n)
{
int i, j,temp;
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
三、插入排序法
3.1演算法描述
1.從第一個元素開始,該元素可以認為已經被排序
2.取出下一個元素,在已經排序的元素序列中從後向前掃描
3.如果該元素(已排序)大於新元素,將該元素移到下一位置
4.重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
5.將新元素插入到該位置後
6.重複步驟2~5
插入排序法的步驟就像我們平時玩卡牌遊戲的時候對卡牌進行排序的步驟:拿出一張牌,尋找正確的位置插入。
3.2 動圖演示
3.3 例子
0 | 原始序列: 23 { 78 45 8 32 56 } |
---|---|
1 | 23 78 { 45 8 32 56 } |
2 | 23 45 78 { 8 32 56 } |
3 | 8 23 45 78 { 32 56 } |
4 | 8 23 32 45 78 {56} |
5 | 8 23 32 45 56 78 |
3.4 流程圖
注: Found 起標記作用,用來判斷是否需要執行內迴圈。
3.5 程式碼示例
void insert(int a[], int n)
{
for (int i = 1; i < n; i++)
{
int temp = a[i], j;
for (j = i; j > 0 && temp < a[j - 1]; j--)
{
a[j] = a[j - 1];
}
a[j] = temp;
}
}