排序专题之选择排序

第二类的排序,选择排序,有两种,一种是直接选择排序,一种是堆排序,

堆排序用到了树部分的知识,下面来看这2种排序。


第一种为选择排序:



基本思想:
         第i趟排序开始时,当前有序区和无序区分别为R[0..i-1]和R[i..n-1](0≤i<n-1),
该趟排序则是从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,
使R[0..i]和R[i+1..n-1]分别变为新的有序区和新的无序区。
        因为每趟排序均使有序区中增加了一个记录,且有序区中的记录关键字均不大于无序区中记录的关键字,
即第i趟排序之后R[0..i]的所有关键字小于等于R[i+1..n-1]中的所有关键字,所以进行n-1趟排序之后
有R[0..n-2] 的所有关键字小于等于R[n-1].key,即经过n-1趟排序之后,整个表R[0..n-1]递增有序。


代码如下:

void SelectSort(RecType R[],int n)
{    int i,j,k;  RecType temp;
      for (i=0;i<n-1;i++)    	   /*做第i趟排序*/
      {     k=i;
	for (j=i+1;j<n;j++)  /*在[i..n-1]中选key最小的R[k] */
	      if (R[j].key<R[k].key)
		      k=j;    /*k记下的最小关键字所在的位置*/
	 if (k!=i)          /*交换R[i]和R[k] */
	 {    temp=R[i];  R[i]=R[k];  R[k]=temp;  }
        }
    }





第二种是堆排序,

堆排序:将无序序列建成一个堆,得到关键字最小(或最大)的记录;

输出堆顶的最小(大)值后,使剩余的n-1个元素重又建成一个堆,

则可得到n个元素的次小值;重复执行,得到一个有序序列,
堆排序需解决的两个问题
如何由一个无序序列建成一个堆?
如何在输出堆顶元素之后,调整剩余元素,使之成为一个新的堆?
第二个问题解决方法——筛选
方法:输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结点值

与左、右子树的根结点值进行比较,并与其中小者进行交换;重复上述操作,

直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”


三个步骤如下:




建立一个初堆:

void   crt_heap(RecordType r[], int length )
/*对记录数组r建堆,length为数组的长度*/
{
    n= length;
    for ( i=n/2 ; i>= 1 ; --i)  /* 自第个记录开始进行筛选建堆 */ 
         sift(r,i,n) ;  
} 

重建序列的算法为:


void sift(RecType R[],int low,int high)
{    int i=low,j=2*i;    /*R[j]是R[i]的左孩子*/
      RecType temp=R[i];
      while (j<=high) 
      {     if  (j<high && R[j].key<R[j+1].key)  j++;
             if   (temp.key<R[j].key) 
             {    R[i]=R[j]; /*将R[j]调整到双亲结点位置上*/
	          i=j;   	     /*修改i和j值,以便继续向下筛选*/
   	          j=2*i;
	   }
	   else break; 	/*筛选结束*/
       }
       R[i]=temp;  	/*被筛选结点的值放入最终位置*/
    }

排序的算法为:



void HeapSort(RecType R[],int n)
{    int i;  	RecType temp;
      for (i=n/2;i>=1;i--)  	/*循环建立初始堆*/
            sift(R,i,n); 
      for (i=n;i>=2;i--)   /*进行n-1次循环,完成推排序*/
      { 	 temp=R[1];  /*将第一个元素同当前区间内R[1]对换*/
        	 R[1]=R[i];R[i]=temp;
        	 sift(R,1,i-1);     /*筛选R[1]结点,得到i-1个结点的堆*/
      }
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值