插入排序(Insertion Sort)

来源:互联网 发布:UG中编程中D是什么意思 编辑:程序博客网 时间:2024/05/17 02:53

维基百科:http://zh.wikipedia.org/wiki/插入排序

算法思想:
若数组A[n]的前n-1个数已经有序,我们只需把第n个元素插入到适当的位置即可。易分析得算法的时间复杂度为Ο(n^2)

具体描述:

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

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。

一、简单插入排序(simple insertion sort)

#include <cstdlib>#include <iostream>using namespace std;//iterative implementationtemplate<class T>void simpleInsertionSort(T *a, int n){    T temp;    int j;    for(int i=1; i<n; i++)    {        temp = a[i];        j = i-1;        while(j >= 0 && a[j] > temp)        {            a[j+1] =  a[j];            j--;        }        a[j+1] = temp;  //put a[i] to right place    }}//recursive implementationtemplate<class T>void insertionSort(T *a ,int n){    if(n>1)    {      insertionSort(a,n-1); //sort the first n-1 elements recursively      insert(a,n);          //insert a[n-1] in a[0..n-2]    }}/* n the size of the array * assume the first n-1 elements is already sorted*/template<class T>void insert(T *a, int n){    T temp = a[n-1];    int i = n-2;        while(i >= 0 && a[i] > temp)    {        a[i+1] = a[i];        i--;    }    a[i+1] =  temp;}int main(int argc, char *argv[]){    int n;    int *a = NULL;        while(cin>>n && n > 0)    {        a = new int[n];        for(int i=0; i<n; i++)        {            cin>>a[i];        }        //simpleInsertionSort(a,n);        insertionSort(a,n);        for(int i=0; i<n; i++)        {            cout<<a[i]<<" ";        }        cout<<endl<<endl;        delete [] a;    }        system("PAUSE");    return EXIT_SUCCESS;}

二、二分查找排序(binary search sort)
template<class T>void binarySearchSort(T *a, int n){    T temp;    int low ,mid,high;    for(int i=1; i<n; i++)    {        temp = a[i];            //暂存记录         low = 0;        high = i-1;                while(low <= high)       //寻找插入点        {            mid = (low + high)/2;            if(temp < a[mid])            high = mid - 1;     //插入点在低半区间            else            low = mid + 1;      //插入点在高半区间        }        //high+1为插入点        for(int k=i-1; k>=high+1; k--)//记录后移        {            a[k+1] = a[k];        }        a[high+1] = temp;//插入到适当位置    }}

注意:

1、虽然折半查找减少了比较次数,但是没有减少移动次数,因而折半插入排序的算法时间复杂度仍为Ο(n^2)

2、折半插入,插入点的确定:
(1)考虑特殊情况,当区间[0,i]恰好是有序的,此时插入点应该为i,即high+1,因为high==i-1
(2)对于折半插入,我们就是要在[0,i-1]之间寻找一个有效的插入点k,使得a[k-1]<=a[i]<a[k],即保证插入是稳定的。
(3)由于搜索区间是以2倍的速度不断递减,必然会有某一时刻出现:low == mid == high的情况,此时分两种情况:
a、若temp <a[mid],插入点在左边区间:high = mid-1;接着由于循环条件low<=high不满足而结束循环,此时temp 刚好比a[low]小,也就是说应该插入在low处。且满足low == mid == high+1
b、若temp>=a[mid],插入点在右边区间:low = mid +1;同样循环结束,此时temp刚好应该插入high点之后,且满足mid == high ==low-1
(4)综合两种情况,插入点都应该为high+1

参考书籍:
[1]《数据结构(C语言版)》严蔚敏
[2]《算法导论》第2版,潘金贵译
原创粉丝点击