目錄
折半插入排序原理
折半插入排序是對直接插入排序的一種改良方式,在直接插入排序中,每次向已排序序列中插入元素時,都要去尋找插入元素的合適位置,但是這個過程是從已排序序列的最後開始逐一去比較大小的,這其實很是浪費,因爲每比較一次緊接着就是元素的移動。折半排序就是通過折半的方式去找到合適的位置,然後一次性進行移動,爲插入的元素騰出位置。什麼是折半的方式去找合適的位置呢,那就是折半查找了,因爲再已排序的序列中,序列元素都是按照順序排列的,既然這樣,完全不需要逐一去比較大小,而是去比較已排序序列的中位數,這個中間的位置將一排序列分爲左右兩部分,通過一次比較後,就縮小了比較的範圍,重複這樣的操作,需要插入的元素就找到了合適的位置了。
折半插入排序圖文說明
注:藍色代表已排序序列,白色代表未排序序列,紅色箭頭指向未排序序列的第一個元素位置。
如圖所示,現在有一個待排序序列[8 5 4 2 3],首先默認初始狀態下,位置0的數字8作爲已排序序列[8],位置1--位置4的[5 4 2 3 1] 爲待排序序列,之後就逐一從[5 4 2 3 1]中取出數字向前進行比較,插入到已排序序列的合適位置。尋找過程中將藍色的已排序區域不斷進行折半。
初始狀態下,已排序區只有一個數據元素8,low位置和high位置都指向了該位置,mid爲中間位置,此時很顯然也是0位(0+0)/ 2。此時temp < mid,將high指向mid的前一位,這裏也就是-1,這個時候high=-1,low=1,很顯然high<low,每當這個時候,就到了移動元素的時候了,將(high+1)到(i-1)的元素都向後移一位,再把(high+1)位置上插入要插入的元素。
之後的操作也是這樣類似的,詳細過程如下圖。
代碼實現
C實現
代碼:
#include <stdio.h>
void insertSort(int array[], int n){
int temp;
for(int i = 1; i < n; i++){
int low = 0;
int hight = i-1;
temp = array[i];
while(hight>=low){
int mid = ( low + hight ) / 2;
if (array[mid] > temp){
hight = mid - 1;
}else{
low = mid + 1;
}
}
for (int j = i-1; j > hight; j--) {
array[j+1] = array[j];
}
array[hight+1] = temp;
}
}
void main(){
int i;
int a[8] = { 8, 5, 4, 3, 2, 1, 6, 7 };
printf("before:{");
for(i = 0; i < 8; i++){
printf("%d ",a[i]);
}
printf("}\n");
insertSort(a,8);
printf("after:{");
for(i = 0; i < 8; i++){
printf("%d ",a[i]);
}
printf("}\n");
}
測試結果:
JAVA實現
代碼:
/**
* Created by GFC on 2018/8/29.
*/
public class HalfSearchSort {
public void sort(int[] array){
int temp;
for(int i = 1; i < array.length; i++){
int low = 0;
int hight = i-1;
temp = array[i];
while(hight>=low){
int mid = ( low + hight ) / 2;
if (array[mid] > temp){
hight = mid - 1;
}else{
low = mid + 1;
}
}
for (int j = i-1; j > hight; j--) {
array[j+1] = array[j];
}
array[hight+1] = temp;
}
}
public static void main(String[] args) {
HalfSearchSort sort = new HalfSearchSort();
int a[] = {8, 5, 4, 3, 2, 1, 6, 7};
System.out.println("Before: " + Arrays.toString(a));
//System.out.println(5/2);
sort.sort(a);
System.out.println("After: " + Arrays.toString(a));
}
}
測試結果:
複雜度分析和穩定性
複雜度
和直接插入排序相比較,折半插入排序僅僅是減少了比較的次數,而移動總次數並沒有發生改變。這個比較次數大概是,移動次數沒有改變,所以其複雜度和直接插入排序是一樣的。
穩定性
根據代碼分析可以知道,當待插入數與mid位置的值相等時,接下來相當於進入了有序序列的右半區,mid+1到high,之後經過多次折半查找,該元素所找到的合適位置就是前一個與之相等元素的後一位,所以說兩者相對位置沒有發生變化,這般插入排序是穩定的。
總結
折半插入排序其實是在直接插入排序的基礎上,結合了二分查找法的思想,順序的二分查找替代了直接插入排序中遍歷查找的過程,從而更快的能夠確定待插入元素的位置,但是由於移動次數並沒有發生改變,所以兩者的時間複雜度相同。折半插入排序是穩定的,其時間複雜度爲。