排序->內部排序->插入排序
1.直接插入排序
算法思想
每次將一個待排序的記錄按照關鍵字大小插入已排好序的子序列,直到全部記錄插入完成。
實現思路(順序:非遞減有序序列)
1. 記錄當前需要排序元素的位置與大小(設位置為 i,大小為min )
2. 以 i 為分界線,其前為一個有序序列,其后為待排序元素
3. 將 min 與有序序列中的元素進行比較,直到該元素 <= min,否則將該元素后移。
4. 將 min 元素放入有序列表
5. 循環(i++),直到有序
實現代碼
點擊查看代碼
/**
* 插入排序,最普通的實現方法(還有一種帶哨兵的實現方法,就不在此實現了)
* @param arr
*/
public static void InsertSort(int[] arr){
for(int i = 1; i < arr.length; i++){
// 1. 當前需要排列的元素
int value = arr[i];
int j;
// 2. 以當前下標為分界線,前為有序,找到比他更小的元素
for(j = i-1; j >= 0; j--){
if(arr[j] <= value){
break ;
}
// 將比它大的元素后移
arr[j+1] = arr[j];
}
// 3. 將元素放在他應在的位置上
arr[j+1] = value;
}
}
2.折半插入排序
算法思想
在直接插入的基礎上,可以尋找元素在有序表中的位置時使用折半查找的方法,能夠減少時間復雜度。
算法思路
同上,但在進行 3 時使用折半查找的方法。
實現代碼
點擊查看代碼
/**
* 折半插入排序
* 插入排序的一種優化,同樣還有一種帶哨兵的實現方法,不再次實現了。
* @param arr
*/
public static void InsertSortBin(int[] arr){
for(int i = 1; i < arr.length; i++){
int value = arr[i];
int left = 0;
int right = i-1;
int mid;
// 折半查找元素應該在的位置
while (left <= right){
mid = (left+right)/2;
if(arr[mid] <= value){
left = mid+1;
}else {
right = mid-1;
}
}
// 將該位置之后的元素后移
for(int j = i-1; j >= right+1; j--){
arr[j+1] = arr[j];
}
arr[right+1] = value;
}
}
3.希爾排序
算法思想
把待排序表分成若干個等長間隔的子表,對每個子表分別進行插入排序,當整個表中的元素都基本有序時,再對全體記錄進行一次直接插入排序。
算法思路
1.取一個小於n的步長d1,將表中的元素分為d1組,所以距離為d1的元素放在一個組里;
2.組內進行直接插入排序;
3.取第二個步長d2 < d1,重復上述過程,直到dt = 1,再進行直接插入排序。
ps: 到目前為止,還沒有得出最優的增量序列(步長序列),希爾提出的方法是每次折半,即d1 = n/2; d2 = d1/ 2,......直到最后增量等於1。
實現代碼
點擊查看代碼
/**
* 希爾排序
* 第一個結點暫存元素,不參與排序
* @param arr
*/
public static void ShellSort(int[] arr){
for(int d = arr.length/2; d >= 1; d /= 2){
for(int i = d+1; i < arr.length; i++){
if(arr[i] < arr[i-d]){
arr[0] = arr[i];
int j;
for(j = i-d; j > 0 && arr[0] < arr[j]; j -= d){
arr[j+d] = arr[j];
}
arr[j+d] = arr[0];
}
}
}
}
4.其他結論
直接插入排序最壞情況下需要進行的比較次數為:n*(n-1)/2;
直接插入排序屬於穩定排序,而希爾排序屬於不穩定排序;
直接插入的三種排序方法時間復雜度都為O(n^2);