【排序】折半插入排序

目錄

折半插入排序原理

折半插入排序圖文說明

代碼實現

C實現

 JAVA實現

 複雜度分析和穩定性

複雜度

穩定性

總結


折半插入排序原理

折半插入排序是對直接插入排序的一種改良方式,在直接插入排序中,每次向已排序序列中插入元素時,都要去尋找插入元素的合適位置,但是這個過程是從已排序序列的最後開始逐一去比較大小的,這其實很是浪費,因爲每比較一次緊接着就是元素的移動。折半排序就是通過折半的方式去找到合適的位置,然後一次性進行移動,爲插入的元素騰出位置。什麼是折半的方式去找合適的位置呢,那就是折半查找了,因爲再已排序的序列中,序列元素都是按照順序排列的,既然這樣,完全不需要逐一去比較大小,而是去比較已排序序列的中位數,這個中間的位置將一排序列分爲左右兩部分,通過一次比較後,就縮小了比較的範圍,重複這樣的操作,需要插入的元素就找到了合適的位置了。

折半插入排序圖文說明

注:藍色代表已排序序列,白色代表未排序序列,紅色箭頭指向未排序序列的第一個元素位置。

 

如圖所示,現在有一個待排序序列[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=-1low=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));
    }
}

 測試結果

 複雜度分析和穩定性

複雜度

和直接插入排序相比較,折半插入排序僅僅是減少了比較的次數,而移動總次數並沒有發生改變。這個比較次數大概是O(nlogn),移動次數沒有改變,所以其複雜度和直接插入排序是一樣的O(N^{2})

穩定性

根據代碼分析可以知道,當待插入數與mid位置的值相等時,接下來相當於進入了有序序列的右半區,mid+1到high,之後經過多次折半查找,該元素所找到的合適位置就是前一個與之相等元素的後一位,所以說兩者相對位置沒有發生變化,這般插入排序是穩定的。

總結

折半插入排序其實是在直接插入排序的基礎上,結合了二分查找法的思想,順序的二分查找替代了直接插入排序中遍歷查找的過程,從而更快的能夠確定待插入元素的位置,但是由於移動次數並沒有發生改變,所以兩者的時間複雜度相同。折半插入排序是穩定的,其時間複雜度爲O(N^{2})

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章