zoukankan      html  css  js  c++  java
  • 【啊哈!算法】之二、插入排序

    作者:jofranks 原创作品,转载请标明出处!版权所有,侵权必究!

    来源:http://blog.csdn.net/jofranks


    插入排序包括:直接插入排序,折半插入排序,希尔排序~!

    OK,下面我们就来逐个讲解!

    一、直接插入排序

    直接插入排序属于稳定的排序,时间复杂性为O(n^2),空间复杂度为O(1)。

    它的基本思想是:    

    假设待排序数据存放在数组A[1..n]中,则A[1]可看作是一个有序序列,让i从2开始,依次将A[i]插入到有序序列A[1..i-1]中,A[n]插入完毕则整个过程结束,A[1..n]成为有序序列。


    OK,现在我们来看一下排序的过程:

    待排序数据:  25  54 8  54  21 1  97  2 73  15            (n=10)

    i=2:               25 54  8 54  21  1 97  2  73  15

    i=3:               8  25  54  54 21  1  97 2  73  15

    i=4:               8  25 54 54  21 1  97  2 73  15

    i=5:               21  25 54  54  1 97  2  73  15

    i=6:               1  8  21 25  54  54  97 2  73  15

    i=7:               1  8 21  25  54 54 97  2 73  15

    i=8:               2  8 21  25  54 54  97  73  15

    i=9:               1  2 8  21  25 54  54 73  97  15

    i=10:             1  2 8 15  21 25  54  54 73  97           排序结束


    可在数组中增加元素A[0]作为关键值存储器和循环控制开关。第i趟排序,即A[i]的插入过程为:

    ① 保存A[i]→A[0]

    ③ 如果A[j]<=A[0](即待排序的A[i]),则A[0]→A[j+1],完成插入;

       否则,将A[j]后移一个位置:A[j]→A[j+1];;继续执行③

    对于上面的数据实例,i从2依次变化到10的过程中,j值分别为{1,0,3,1,0,6,1,7,3}



    来看一下动画演示:直接插入排序动画演示


    OK,下面来看一下代码,本代码是C语言!

    void insert_sort(int a[], int N)
    {
    	int temp;
    	int j;
    	//从第二个元素开始逐个往下
    	for(int i = 1; i < N; i++)
    	{
    		if(a[i] >= a[i - 1])
    			continue;
    		temp = a[i];
    		//与前面的元素比较,看是否需要插入
    		j = i - 1;
    		for(; a[j] > temp; j--)
    		{
    			if(j < 0)
    				break;
    			a[j + 1] = a[j]; //后移			
    		}
    
    		a[j + 1] = temp;
    	}
    }






    ok,现在我们来看一下C++版本的代码:(本代码取自维基百科)

    #include <iterator>
     
    template<typename biIter>
    void insertion_sort(biIter begin, biIter end)
      {
        typedef typename std::iterator_traits<biIter>::value_type value_type;
        biIter bond = begin;
        std::advance(bond, 1);
        for(; bond!=end; std::advance(bond, 1)) {
          value_type key = *bond;
          biIter ins = bond;
          biIter pre = ins;
          std::advance(pre, -1);
          while(ins!=begin && *pre>key) {
            *ins = *pre;
            std::advance(ins, -1);
            std::advance(pre, -1);
          }
          *ins = key;
        }
      }






    二、折半插入排序

    折半插入排序算法是一种稳定的排序算法,时间复杂度仍然为o(n^2)!!!

    本排序是在直接插入排序的基础上,减少了比较和移动的次数形成的!是对插入排序算法的一种改进!

    具体操作:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。


    OK,我们来看一下代码! 这类似于二分法查找,相信大家都不陌生!

    void binary_insert_sort(int a[], int N)
    {
    	int temp;
    	int low, high,mid;
    	for(int i = 1; i < N; i++)
    	{
    		if(a[i] >= a[i - 1])
    			continue;
                    //开始二分
    		low = 0;
    		high = i - 1;
    		temp = a[i];
    		for(;low <= high;)
    		{
    			mid = (low + high) / 2;
    			if(temp > a[mid])
    				low = mid + 1;
    			else if(temp < a[mid])
    				high = mid - 1;
    			else
    				break;
    		}
                    //开始移动元素
    		for(int j = i; j > low; j--)
    		{
    			a[j] = a[j - 1];
    		}
    		a[low] = temp;
    	}
    }



    三、希尔排序

    该算法也是对直接插入排序的一种改进!也叫做递减增量排序算法!

    该算法的性能提升至O(n log2 n)!他的最优时间是线性时间!


    算法基本思想:

    取一个小于n的整数S1作为增量,把所有元素分成S1个组。所有间距为S1的元素放在同一个组中。

    第一组:{A[1],A[S1+1],A[2*S1+1],……}

    第二组:{A[2],A[S1+2],A[2*S1+2],……}

    第三组:{A[3],A[S1+3],A[2*S1+3],……}

    ……

    第s1组:{A[S1],A[2*S1],A[3*S1],……}

    先在各组内进行直接插人排序;然后,取第二个增量S2(<S1)重复上述的分组和排序,直至所取的增量St=1(St<St-1<St-2<…<S2<S1),即所有记录放在同一组中进行直接插入排序为止。


    序号

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    原始数据

    12

    89

    57

    32

    96

    37

    54

    5

    79

    57

    S1=5

    组别

    排序结果

    12

    54

    5

    32

    57

    37

    89

    57

    79

    96

    S2=3

    组别

    排序结果

    12

    54

    5

    32

    57

    37

    89

    57

    79

    96

    S3=2

    组别

    排序结果

    5

    32

    12

    37

    57

    54

    79

    57

    89

    96

    S4=1

    组别

    排序结果

    5

    12

    32

    37

    54

    57

    57

    79

    89

    96


    OK,通过上表可以看的清楚是如何排序的,有可能有的童鞋还是不清楚,那没事,我现在上传一个短动画,通过动画我相信你能够很好的理解shell排序!

    希尔排序动画演示


    ok,我们现在来看代码吧!

    void shell_sort(int a[], int N)
    {
    	int temp, m;
    	int i = 0;
    	for(; i < N; )
    	{
    		i = i * 4 + 1;
    	}
    	//还是直接插入
    	for(;i > 0;)
    	{
    		for(int j = i; j < N; j++)
    		{
    			m = j - i;
    			temp = a[j];
    			while(a[m] > temp)
    			{
    				a[m + i] = a[m];
    				m -= i;
    			}
    
    			a[m + i] = temp;
    		}
    		i = (i - 1) / 4;
    	}
    }




    OK,再来看一段C++代码,来自维基百科!

    template<typename T> void sort(std::vector<T>& v)
    {
        const size_t s=v.size();
        for(int gap=s/2;gap>0;gap/=2)
            for(int i=gap;i<s;++i)
                for(int j=i-gap;j>=0;j-=gap)
                    if(v[j+gap]<v[j]){
                        T temp=v[j];
                        v[j]=v[j+gap];
                        v[j+gap]=temp;
                    }
    }




    本节到此结束!



    --------2012/7/31

    --------jofranks 于南昌


  • 相关阅读:
    Linux 学习 step by step (1)
    ubuntu server nginx 安装与配置
    ubuntu server samba服务器配置
    iOS app集成支付宝支付流程及后台php订单签名处理
    mac 连接windows 共享内容
    linux 文件查找,which,whereis,locate,find
    ubuntu server vsftpd 虚拟用户及目录
    ubuntu server 安装 mantis bug tracker 中文配置
    ubuntu server vsftpd 匿名用户上传下载及目录设置
    linux 用户管理,用户权限管理,用户组管理
  • 原文地址:https://www.cnblogs.com/java20130723/p/3211427.html
Copyright © 2011-2022 走看看