归并排序:
归并排序(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;
}