合并+快速排序

合并排序

基本思想:
  将待排序元素分成大小大致相同的两个子集合,分别对两个子集进行排序,最终将排好序的子集合并成要求的排好序的集合。
  先将数组a中相邻两个元素两两配对,即s=1,将他们排序,构成长度为2(s=2)的子集合,再将他们排序成长度为4(s=4)的排好序大的子集合,继续下去,直至全部排好序。
时间复杂度为O(nlogn)。

下面一段是个人的思考和总结:
  我是根据《计算机算法设计与分析》教材的代码写的,开始我还想在MergeSort函数里,先将a排序放到函数里定义的数组b中(MergeSort(a, b, s, n)),然后s+=s,再把数组b排序放回数组a中(MergeSort(b, a, s, n)),每次循环要有两次排序,也就是s会有两次增长,会不会第一次增加后s就比n大了,导致数组越界出现问题,用不用比较s和n的大小在调用Mergepass函数。其实是不会的,比如说长度为6的数组a,s=4,s<n,将a排序到b,调用Mergepass函数,n-2s=6-8=-2,i=0>-2,不会走while,i+s=0+4=4<n=6,走if语句,调用Merge函数。排序Merge(c, d, 0, 3, n-1=5),就是左右两边数量不相等的排序,正常走Merge排就可以。现在得到的数组b就是已经全部排好的数组了,在MergeSort里继续走s+=s,现在s=8.继续走(MergeSort(b, a, s, n)),在Mergepass里,n-2s=-10,i=0>-10,不走循环,i+s=0+8>n=6,走else语句,从i!n-1全部赋值给数组a,这样没有进行排序,直接全部复制回去了,最后得到的结果就是排好序的数组a。
(教材在p23Merge里while语句把第二个if、else也括进去了,应该只括第一个的,个人测试)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 101;

void Merge(int c[maxn], int d[maxn], int l, int m, int r)//两端元素进行排序
{
    int i=l, j=m+1, k=l;
    while((i<=m)&&(j<=r))
    {
        if(c[i]<=c[j])
            d[k++]=c[i++];
        else
            d[k++]=c[j++];
    }
    if(i>m)
    {
        for(int q=j; q<=r; q++)
            d[k++]=c[q];
    }
    else
    {
        for(int q=i; q<=m; q++)
            d[k++]=c[q];
    }
}

void Mergepass(int x[maxn], int y[maxn], int s, int n)//合并大小为s的相邻子数组
{
    int i=0;
    while(i<=n-2*s)
    {
        Merge(x, y, i, i+s-1, i+2*s-1);//合并大小为s的相邻两子数组
        i=i+s*2;
    }
    if(i+s<n)
        Merge(x, y, i, i+s-1, n-1);//剩下的元素小于2*s,就将前面排好的全部元素于最后的小于2s的元素一起排序
    else
       for(int j=i; j<=n-1; j++)//如果是已经排好的,全部元素赋值(复制)回去。
       y[j]=x[j];
}

void MergeSort(int a[maxn], int n)
{
    int b[maxn];
    int s=1;
    while(s<n)
    {
        Mergepass(a, b, s, n);//合并到数组b
        s+=s;
        Mergepass(b, a, s, n);//合并到数组a
        s+=s;
    }
}

int main()
{
    int a[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    MergeSort(a, n);
    for(int i=0; i<n; i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}
/*
8
48 12 61 3 5 19 32 7
*/

快速排序

第一次排序过程:
  一共8个数,利用p+rand()%(r-p+1)的方式随机选择一个数,比如说65,在Partition函数中有两个指针,一个i在开始即p的位置,另一个j在r+1的位置,被选择的数赋值给x,在while循环中,++i,–j,如果比x的值小就放在前面,如果比x大就放在后面,用swap函数交换实现,如果i>=j说明排序完毕,退出循环,65与j所在的数交换,实现排序过程。
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int maxn = 101;
int a[maxn];

int Partition(int a[], int p, int r)
{
    int i=p, j=r+1;
    int x=a[p];
    //将小于x的元素交换到左边区域,将大于x的元素交换到右边区域
    while(1)
    {
        while(a[++i]<x && i<r);
        while(a[--j]>x);
        if(i>=j)
            break;
        swap(a[i], a[j]);
    }
    a[p]=a[j];
    a[j]=x;
    return j;
}

int RamdomizedPartition(int a[], int p, int r)
{
    int i=p+rand()%(r-p+1);
    swap(a[i], a[p]);
    return Partition(a, p, r);
}

void RandomizedQuickSort(int a[], int p, int r)
{
    if(p<r)
    {
        int q=RamdomizedPartition(a, p, r);
        RandomizedQuickSort(a, p, q-1);
        //对左半段排序
        RandomizedQuickSort(a, q+1, r);
        //对右半段排序
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
    }
    RandomizedQuickSort(a, 0, n-1);
     for(int i=0; i<n; i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}

/*
8
65 70 75 80 85 55 50 2
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值