第八章排序(2)

简单选择排序

基本思想:第i 趟在n-i+1(i=1,2,…,n-1)个记录中选取关键码最小的记录作为有序序列中的第i个记录。

  • 如何在无序区中选出关键码最小的记录?

解决方法:
设置一个整型变量index,用于记录在一趟比较的过程中关键码最小的记录位置。

  • 如何确定最小记录的最终位置?

解决方法:
第i趟简单选择排序的待排序区间是r[i] ~ r[n],则r[i]是无序区第一个记录,所以,将index所记载的关键码最小的记录与r[i]交换。

void  selectSort ( int  r[ ], int n)
{   
    for ( i=1; i<n; i++) 
    {  
        index=i; 		
        for (j=i+1; j<=n; j++) 
           if  (r[j]<r[index])  index=j;
        if (index!=i)   r[i]<==>r[index]; 	 
    }
} 
  • 性能分析

移动次数:
最好情况(正序):0次
比较次数:
在这里插入图片描述简单选择排序的时间复杂度为O(n2)。
空间性能:需一个辅助空间。
稳定性:根据我们教材上的算法,简单选择排序是不稳定的。

堆排序

堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(称为小根堆),或每个结点的值都大于或等于其左右孩子结点的值(称为大根堆)。

将堆用顺序存储结构来存储,则堆对应一组序列。

基本思想:
1.首先将待排序的记录序列构造成一个堆(大顶堆),
2.此时,选出了堆中所有记录的最大者,然后将它从堆中移走,
3.将剩余的记录再调整成堆,
4.这样又找出了次大的记录,以此类推,直到堆中只有一个记录。

  • 如何处理堆顶记录?

解决方法:
第1 次处理堆顶是将堆顶记录r[1]与序列中第?个记录
第2 次处理堆顶是将堆顶记录r[1]与序列中第?个记录
第 i 次处理堆顶是将堆顶记录r[1]与序列中第n-i+1个记录r[n-i+1]交换。
如何调整剩余记录,成为一个新堆?
解决方法:
第 1 次调整剩余记录,此时,剩余记录有?个,

  • 调整范围?

第 i 次调整剩余记录,此时,剩余记录有n-i个,调整根结点至第n-i个记录。

void  HeapSort ( int  r[], int n)
{
    for (i=n/2; i>=1; i--)      //初建堆
       sift(r, i, n) ;     
    for (i=1; i<n; i++ )
    {
       r[1]←→r[n-i+1];        //移走堆顶
       sift(r, 1, n-i);               //重建堆
    }
}
  • 复杂性分析:

建堆:O(n)
删除堆顶的调整:O(log2n)
一次建堆 ,n次删除堆顶
总时间代价为O(nlog2n)
空间代价为O(1)
堆排序是一种不稳定的排序方法 。

归并排序
归并:将两个或两个以上的有序序列合并成一个有序序列的过程。
归并排序的主要操作是归并,其主要思想是:将若干有序序列逐步归并,最终得到一个有序序列。

二路归并排序

基本思想:
将一个具有n个待排序记录的序列看成是n个长度为1的有序序列,
然后进行两两归并,
得到n/2个长度为2的有序序列,
再进行两两归并,得到n/4个长度为4的有序序列,
……,
直至得到一个长度为n的有序序列为止。

  • 如何将两个有序序列合成一个有序序列?

设相邻的有序序列为r[s] ~ r[m]和r[m+1] ~ r[t],归并成一个有序序列r1[s] ~ r1[t]

  • 怎样完成一趟归并?

在一趟归并中,除最后一个有序序列外,其它有序序列中记录的个数相同,用长度h表示。
设参数i指向待归并序列的第一个记录,归并的步长是2h,
在归并过程中,有以下三种情况:
①相邻两个有序表的长度均为h (此时,i+2h-1<=n) ,执行一次归并,
此时,i≤n-2h+1,
完成后i加2h,准备进行下一次归并;
②仍有两个相邻有序表,一个长度为h,另一个长度小于h(i+h-1<n),
此时,i<n-h+1
则执行两个有序表的归并,完成后退出一趟归并。
③只剩下一个有序表(i+h-1>=n),
i≥n-h+1
直接将该有序表送到r1的相应位置,完成后退出一趟归并。

  • 如何控制二路归并的结束?

解决方法:
开始时,有序序列的长度h=1,
结束时,有序序列的长度h=n,
用有序序列的长度来控制排序的结束。

void Merge (int r[ ], int r1[ ], int s, int m, int t )
{
    i=s;   j=m+1;   k=s;
    while (i<=m && j<=t)
    {   
        if (r[i]<=r[j])  r1[k++]=r[i++];
        else  r1[k++]=r[j++]; 
     }
     if (i<=m)  while (i<=m)              //收尾处理
                           r1[k++]=r[i++];    //前一个子序列
     else  while (j<=t)
                  r1[k++]=r[j++];             //后一个子序列
} 
void  MergePass (int  r[ ], int  r1[ ], int  n, int  h)
{
     i=1;		//第一个子序列的第一个元素
     while (i≤n-2h+1)                //情况1
     {
           Merge (r, r1, i, i+h-1, i+2*h-1);
           i+=2*h;
      }
      if (i<n-h+1) Merge (r, r1, i, i+h-1, n);   //情况2
      else for (k=i; k<=n; k++)    //情况3
                 r1[k]=r[k];
}
算法描述:
void  MergeSort (int r[ ], int r1[ ], int n )
{
    h=1;
    while (h<n)
    {
         MergePass (r, r1, n, h);
         h=2*h;
         MergePass (r1, r, n, h);
         h=2*h;
    }
} 
  • 归并排序的递归实现
void msort(int a[], int r[], int s, int t){
    if(s==t) 
         return;              //如果只有一个数字则返回,无须排序
    int mid=(s+t)/2;
    msort(s,mid);                //分解左序列
    msort(mid+1,t);            //分解右序列
    int i=s, j=mid+1, k=s;   //接下来合并
    while(i<=mid && j<=t)  {
          if(a[i]<=a[j]) {
                r[k]=a[i];     k++; i++;
           }
          else {
               r[k]=a[j];  k++; j++;
          }
    }  
      while(i<=mid) {     //复制左边子序列剩余
           r[k]=a[i]; k++; i++;
       }
       while(j<=t)  {  //复制右边子序列剩余  
        
            r[k]=a[j]; k++; j++;
        }
        for(int i=s; i<=t; i++)
              a[i]=r[i];  
        return 0;
} 
  • 性能分析

时间性能:
一趟归并操作是将r[1]-r[n]中相邻的长度为h的有序序列进行两两归并,并把结果存放到r1[1]-r1[n]中,这需要O(n)时间。整个归并排序需要进行log2n趟,因此,总的时间代价是O(nlog2n)。这是归并排序算法的最好、最坏、平均的时间性能。
空间性能:
算法在执行时,需要占用与原始记录序列同样数量的存储空间,因此空间复杂度为O(n)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值