归并排序和快速排序

归并排序:

归并排序(MergeSort)是将两个或两个以上的有序表合并成一个新的有序表。归并排序算法是使用分治策略实现N 个元素进行排序的算法。

基本思想:(分治  +  合并 )

当N = 1 时, 终止排序;否则将待排序的元素分成两个大致相同的子集合。分别对两个子集合进行归并排序。最终将排序好的有序子集合合并成所要求的排序结果:

例如:

对一组待排序的记录: 47     33     25     36     48    58

初始关键字     47     33     25     36     48    58                   

//对其分治成两个子集合:{ 47 ,33, 25}       {36, 48 , 58}

//在对子集合进行分治:   {47}   {33,25}       {36}   {48,58}  

//在对子集合进行分治:   {47}  {33}  {25}     {36}   {48}  {58}    /// 由于集合中只有一个关键字时, 一定有序,所以停止分治:

对其子集合合并:

合并的思想是引一个辅助数组R1暂存 目前需要合并的有序子集合(注:合并的方法多种,例如2路合并,3路合并,等)

介绍2 路合并,即每次合并两个有序的子集合;

每次将待合并的两个有序的子集 复制到 R1 ; 然后, 引入3 个指针 left   、  right   、  k   

(left  、 rihght开始分别指向合并集合的第一个位置,k 指向 left )

每次对比 R1[left] 与 R1[right] 的值, 将符合要求的放在 R[k]   ///然后移动相应的指针 ,即可合并。

如果一个子集合已经比较完最后一个元素,则将另外一个集合的元素直接放到R[] 中 

对其递归合并:

//在对子集合进行合并:   {47}  {33}  {25}     {36}   {48}  {58}   //从小到大排序

//合并后的集合为:           {33,47}   {25,36}   {48,58}

//再对有序集合合并:        {25,33,36,47}   { 48,58}

//再合并有序集合:            {25,33,36,47,48,58}

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int R1[1000];
int R[1000];
void Merge(int R[],int left,int mid,int right);
void MergeSort(int R[],int left, int right){
    if(left<right){
        int mid=(left+right)/2;///划分成左右两部分
        MergeSort(R,left,mid);///对左部分再划分
        MergeSort(R,mid+1,right);///对右部分再划分
        Merge(R,left,mid,right);///将有序的左右两部分进行合并
    }
}
void Merge(int R[],int left,int mid,int right){
/// R 的左右子序列已经有序
    for(int k=left; k<=right; k++)///R1 为辅助数组
        R1[k]=R[k];
    int i,j,k;
    i=left,j=mid+1,k=left;
    while(i<=mid&&j<=right)
        if(R1[i]<=R1[j])
            R[k++]=R1[i++];
        else
            R[k++]=R1[j++];
        ///处理没有处理完的剩余部分,不需要比较,所以直接复制就可以了
        while(i<=mid)
            R[k++]=R1[i++];
        while(j<=right)
            R[k++]=R1[j++];
}
int main(){

    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>R[i];
    MergeSort(R,1,n);
    for(int i=1;i<=n;i++)
        cout<<R[i]<<" ";
    return 0;
}

快速排序:

快速排序算法是基于分治的策略排序算法之一。

基本思想:(分解 (找基准) + 合并)

step1: 分解(Divide) 。 以R[q] 为基准将 R[1 ~ n ] 分成   R[1~q-1]    R[q]   R[1~q-1] 三段 ,

使 R[1~q-1] 中的元素均小于 R[q]  ,

使 R[q+1~n] 中的元素均大于 R[q]     // 例如 { 47     33     25     36     48    58} 分成 { 36    33     25  }    {47}   {48    58}

step2:   递归求解。 通过递归调用快速排序算法分别对  R[1~q-1]  和  R[1~q-1]   进行快速排序。

step3: 合并(Merger)。 由于对无序  R[1~q-1]  和  R[1~q-1]  的排序是就地进行的,事迹上不需要进一步合并计算。(合并的过程再划分中进行)。

如何划分:

分别以每个子集合的第一个关键字为基准进行划分,划分为大于基准的集合,小于基准的集合, 基准元素集合。

(1)从右向左扫描,直到找到第一个小于基准R[q] 的位置 j, 然后将 R[j] 和 R[q] 的交换 。///

(2)  从左向右扫描,直到找到第一个大于基准R[q] 的位置 i, 然后将 R[i] 和 R[q] 的交换 。

     重复以上步骤, 直到 i=j 时就停止。 /// j 代表从集合为部向左扫描的指针 , i 代表从向右扫描的指针。当两个指针指向同一位置,即完成一次分解。(初始, i 指向第一个关键字     ,     j 指向 最后一个关键字)

(3)分别对每个分解的子集合执行上述步骤,即可完成排序

#include<iostream>
#include<cstdio>
using namespace std;
int Parttion(int R[],int left,int right);
void QuickSort(int R[],int left,int right){
    int mid;
    if(left<right)
    {
        mid = Parttion(R,left,right);///寻找R 中的基准,mid 的 左边都比R[mid] 小; mid 的 右边都 比 R[mid] 大
        QuickSort(R,left,mid);///对左部分在 找基准 mid
        QuickSort(R,mid+1,right);///对右部分 找基准 mid
    }
}
int Parttion(int R[],int left,int right){
    int pivot=R[left];
    while(left<right)
    {
        while(left<right&&R[right]>=pivot) right--;///从右向左找,第一个比基准大的元素
        R[left]=R[right];
        while(left<right&&R[left]<pivot)   left++;///从左往右找,第一个比基准小的元素
        R[right]=R[left];
    }
    R[left]=pivot;///当left==right 的时候, 将基准填入
    return left;
}
int main()
{
    int n;
    int R[1000];
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>R[i];
   QuickSort(R,1,n);
    for(int i=1;i<=n;i++)
        cout<<R[i]<<" ";

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值