資料結構演算法-插入排序
插入排序演算法有兩種,一種是直接插入排序,一種是折半插入排序
演算法分析:1.當元素的初始序列為正序時,僅外迴圈要進行n-1趟排序且每一趟只進行一次比較,沒有進入if語句不存在元素之間的交換(移動)。此時比較次數(Cmin)和移動次數(Mmin)達到最小值。
Cmin = n-1Mmin = 0;
此時時間複雜度為O(n)。
2.當元素的初始序列為反序時,每趟排序中待插入的元素都要和[0,i-1]中的i個元素進行比較且要將這i個元素後移(arr[j+1] = arr[j]),i個元素後移移動次數當然也就為i了,再加上temp = arr[i]與arr[j+1] = temp的兩次移動,每趟移動的次數為i+2,此時比較次數(Cmin
Cmax = 1+2+...+(n-1) = n*(n-1)/2 = O(n2)
Mmax = (1+2)+(2+2)+...+(n-1+2) = (n-1)*(n+4)/2 = O(n2) (i取值範圍1~n-1)
此時時間複雜度為O(n2)。
3.在直接插入排序中只使用了i,j,temp這3個輔助元素,與問題規模無關,所以空間複雜度為O(1).
4.在整個排序結束後,即使有相同元素它們的相對位置也沒有發生變化,
如:5,3,2,3排序過程如下
A--3,5,2,3
B--2,3,5,3
C--2,3,3,5
void InsertSort(int a[], int n)
{
for(int i= 1; i<n; i++)
{
if(a[i] < a[i-1])
{
//若第i個元素大於i-1元素,直接插入。小於的話,移動有序表後插入
int j= i-1;
int x = a[i]; //複製為哨兵,即儲存待排序元素
a[i] = a[i-1]; //先後移一個元素
while(x < a[j]) //查詢在有序表的插入位置
{
a[j+1] = a[j];
j--; //元素後移
}
a[j+1] = x; //插入到正確位置
}
}
for(int i=0; i<n; i++)
printf("%d%c",a[i],i==n-1?'\n':' ');
}
折半插入排序:
演算法的基本過程:
1)計算 0 ~ i-1 的中間點,用 i 索引處的元素與中間值進行比較,如果 i 索引處的元素大,說明要插入的這個元素應該在中間值和剛加入i索引之間,反之,就是在剛開始的位置 到中間值的位置,這樣很簡單的完成了折半;
2)在相應的半個範圍裡面找插入的位置時,不斷的用(1)步驟縮小範圍,不停的折半,範圍依次縮小為 1/2 1/4 1/8 .......快速的確定出第 i 個元素要插在什麼地方;
3)確定位置之後,將整個序列後移,並將元素插入到相應位置。
折半插入排序過程:
第一趟:按上述程式碼的流程分析,從A[2]開始計算,{11}是一個已排序子表,按關鍵字13進行折半查詢它的位置,程式碼的上半部分查詢該元素元素應該插入的位置為A[2],所以下半部分並不需要移動元素,已排序子表為{11,13}
第二趟:從A[3]開始計算,low=1,high=2,mid=1,因為7<11,所以high=2-1=1;第二次迴圈mid=1,7<11,high=0,迴圈不滿足條件,此時開始移動元素;要移動的元素範圍為A[1]到A[2],A[1]=7。
第三趟第四趟依此類推…..(只要記住一點,先折半查詢元素的應該插入的位置,然後統一移動應該移動的元素,再將這個元素插入到正確的位置)
void BinaryInsertSort(int array[],int n)//傳遞陣列和陣列元素個數
{
int i,j,mid,low,high,temp;
for(i = 1; i < n; ++i) //我看了一些其他人寫得折半插入演算法是從下標1開始的,i = 2;i <=n,並將array[i]儲存到array[0]
{
temp = array[i];//把第i+1個元素賦值給temp(陣列從下標0開始)
low = 0;//初始化low,array[low]代表陣列中第1個元素
high = i;//初始化high,array[high]代表已插入的最後一個元素
while(low <= high) //不斷的折半1/2 1/4 ....
{
mid = (low + high) / 2;//計算中間位置
if (temp > array[mid])
{
//插入值大於中間值
low = mid + 1;
}
else
{
//插入值小於中間值
high = mid - 1;
}
}
for(j=i-1; j >= low; --j)
{
//將需要移動的陣列向後移
array[j+1] = array[j];
}
//將值插入到指定位置
array[low] = temp;
}
}
兩個者的區別是:折半插入排序基本思想和直接插入排序一樣,區別在於尋找插入位置的方法不同,折半插入排序採用折半查詢法來尋找插入位置。折半查詢法只能對有序的序列使用。基本思想就是查詢插入位置的時候,把序列分成兩半(選擇一箇中間數mid),如果帶插入資料大於mid則到右半部分序列去在進行折半查詢;反之,則到左半部分序列去折半查詢。
折半插入排序在記錄移動次數上和直接插入排序是一樣,所以演算法時間複雜度也是一樣,只是在尋找插入位置的時候可能會節約相當多的時間。