排序算法

前提

void X_Sort(ElementType A[],int N)

  • 大多数情况下,为简单起见,讨论从小到大整数排序
  • N是整数
  • 只讨论基于比较的排序(<=>有定义)
  • 只讨论内部排序
  • 稳定性:任意两个相等的数据排序前后的相对位置不发生改变
  • 没有一种排序是任何情况下都表现最好的

冒泡排序


顾名思义,比较相邻的泡泡大小,当上面的泡泡大时,互换位置。先比较1位和2位的大小,则互换位置。



然后比较2位和3位的大小,2比3小,则不动。依次类推,3位比4大,则互换


然后4位比5位大,互换位置。


这时完成了一趟排序,最大的泡泡位于最下面。依次第二趟只需要对1到n-1的泡泡进行排序。

代码实现:

void Bubble_Sort(ElementType A[],int N)
{   for(p=N-1;p>=0;p--){
       flag=0;
        for(i=0;i<p;i++){//一趟冒泡
            if(A[i]>A[i+1]{
               Swap(A[i].A[i+1]);
                flag=1;//标识发生交换
             }
         }
         if(flag==0)//全程无交换
            break;
  }
}

最好情况:顺序T=O(N)

最坏情况:逆序T=O(N2)

优点:简单,对数组和链表均适用,稳定

插入排序

就像抓牌一样,首先抓一张J

第二张是K,比J大,直接放在后面


第三张A比K大,放在K后面

第四张是Q,需要和A比较,比A小,因此在A前面,所以把A向后一位,然后和K比较,依然比K小,将K也向后一位,再与J比较,比J大,因此放在J后面。


实现代码

void Insertion_Sort(ElementType A[],int N)
{   for(p=1;p<N;p++) {
     Tmp=A[p];//摸下一张牌
     for(i=p;i>0&&A[i-1]>Tmp;i--)
         A[i]=A[i-1];//移出空位
     A[i]=Tmp;//新牌落位
      }
}

最好情况:顺序T=O(N)

最坏情况:逆序T=O(N2)

时间复杂度下界

  • 对于下标i<j,如果A[i]>A[j],则称(i,j)是一对逆序对(inversion)
  • 交换2个相邻元素正好消去1个逆序对
  • 插入排序:T(N,I)=O(N+I) ——如果序列基本有序,则插入排序简单且高效

定理:任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对。

定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为Ω(N2)

这意味着:要提高算法效率,我们必须

  • 每次交换不止消去1个逆序对!
  • 每次交换相隔较远的2个元素!

希尔排序(by Donald Shell)


基本思路:利用插入排序的简单,同时克服了插入排序每次只交换相邻两个元素的缺点。

例子:

81941196123517952858417515

先做5间隔的排序:即比较处于1,6,11位的3个数,并从小到大放到相应的位置。


接下来比较下一位间隔5的序列:

依次类推:





最后将12和58排序放入相应位置


接下来在5间隔排序的基础上进行3间隔的排序,接下来进行3趟排序:




此时3间隔的排序结果已经有了很大的"改观",最后还需要做1间隔的排序,发现大多数逆序对已经在前面被消除了。


  • 定义增量序列DM>DM-1>...>D1=1
  • 对每个Dk进行“DK-间隔”排序(k=M,M-1,...1)
  • 注意:“Dk-间隔”有序的序列,在执行“Dk-1-间隔”排序后,仍然是“Dk-间隔”有序的

希尔增量序列

原始希尔排序 

DM=N/2,DK=DK+1/2

代码实现:

void Shell_Sort(ElementType A[],int N)
{   for(D=N/2;D>0;D/=2){//希尔增量序列
        for(p=D;p<N;p++){//插入序列
            Tmp=A[p];
            for(i=p;i>=0&&A[i-D]>Tmp;i-=D)
                A[i]=A[i-D];
            A[i]=Tmp;
            }
         }
}
最坏情况:逆序T=Θ(N2)


更多增量序列









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值