插入排序與選擇排序
在學習過程中我總是難以分清選擇排序與插入排序的區別所在。粗看兩個算法的實現原理,都是從數組的無序范圍內選擇一個元素,放入我們所維護的不斷擴大的數組的有序范圍中。為了區分兩者的不同,並加深自己對插入排序和選擇排序的理解,故有此文。
直接插入排序(Insertion Sort)
直接插入排序算法是一種穩定的、原地的排序算法,算法的時間復雜度為\(O(n^2)\)。
基本思想
每次將一個待排序的記錄按其關鍵字大小插入到前面已經排好序的子表中的適當位置,直到全部記錄插入完成為止。
實現(升序)
每一趟從無序范圍中取出第一個數\(a\),在有序范圍中將比\(a\)大的數全部移動一位,直到在有序范圍內遍歷的數比\(a\)小,再將\(a\)插入到該數之后。
void InsertionSort(int a[], int len)
{
int temp;
for(int i = 1; i < len; i++)
{
temp = a[i];
int j = i - 1;
while(j >= 0 && a[j] > temp)
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = temp;
}
}
最好情況與最壞情況
- 最好情況出現在數組已經正序有序的情況下。此時對數組進行排序,不會進入到while循環中,相當於遍歷了一次數組,時間復雜度為\(O(n)\)。
- 最壞情況出現在逆序有序的情況下。此時對數組進行排序,每次都會進入到while循環中,並且每次都會從有序范圍的尾部遍歷到有序范圍的首部,時間復雜度為\(O(n^2)\)。
簡單選擇排序(Selection Sort)
簡單選擇排序算法是一種不穩定的、原地的排序算法,算法的時間復雜度為\(O(n^2)\)。
思想
每一趟都選擇出一個最大或最小的元素,並放在合適的位置。
實現(升序)
每一趟從無序范圍中選擇最小的數\(a\),並將\(a\)放入有序范圍中的最后一個位置。
void SelectionSort(int a[], int len)
{
for(int i = 0; i < len; i++)
{
int min = i; // min記錄無序范圍最小元素的下標
for(int j = i + 1; j < len; j ++)
{
if(a[j] < a[min])
{
min = j;
}
}
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
最好情況與最壞情況
選擇排序沒有最好情況與最壞情況之分,無論數組有序與否,排序算法都需要進入到第二個for循環中遍歷數組的無序部分找出最小元素,時間復雜度為\(O(n^2)\)。
插入排序與選擇排序的異同
如前言所述,兩算法都是從無序范圍取數,放置到有序范圍中,但兩者依舊有不小的區別。
- 插入排序算法是從無序范圍中取出第一個數,在有序范圍中尋找合適的位置,將位置往右的元素全部右移一位,再將數插入到數組中。
- 選擇排序算法是從無序范圍中取出最大或最小的數,插入到有序范圍中的最后一個位置。
如此來看,兩算法的大體思路略有相似,但具體的實現細節是不同的。