内部排序2 (快速排序、堆排序、基数排序)

内部排序2 (快速排序、堆排序、基数排序)

1.快速排序

(1)基本思想

通过一趟排序,将待排序列以枢轴为标准划分成两部分,使其中一部分记录的关键字均比另一部分小,再分别对这两部分进行快速排序,以达到整个序列有序。通常取第一个记录的值为基准值,或称枢轴。

(2)一趟快速排序

在这里插入图片描述
在这里插入图片描述

(3)快速排序的算法

int Partition (SqList &L, int low, int high){
     L.r[0] = L.r[low];   pivotkey = L.r[low].key;  
     while (low < high) { // 从两端交替向中间扫描
          while (low < high && L.r[high].key >= pivotkey) - - high;
          L.r[low] = L.r[high];  // 将比枢轴记录小的移到低端
          while (low < high && L.r[low].key <= pivotkey)  + + low;
          L.r[high] = L.r[low];  // 将比枢轴记录大的移到高端
     } 
     L.r[low] = L.r[0];   // 枢轴记录到位
     return low;    // 返回枢轴位置
}

(4)快速排序分析

a.最好的情形(左、右子区间的长度大致相等), 最好时间复杂度应为O(nlog2n)。

b.最坏的情形(每次能划分成两个子区间,但其中一个是空),快速排序的最坏时间复杂度为O(n2)。

c.对n较大的情况,它是平均速度最快的排序算法,但当n很小时,此方法往往比其他简单排序方法还要慢。

d.快速排序是不稳定的。

2.简单选择排序

(1)基本思想

通过 n-i 次关键字间的比较,从无序序列[i…n]的 n-i+1 记录中选出关键字最小的记录作为第i个记录。

(2)算法

void SelectSort (SqList &L) 
{ 
    for (i=1; i<L.length; ++i) { //选择第i小记录换到位置i
        j = SelectMinKey( L, i ); //在L.r[i..L.length]中选择key最小的记录
        if ( i != j )
        {
            L.r[0] = L.r[i];
            L.r[i] = L.r[j];//交换
            L.r[j] = L.r[0];
		}
    }
} 

(3)简单选择排序的算法分析

a.由于存在不相邻元素之间的交换,所以简单选择排序是不稳定的。

b.时间复杂度为O(n^2).

3.堆排序

(1)基本思想

堆排序利用大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征进行排序。

步骤:

按堆的定义将待排序序列 r[1…n] 调整为大根堆(这个过程称为建初堆),交换 r[1] 和 r[n],则 r[n]为关键字最大的记录。将 r[1…n-1] 重新调整为堆,交换 r[1] 和 r[n-1] ,则 r[n-1] 为关键字次大的记录。循环n-1次,直到交换了r[1]和r[2]为止,得到了一个非递减的有序序列r[1…n]。

大根堆:ki ≥ k2i , ki ≥ k2i+1

小根堆: ki ≤ k2i , ki ≤ k2i+1

大根堆实例

在这里插入图片描述

在这里插入图片描述

(2)堆的排序算法

// 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,
// 调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆	
void HeapAdjust(SqList &H, int s, int m)
{
	rc = H.r[s];    // 暂存H.r[s]
       for (j=2*s; j<=m; j*=2) //沿key较大的孩子结点向下筛选
	 {    
         if (j<m && H.r[j].key<H.r[j+1].key) ++j;//j为较大孩子的下标
         if (rc.key>=H.r[j].key) break;  //大于等于左右子,rc应插入在位置s上
         H.r[s]=H.r[j]; s=j;
     }
     H.r[s] = rc;  //插入
}

void HeapSort (HeapType &H)
{      for(i=H.length/2;i>0;--i) //H.r[1..length]初始建堆
        	HeapAdjust(H,i,H.length);
            for(i=H.length; i>1; --i)
            {     
            H.r[1]<-> H.r[i]; // 将堆顶记录和最后一个记录相互交换 
            HeapAdjust(H,1,i-1); // 将H.R[1..i-1]重新调整为大根堆
} 

(3)堆排序的效率分析

a.时间复杂度:最坏和最好情况下的时间复杂度为O(n*logn)

b.空间复杂度:只需要一个记录大小的辅助储存空间

c.堆排序是不稳定的。

d.只适用于顺序结构不适用于链式结构

4.归并排序

(1)归并排序的主要思想

将若干有序子序列逐步归并,最终得到一个有序序列。

在这里插入图片描述

整个归并排序只需要logn向上取整趟

(2)归并排序的算法

//将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]  
void Merge(RcdType SR[ ],RcdType &TR[ ],int i,int m,int n) 
{ 
    for(j=m+1,k=i; i<=m && j<=n;++k){ //将SR中记录由小到大并入TR
        if (SR[i].key<SR[j].key) TR[k]=SR[i++];
        else TR[k]=SR[j++];
      }
    if (i<=m)
    {
        for(k,i;k<=n&&i<=m;k++,i++) TR[k] = TR[i]; // 将剩余的SR[i..m]复制到TR
	}
    if (j<=n)
    {
         for(k,j;k<=n&&i<=n;k++,i++) TR[k] = TR[j];// 将剩余的SR[j..n]复制到TR
    }
}//merge

void MSort(RcdType SR[ ],RcdType &TR1[ ],int s,int t) { 
      if ( s==t )  TR1[s] = SR[s]; // 只有一个记录
      else {
            m = (s+t)/2;   //将SR[s..t] 平分为SR[s..m]SR[m+1..t]
            MSort(SR,TR2,s,m)   //递归地将SR[s..m]归并排序,结果放入TR2[s..m] 
            MSort(SR,TR2,m+1,t) //递归地将SR[m+1..t]归并排序,结果放入TR2[m+1..t]
            Merge(TR2,TR1,s,m,t) //将有序的TR2[s..m] 和TR2[m+1..t]归并到TR1[s..t]
     }
}

(3)归并排序分析

a.时间复杂度:O(nlogn)

b.空间复杂度:O(n)

c.归并排序是稳定的

并排序,结果放入TR2[m+1…t]
Merge(TR2,TR1,s,m,t) //将有序的TR2[s…m] 和TR2[m+1…t]归并到TR1[s…t]
}
}


**(3)归并排序分析**

a.时间复杂度:O(nlogn)

b.空间复杂度:O(n)

c.归并排序是稳定的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值