经典排序算法学习笔记三——插入排序

插入排序

工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

 

 

数据结构 数组
最差时间复杂度 O(n^2)
最优时间复杂度 O(n)
平均时间复杂度  O(n^2)
最差空间复杂度 总共 O(n) ,需要辅助空间O(1)

   

 

 

 

          

 

 

https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F#.E7.AE.97.E6.B3.95.E6.8F.8F.E8.BF.B0

1、算法思想

插入排序都采用in-place在数组上实现。

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤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);
}

折半插入排序代码来源:http://baike.baidu.com/link?url=x12HcpirljXV_EWkGELhZEbwM1PBFMgZKENK6DspEH91gepF4ZkuHIdupjbBLqxJuYvTCDbBhupo41K81KZds_#4_3

(4)复杂度分析

时间复杂度:O(n^2) //折半查找只是减少了比较次数,但是元素的移动次数不变,所以折半插入排序算法的时间复杂度仍然为O(n^2)

空间复杂度:O(1)

 

posted @ 2016-10-04 15:46  米琪儿  阅读(491)  评论(0编辑  收藏  举报