合并排序
基本思想:
将待排序元素分成大小大致相同的两个子集合,分别对两个子集进行排序,最终将排好序的子集合并成要求的排好序的集合。
先将数组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
*/