Chinaunix首页 | 论坛 | 博客

fx

  • 博客访问: 1372993
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3964
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-02 14:36
文章分类
文章存档

2022年(2)

2019年(2)

2018年(10)

2017年(1)

2016年(50)

2015年(12)

2014年(9)

2013年(29)

分类: C/C++

2016-08-26 12:56:33

插入排序:

插入排序由n-1趟排序组成。第 i 趟排序前,保证从位置 0 到位置i-1 上的元素已经是排序状态(这是插入排序正确的原因,也是前提条件)。

所以第 i 趟的排序工作就是将 A[i] 放到 A[0,1,2,3...i-1]中的正确的位置。

举个例子。就像玩扑克牌的时候,我们每次拿到的是一张不知道的牌,然后顺着左手中已经有的牌遍历,然后找到它正确的位置后插入这张新牌,这时候在这新插入的牌之前的牌的位置是不变的。但它之后的牌的位置都向后依次移动了一位。


我们给个简单的图例:



代码如下


点击(此处)折叠或打开

  1. void InsertSort(int *A,int n)
  2. {
  3.  int i,j;
  4.  int key;
  5. for(i=1;i<n;i++)
  6. {
  7.     key=A[i];
  8.  
  9.  /*检测是不是在正确的位置上*/
  10.     for(j=i;j>0&&key<A[j-1];j--)
  11.         A[j]=A[j-1];
  12.  
  13.     A[j]=key;
  14. }
  15. }


基于上面的解释,插入排序应该很好理解了。下面我们来分析一下插入排序的运行时间问题。

 

最坏情况下,当输入的逆序的。内层循环每次都执行,且执行最大次数。

所以 T(n)=2+3+4+....n=O(n^2);

最好情况下,当输入是已排序时,内层循环并不工作 

所以 时间复杂度T(n)=O(n)

所以插入排序的运行时间变化差别是很大的,如果输入几乎被排序,那么插入排序的运行时间很快。

 

对于平均时间的分析,我们假设不存在重复的元素。

我们先来讨论一下插入排序到底做了什么事情。

我们定义一个逆序: i < j A[i]>A[j] 这样的一个序偶(A[i],A[j])我们称为一个逆序,

所以显然插入排序所做的工作就是同交换相邻元素来消除逆序对,从而带到排序的目的。所以插入排序的运行时间可表示为 T(n)=O(I+n)。其中 I  为逆序数,O(n)为所做的其他线性工作。

 

那么如果我们知道一个任意 输入序列中的平均逆序数,就知道了插入排序的平均运行时间。

 

定理:含N个互异数的数组的平均逆序数是N(N-1)/4

证明如下:

考虑一个序列 A ,和它的反序列 A~ 。则任意一个序偶(a,b)必定是A或者A~中的一个逆序数

比如 序列A=3,6,1,4,8,7,9和它的反序列A~=9,7,8,4,1,6,3      则(3,6)是A~中的一个逆序 (4,6)是A中的一个逆序。

所以对于n个元素的序列A,任意取两个数组成的序偶。必定是AA~中的一个逆序

所以总的序偶数为   N(N-1)/2  (这是相对于AA~整体而言。)

所以 A 中的逆序数为总逆序数的一半  N(N-1)/4.

 

我们看到任意不包含相同元素的数组A的逆序数 为  O(n^2)

所以我们得到差投入排序的平均时间为T(n)=O(n^2).

 

 

希尔排序:

 

我们将希尔排序和插入排序在一起介绍,原因就是希尔排序的原理和插入排序是一样的,只是它多了一个增量序列。

他也是通过比较元素来工作,不同的是它并不像插入排序那样比较相邻的元素,而是比较相距一定距离的元素。各躺比较所用的距离也逐渐减小,直到距离减小为1

所以他的最后一次进行的就是插入排序。

希尔排序使用的的增量序列H1,H2,H3````Hk.只要h1=1 任何增量序列都是可行的。但存在一些序列比另外一些序列更好。

使用增量Hi排序依次后,对于每一个i A[i]<=A[i+Hi]   即所有相距Hi的元素都被排序了 。此时称数组是Hi 排序的。并且在之后的排序中保持它的Hi 排序性。

 

我们给出其代码。我们使用Shell建议的增量序列Hi=N/2Hi=Hi/2.


点击(此处)折叠或打开

  1. void ShellSort(int *A,int n)
  2. {
  3.     int i,j;
  4.     int increase;
  5.     int key;
  6.     for(increase=n/2;increase>0;increase/=2)
  7.     {
  8.         for(i=1;i<n;i+=increase)
  9.         {
  10.             key=A[i];
  11.             for(j=i;j>0&&j-increase>=0;j-=increase)
  12.             {
  13.                 if(key<A[j])
  14.                     A[j]=A[j-increase];
  15.                 else
  16.                     break;
  17.             }
  18.             A[j]=key;
  19.         }
  20.     }
  21. }


对于希尔排序的运行时间分析通常基于特定的增量序

对于希尔增量 T(n)=O(n)

Hibbard1,3,7。。。。2k-1)增量T(n)=O(N^3/2)  (k3/2为指数)

Sedgewick1,5,19,41,109.。。。)增量T(n)=O(N^7/6) (7/6为指数)

对于他们的定量分析参考《数据结构与算法分析》P169

阅读(14778) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~