詳解折半插入排序算法


折半插入排序算法的時間復雜度:O(nlogn)

折半插入排序利用二分法的思想,在一個有序的序列中,找到新元素在該序列中的位置,然后插入。如圖1所示,共有n個元素,前i個元素已經是有序序列,現在要將第i個元素插入其中。折半插入排序需要做兩步工作:找到待插入元素的位置、插入。


圖1 插入排序示意圖


首先要定義兩個指針(不是語法里面的指針,是下標的意思)low和high用於尋找a[i]的插入位置,low指向a[0],high指向a[i-1],中點mid=(low+high)/2,


圖2 “折半”示意圖


如圖2所示二分法的思想是,比較a[i]與a[mid]的大小,若a[i]>a[mid],說明a[i]的位置應該在mid~high之間,將區間[low,high]縮短為[mid+1,high],令指針low=mid+1;若a[i]<=a[mid],說明a[i]的位置應該在low~mid之間,將區間壓縮為[low,mid-1],令指針high=mid-1。每次折半之后,a[i]的位置應該在[low,high]之間。

如此循環,low與high漸漸靠近,直到low>high跳出循環,a[i]的位置找到,low即為a[i]應該放置的位置。

找到a[i]的位置之后進行插入,先將a[low]~a[i-1]這些元素向后平移一個元素的位置,然后將a[i]放到low位置。


用Dev-C++編寫的C++代碼:


#include <iostream>
using namespace std;

void BinSort(int *a,int n) //對int數組進行從小到大的排序 
{
	for(int i=1;i<n;i++) //開始 以a[0]作為有序序列,從a[1]開始找到當前元素a[i]應該放置的位置 
	{
		int low=0,high = i-1,mid;//每次尋找a[i]的位置,都要更新這些數據 
		while(low<=high) //二分思想循環尋找a[i]的位置 
		{
			mid = (low+high) / 2;  
			if(a[i]<=a[mid])
				high = mid - 1;  //high指針減小 
			else
				low = mid + 1;   //low指針增加 
		}  //循環結束,low就是a[i]應該放置的位置 
		
		int temp = a[i];  
		for(int j=i;j>low;j--)  //將元素向后平移
			a[j] = a[j-1];  
		a[low] = temp;   //將元素temp = a[i] 放置到low位置 
	}
}

int main()  //舉例說明
{
	int n = 10;
	int a[10] = {5,8,9,4,7,5,6,3,1,11}; 
	BinSort(a,n);
	for(int i=0;i<n;i++)
		cout << a[i] << " ";
	cout << endl;
	
	return 0;
}

一個細節:為什么內層的循環while(low<=high){...}結束之后以low作為a[i]應該放置的位置?

觀察指針low與high重合之前與之后二者位置變化情況。設low>high的一步為第N步,走到第N步一共有四種情形:


情形一:


第N-2步時,mid=(low+high)/2,如果a[i]>a[mid],low=mid+1,這樣就到了第N-1步,low與high重合,mid=(low+high)/2=low=high,由於a[i]<=a[high]=a[mid]必然成立(否則,a[i]>a[mid]=a[high],那么a[i]放置的位置應該在high之后了,也不會到達這一步),所以high=mid-1,這樣就到了第N步,high<low,退出循環,此時位置high就是第N-2步的位置mid,所以此時,a[high]<a[i]<=a[low],所以low就是a[i]應該放置的位置。


情形二:


第N-2步,mid=(low+high)/2,如果a[i]<=a[mid],high=mid-1,這樣就到了第N-1步,low與high重合,mid=(low+high)/2=low=high,由於a[i]>a[low]=a[mid],所以low=mid+1,這樣就到了第N步,high<low,退出循環,此時位置low就是第N-2步的位置mid,那么此時,a[high]<a[i]<=a[low],所以low就是a[i]應該放置的位置。


情形三:


第N-2步,mid=(low+high)/2=low,如果a[i]>a[mid]=a[low],low=mid+1,這樣就到了第N-1步,low與high重合,mid=low=high,由於a[i]<=a[high]=a[mid],所以,high=mid-1,這樣就到了第三步,high<low,退出循環,此時位置high就是第N-2步的位置low,那么此時,a[high]<a[i]<=a[low],所以low就是a[i]應該放置的位置。


情形四:


第N-1步,mid=(low+high)/2 = low,如果a[i]<=a[mid]=a[low],high=mid-1=low-1,這樣就到了第N步,low>high,退出循環,此時a[high]<a[i]<=a[low],所以low就是a[i]應該放置的位置。

這樣就解釋了為什么退出循環之后,將low作為尋找的位置。


如有錯誤請指正!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM