经典排序算法学习笔记三——插入排序
插入排序
工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
数据结构 | 数组 |
---|---|
最差时间复杂度 | O(n^2) |
最优时间复杂度 | O(n) |
平均时间复杂度 | O(n^2) |
最差空间复杂度 | 总共 O(n) ,需要辅助空间O(1) |
1、算法思想
插入排序都采用in-place在数组上实现。
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
2、伪代码
mark first element as sorted for each unsorted element 'extract' the element for i = lastSortedIndex to 0 if currentSortedElement > extractedElement move sorted element to the right by 1 else: insert extracted element
3、C实现
void insertion_sort(int arr[], int len) { int i, j; int temp; for (i = 1; i < len; i++) { temp = arr[i]; //與已排序的數逐一比較,大於temp時,該數向後移 for (j = i - 1; j >= 0 && arr[j] > temp; j--) //j循环到-1时,由于[[短路求值]](http://zh.wikipedia.org/wiki/短路求值),不会运算array[-1] arr[j + 1] = arr[j]; arr[j+1] = temp; //被排序数放到正确的位置 } }
C++实现
template<typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定大於(>)的運算子功能 void insertion_sort(T arr[], int len) { int i, j; T temp; for (i = 1; i < len; i++) { temp = arr[i]; for (j = i - 1; j >= 0 && arr[j] > temp; j--) arr[j + 1] = arr[j]; arr[i-1] = temp; } }
4、复杂度分析
(1)时间复杂度
初始状态( n项) 正序 反序 无序(平均) 第i趟比较次数 1 i / 总比较次数 n-1 n(n-1)/2 / 第i趟移动次数 0 i / 总移动次数 0 n(n-1)/2 / 时间复杂度 O(n) O(n^2) O(n^2) (2)空间复杂度
在排序过程中仅需要一个元素的辅助空间,所以空间复杂度为为O(1)。
5、改进
(1)折半插入排序:因为使用插入排序得到的前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
(2)具体操作:
1、将待插入区域的首元素设置为a[low],末元素设置为a[high],则比较时将待插入元素与a[m],其中m=(low+high)/2相比较
2、
do{ if(新元素<a[m]) 选择a[low]到a[m-1]为新的插入区域(即high=m-1) else 选择a[m+1]到a[high]为新的插入区域(即low=m+1) }while(low>high)
3、将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
(3)C实现:
#include <stdio.h> typedef int ElemType ; ElemType arr[]={0,9,8,7,6,5,4,3,2,1}; ElemType n=10,i,j; ElemType low,high,mid; void BinSort(ElemType r[],ElemType n) { for(i=2;i<=n;i++) { r[0]=r[i]; low=1; high=i-1; while (low<=high) { mid=(low+high)/2; if(r[0]<r[mid]) high=mid-1; else low=mid+1;} for(j=i-1;j>=low;j--) { r[i]=r[j]; i--; } r[low]=r[0];} } void put(ElemType r[],ElemType n) { for(j=1;j<n;j++) printf("%d\t",r[j]); printf("\n"); } void main() { BinSort(arr,n); put(arr,n); }
(4)复杂度分析:
时间复杂度:O(n^2) //折半查找只是减少了比较次数,但是元素的移动次数不变,所以折半插入排序算法的时间复杂度仍然为O(n^2)
空间复杂度:O(1)