排序技术

1、排序的基本概念
在排序问题中,通常将数据元素称为记录
排序:给定一组记录的集合{r1, r2, ……, rn},其相应的关键码分别为{k1, k2, ……, kn},排序是将这些记录排列成顺序为{rs1, rs2, ……, rsn}的一个序列,使得相应的关键码满足ks1≤ks2≤……≤ksn(称为升序)或ks1≥ks2≥……≥ksn(称为降序)。
正序:待排序序列中的记录已按关键码排好序。
逆序(反序):待排序序列中记录的排列顺序与排好序的顺序正好相反。
:在排序过程中,将待排序的记录序列扫描一遍称为一趟。通常,一次排序过程需要进行多趟扫描才能完成。
排序算法的稳定性:多个具有相同键值的记录,经过排序,这些记录的相对次序仍然保持不变。
内排序:在排序的整个过程中,待排序的所有记录全部被放置在内存中
基于比较的内排序:插入排序、交换排序、选择排序、归并排序
不基于比较的内排序:分配排序、桶式排序、基数排序
排序算法的性能:
1.时间复杂性:基本操作。
内排序在排序过程中的基本操作:
⑴比较:关键码之间的比较;
⑵移动:记录从一个位置移动到另一个位置。
2.空间复杂性: 辅助存储空间。
辅助存储空间是指在数据规模一定的条件下,除了存放待排序记录占用的存储空间之外,执行算法所需要的其他存储空间。
2、插入排序
(1)直接插入排序
基本思想:在插入第 i(i>1)个记录时,前面的 i-1个记录已经排好序。
r[0]有两个作用

  1. 进入循环之前暂存了r[i]的值,使得不致于因记录的后移而丢失r[i]的内容;
  2. 在查找插入位置的循环中充当哨兵。
void  insertSort (int  r[ ], int n){	
   for (i=2; i<=n; i++)   { 
       r[0]=r[i]; j=i-1;
       while (r[0]<r[j])       {  
           r[j+1]=r[j];	
	 j=j--;	
        }
       r[j+1]=r[0];	
    }
}

时间复杂度为O(n的平方)。
(2)希尔排序
基本思想
将整个待排序记录分割成若干个子序列,
在子序列内分别进行直接插入排序,
待整个序列中的记录基本有序时,对全体记录进行直接插入排序。

void Shellsort(int r[],int n){
  for (d=n/2; d>=1; d=d/2){
     for (i=d+1; i<=n; i++) {
	     r[0]=r[i];           
	     j=i-d;                
	     while (j>0 && r[0]<r[j])
	     { 
          		r[j+d]=r[j]; 
	          j=j-d;          
	      }
	      r[j+d]=r[0]; 
	}
  }
}

3、交换排序
(1)起泡排序
基本思想:两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。

void BubbleSort(int r[ ], int n)
{	
    exchange=n; 	
    while (exchange) 
    {
        bound=exchange; 
        exchange=0;  
        for (j=1; j<bound; j++)
            if (r[j]>r[j+1]) {
                r[j]←→r[j+1];
	      exchange=j; 
            }
     }
 }

提高冒泡排序的性能?排序过程中交替改变扫描方向——双向起泡排序

int temp;
int    exchange1,exchange2;
int bound1,bound2;
exchange1=n-1; 
exchange2=0; 
while (exchange1) {
    exchange1=0;  
    bound1=exchange1;
    bound2=exchange2;
    for (int j=bound2; j<bound1; j++) 
        if (r[j]>r[j+1]){
	temp=r[j];
	r[j]=r[j+1];
	r[j+1]=temp;
	exchange1=j; 
	}
    bound1=exchange1;    
    for ( j=bound1; j>bound2; j--) 
	    if (r[j]<r[j+1]) {
		  temp=r[j];
		  r[j]=r[j+1];
		  r[j+1]=temp;
		  exchange2=j; 
	   }
		bound2=exchange2;
	}

(2)快速排序
基本思想:首先选一个轴值(即比较的基准),
通过一趟排序将待排序记录分割成独立的两部分,
前一部分记录的关键码均小于或等于轴值,
后一部分记录的关键码均大于或等于轴值,
然后分别对这两部分重复上述方法,直到整个序列有序。
选择轴值的方法:
1.使用第一个记录的关键码;
2.选取序列中间记录的关键码;
3.比较序列中第一个记录、最后一个记录和中间记录的关键码,取关键码居中的作为轴值并调换到第一个记录的位置;
4.随机选取轴值。

int Partition(int r[ ], int first, int end)
{	
    i=first; j=end;         //初始化
    r[0]=r[i];
     while (i<j)	
    {  
      while (i<j && r[0]<= r[j]) j--;  //右侧扫描
       if (i<j) { 
          r[i]=r[j];   i++;  //将较小记录交换到前面
       }
       while (i<j && r[i]<= r[0]) i++;  //左侧扫描
       if (i<j) {
          r[j]=r[i];   j--;  //将较大记录交换到后面
       }
    }
    r[i]=r[0];
    retutn i;    //i为轴值记录的最终位置
}
void QuickSort (int  r[ ], int first, int end )
{
    pivotpos = Partition (r, first, end );  //一次划分  
   //对前一个子序列进行快速排序
    QuickSort (r, first, pivotpos-1);      
   //对后一个子序列进行快速排序
   QuickSort (r, pivotpos+1, end ); 
}

时间平均情况:为O(nlog2n)。
4、选择排序
(1)简单选择排序
基本思想:第i 趟在n-i+1(i=1,2,…,n-1)个记录中选取关键码最小的记录作为有序序列中的第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]; 	 
    }
} 

时间复杂度为O(n2)。
稳定性:根据我们教材上的算法,简单选择排序是不稳定的
(2)堆排序
①堆的定义:堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(称为小根堆),或每个结点的值都大于或等于其左右孩子结点的值(称为大根堆)。

  1. 小根堆的根结点是所有结点的最小者。
  2. 较小结点靠近根结点,但不绝对。
  3. 大根堆的根结点是所有结点的最大者。
  4. 较大结点靠近根结点,但不绝对。

将堆用顺序存储结构来存储,则堆对应一组序列。
②基本思想
首先将待排序的记录序列构造成一个堆(大顶堆),
此时,选出了堆中所有记录的最大者,然后将它从堆中移走,
将剩余的记录再调整成堆,
这样又找出了次大的记录,以此类推,直到堆中只有一个记录。
堆调整:

void sift ( int r[ ], int k, int m )
{//要筛选结点的编号为k,堆中最后一个结点的编号为m 
    i=k;  j=2*i;  temp=r[i];  //将筛选记录暂存
    while (j<=m )           //筛选还没有进行到叶子
    {
        if (j<m && r[j]<r[j+1]) j++;  //左右孩子中取较大者
        if (temp>r[j]) break; 
        else {
             r[i]=r[j];   i=j;   j=2*i;
        }
     }
     r[i]=temp;   //将筛选记录移到正确位置
}

算法:

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);               //重建堆
    }
}

5、归并排序
归并:将两个或两个以上的有序序列合并成一个有序序列的过程。

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;
} 

时间复杂度O(nlog2n),空间复杂度:O(n)
6、分配排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值