經典演算法之三:插入排序及二分優化
阿新 • • 發佈:2019-01-04
直接插入排序(Insertion Sort)的基本思想是:每次將一個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子序列中的適當位置,直到全部記錄插入完成為止。
設陣列為a[0…n-1]。
1. 初始時,a[0]自成1個有序區,無序區為a[1..n-1]。令i=1
2. 將a[i]併入當前的有序區a[0…i-1]中形成a[0…i]的有序區間。
3. i++並重復第二步直到i==n-1。排序完成。
直接插入排序
基本思想
當插入第i(i≥1)個物件時,前面的V[0],V[1],…,V[i−1]已經排好序。這時,用V[i]的排序碼與V[i−1],V[i−2 ],…,V[0]的排序碼順序進行比較,找到插入位置即將V[i]插入,原來位置上的物件向後順移。
直接插入排序圖示
從上到下,分別展示了直接排序演算法的所有可能的過程,包括相同排序碼的排序方式(保持了原來的順序,說明是穩定排序)以及in-place操作中的元素移動等。
直接插入排序演算法分析
設待排序物件個數為n,則該演算法的主程式執行n−1趟排序碼比較次數和物件移動次數與物件排序碼的初始排列有關。
- 最好情況下,排序前物件已經按照要求的有序。比較次數(KCN):n−1 ; 移動次數(RMN):為0。則對應的時間複雜度為O(n)。
- 最壞情況下,排序前物件為要求的順序的反序。第i
- 如果排序記錄是隨機的,那麼根據概率相同的原則,在平均情況下的排序碼比較次數和物件移動次數約為n24,因此,直接插入排序的時間複雜度為O(n2)。
直接插入排序演算法的特點
- 它是穩定排序,不改變相同元素原來的順序。
- 它是in-place排序,只需要O(1)的額外記憶體空間。
- 它是線上排序,可以邊接收資料邊排序。
- 它跟我們牌撲克牌的方式相似。
- 對小資料集是有效的。
演算法分析
直接插入排序的演算法效能
時間複雜度
當資料正序時,執行效率最好,每次插入都不用移動前面的元素,時間複雜度為O(N)。
當資料反序時,執行效率最差,每次插入都要前面的元素後移,時間複雜度為O(N2)。
所以,資料越接近正序,直接插入排序的演算法效能越好。
空間複雜度
由直接插入排序演算法可知,我們在排序過程中,需要一個臨時變數儲存要插入的值,所以空間複雜度為 1 。
演算法穩定性
直接插入排序的過程中,不需要改變相等數值元素的位置,所以它是穩定的演算法。
完整參考程式碼
直接插入排
完整程式碼:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5;
void Init(int *a,int *b,int n)
{
srand(time(NULL));
for(int i=0; i<n; i++)
b[i]=a[i]=rand()%100;
}
void P(int *a,int n)
{
for(int i=0; i<n; i++)
cout<<a[i]<<" ";
cout<<endl;
}
void Insert_Sort(int *a,int n)
{
int i,j;
for(i=1; i<n; i++)
{
if(a[i]<a[i-1])
{
int t=a[i];
for(j=i-1; j>=0&&a[j]>t; j--)
{
a[j+1]=a[j];
}
a[j+1]=t;
}
//P(a,i);
}
}
//二分優化
void Insert_Sort_Binary(int *a,int n)
{
for(int i=1; i<n; i++)
{
if(a[i]<a[i-1])
{
int left=0;
int right=i-1;
int t=a[i];
while(left<=right)
{
int mid=(left+right)>>1;
if(a[mid]>t)
right=mid-1;
else
left=mid+1;
}
for(int j=i-1; j>=left; j--)
{
a[j+1]=a[j];
}
a[left]=t;
}
//P(a,i);
}
}
int main()
{
int a[MAXN],b[MAXN];
char ch;
do
{
Init(a,b,MAXN);
//P(a,MAXN);
time_t t1=clock();
Insert_Sort(a,MAXN);
time_t t2=clock();
cout<<t2-t1<<endl;
//P(a,MAXN);
//P(b,MAXN);
time_t t3=clock();
Insert_Sort_Binary(b,MAXN);
time_t t4=clock();
cout<<t4-t3<<endl;
//P(b,MAXN);
}
while(ch=getchar());
return 0;
}