排序方法
1. 归并排序
①、排序思路
归并排序的基础思想是将数列划分成单一元素。
int mid=0;
if (l<r) {
mid= (l+r)/2;
//从中间分割
MSort (arr,arrTmp,l,mid);
MSort (arr,arrTmp,mid+1,r);
}
再在和并时两两比较。
while (LS <= LE && RS <= RE)
//谁小就先加入,大的后加入
if (arr[LS] <= arr[RS])
arrTmp[index++] = arr[LS++];
else
arrTmp[index++] = arr[RS++];
//左边或右边还剩下元素(前面保证有一个放好的数列),就把剩下的元素依次放入备用数组
while (LS <= LE) arrTmp[index++] = arr[LS++];
while (RS <= RE) arrTmp[index++] = arr[RS++];
放入原数列中。
for (int i=0; i<arrLen; i++, RE--)
arr[RE] = arrTmp[RE];
②、完整代码
#include <iostream>
using namespace std;
void Merge(int*,int*,int,int,int);
void MSort(int*,int*,int,int);
int main() {
int n;
cin>>n;
int a[n],b[n];
for(int i=0;i<n;i++)
cin>>a[i];
MSort(a, b, 0, n-1);
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
return 0;
}
void Merge (int arr[], int arrTmp[], int LS, int RS, int RE) {
//LS是左部分起始下标
//RE是右部分结束下标
//LE与RS类似
int arrLen = RE - LS + 1;
int LE = RS - 1;
int index = LS;
while (LS <= LE && RS <= RE)
//谁小就先加入,大的后加入
if (arr[LS] <= arr[RS])
arrTmp[index++] = arr[LS++];
else
arrTmp[index++] = arr[RS++];
//左边或右边还剩下元素(前面保证有一个放好的数列),就把剩下的元素依次放入备用数组
while (LS <= LE) arrTmp[index++] = arr[LS++];
while (RS <= RE) arrTmp[index++] = arr[RS++];
//复制到原数组
for (int i=0; i<arrLen; i++, RE--)
arr[RE] = arrTmp[RE];
}
void MSort (int arr[],int arrTmp[],int l,int r) {
int mid=0;
if (l<r) {
mid= (l+r)/2;
//从中间分割
MSort (arr,arrTmp,l,mid);
MSort (arr,arrTmp,mid+1,r);
//合并两数组
Merge (arr,arrTmp,l,mid+1,r);
}
}
③、思路延伸
题目描述:
给定1,2,…,n的一个排列,求它的逆序数。
内存限制:128 MiB
时间限制:1000 ms
输入格式:
第一行是一个整数n,表示该排列有n个数(n <= 300000)。 第二行是n个不同的正整数,之间以空格隔开,表示该排列。
输出格式:
输出该排列的逆序数
题目分析:
在进行组合的时候:
while (LS <= LE && RS <= RE)
if (arr[LS] <= arr[RS])
arrTmp[index++] = arr[LS++];
else
✧arrTmp[index++] = arr[RS++];✧
while (LS <= LE) arrTmp[index++] = arr[LS++];
while (RS <= RE) arrTmp[index++] = arr[RS++];
被✧ ✧标记的该行可以解读成:若该处有逆序对,则将对中小的那个数放入备用数组中。我们就借此来统计逆序对数。
参考代码:
#include <iostream>
using namespace std;
int ans;
void Mesort (int arr[],int tmp[],int ls,int le,int re) {
int rs=le+1,index=ls,al=re-ls+1;
while (ls<=le && rs<=re) {
if (arr[ls]<=arr[rs]) tmp[index++]=arr[ls++];
else tmp[index++]=arr[rs++],ans+=le-ls+1;
}
while (ls<=le) tmp[index++]=arr[ls++];
while (rs<=re) tmp[index++]=arr[rs++];
for (long long i=0;i<al;i++,re--) arr[re]=tmp[re];
}
void Msort (int arr[],int tmp[],int l,int r) {
if (l<r) {
int mid= (l+r)/2;
Msort (arr,tmp,l,mid);
Msort (arr,tmp,mid+1,r);
Mesort (arr,tmp,l,mid,r);
}
}
int main () {
int n;
cin>>n;
int arr[n],tmp[n];
for (int i=0;i<n;i++)
cin>>arr[i];
Msort(arr,tmp,0,n-1);
cout<<ans;
return 0;
}
2. 希尔排序
①、排序思路
希尔排序的基本思想是将几组数据进行插入排序,其中,内层两层循环与插入排序相差无几,只是将几个位置同时插入排序。
https://blog.csdn.net/weixin_49692699/article/details/107645400
可以去我的另一篇博客详细了解插入排序
②、完整代码
#include <iostream>
using namespace std;
void ShellSort(int*,int);
int main() {
//输入数组长度及数组各项
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
cin>>arr[i];
//升序排列
ShellSort(arr,n);
for(int i=0;i<n;i++)
cout<<arr[i]<<' ';
//输出排序好的数组
return 0;
}
void ShellSort(int arr[], int len) {
//开始排序
int tmp;
int i,j,k;
for(i=len>>1;i>0;i=i>>1)
for(j=i;j<len;j++) {
tmp=arr[j];
for(k=j-i;k>= 0 && arr[k]>tmp;k-=i)
arr[k+i] = arr[k];
arr[k+i]=tmp;
}
}
3. 桶排序
①、排序思路
桶排序局限于正整数的排序,并且局限性很大。又称计数排序。他只是依靠数组的下标来达成排序的效果,但在其他地方更加实用,如去重,过滤等。
②、完整代码
#include <iostream>
using namespace std;
int main() {
//输入数组长度及数组各项
int n;
cin>>n;
int arr[20000]={0},tmp;
for(int i=0;i<n;i++) {
cin>>tmp;
arr[tmp]++;
}
for(int i=0;i<20000;i++)
if(arr[i]!=0)
for(int j=0;j<arr[i];j++)
cout<<i<<" ";
//输出“排序”好的数组
return 0;
}
4. 基数排序
①、排序思路
基数排序的基本思想是将不同数位上的数字桶排,这样做的好处是:空间只需要10个桶。
PS:我这里用的是队列,也可以用数组、链表等数据结构,了解队列可以去我的另一篇博客https://blog.csdn.net/weixin_49692699/article/details/107822937 查看。
②、完整代码
#include <iostream>
#include <cmath>
#include <queue>
using namespace std;
int main() {
//输入
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
cin>>arr[i];
//各数位数字桶
queue<int> RaS0 , RaS1 , RaS2 , RaS3 , RaS4 , RaS5 , RaS6 , RaS7 , RaS8 , RaS9;
for(int i=0;i<=20;i++) {
//排序到第二十位
for(int j=0;j<n;j++) {
switch(arr[j]/(int)pow(10,i)%10) {
//比较各数的数位,并放入对应的队
case 0: RaS0.push(arr[j]);break;
case 1: RaS1.push(arr[j]);break;
case 2: RaS2.push(arr[j]);break;
case 3: RaS3.push(arr[j]);break;
case 4: RaS4.push(arr[j]);break;
case 5: RaS5.push(arr[j]);break;
case 6: RaS6.push(arr[j]);break;
case 7: RaS7.push(arr[j]);break;
case 8: RaS8.push(arr[j]);break;
case 9: RaS9.push(arr[j]);break;
}
}
//原数组下标
int index=0;
for(int j=0;j<10;j++) {
switch(j) {
//存入第j各队中的数字
case 0: {
while(!RaS0.empty()) {
arr[index++]=RaS0.front();
RaS0.pop();
}
break;
}
case 1: {
while(!RaS1.empty()) {
arr[index++]=RaS1.front();
RaS1.pop();
}
break;
}
case 2: {
while(!RaS2.empty()) {
arr[index++]=RaS2.front();
RaS2.pop();
}
break;
}
case 3: {
while(!RaS3.empty()) {
arr[index++]=RaS3.front();
RaS3.pop();
}
break;
}
case 4: {
while(!RaS4.empty()) {
arr[index++]=RaS4.front();
RaS4.pop();
}
break;
}
case 5: {
while(!RaS5.empty()) {
arr[index++]=RaS5.front();
RaS5.pop();
}
break;
}
case 6: {
while(!RaS6.empty()) {
arr[index++]=RaS6.front();
RaS6.pop();
}
break;
}
case 7: {
while(!RaS7.empty()) {
arr[index++]=RaS7.front();
RaS7.pop();
}
break;
}
case 8: {
while(!RaS8.empty()) {
arr[index++]=RaS8.front();
RaS8.pop();
}
break;
}
case 9: {
while(!RaS9.empty()) {
arr[index++]=RaS9.front();
RaS9.pop();
}
break;
}
}
}
}
//输出
for(int i=0;i<n;i++)
cout<<arr[i]<<' ';
return 0;
}
5. 快速排序
①、排序思路
快速排序的基本思路是选一个数字,将比其小的数排左边,比其大的数排右边。
②、完整代码
#include <iostream>
using namespace std;
void QuickSort(int*,int,int);
int main() {
//输入数组长度及数组各项
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
cin>>arr[i];
//升序排列
QuickSort(arr,0,n-1);
for(int i=0;i<n;i++)
cout<<arr[i]<<' ';
//输出排序好的数组
return 0;
}
void QuickSort(int a[],int l,int r) {
//开始递归
if(l<r) {
//没出错
int mid=(l+r)/2;
swap(a[mid],a[r]);
int i=l,j=r-1;
//小的数排左边,大的数排右边
while(i<=j) {
while(a[i]<a[r]) {
i++;
}
while(a[j]>a[r]) {
j--;
}
if(i<=j) {
swap(a[i++],a[j--]);
}
}
swap(a[i],a[r]);
QuickSort(a,l,i-1);
QuickSort(a,i+1,r);
}
}
③、思路延伸
题目描述:
给定一个长度为n(1<=n<=100000)的序列,保证序列中的数不重复,问第k(1<=k<=n)小的元素是多少。
内存限制:128 MiB
时间限制:50 ms
输入格式:
第一行两个个整数n,k。
接下来一行n个数,表示这个序列。
输出格式:
输出仅一行,表示第k小的元素。
题目分析:
我们在排序中选择该元素,则该元素在该轮排序后一定排在序列全部有序后的位置上,如:
2 1 5 4 3
选5排序
一轮后: 2 1 3 4 5
排序完: 1 2 3 4 5
5在第一轮已经找到了它的位置
我们就可以借此来缩小排序次数,即:
if(i==m) return a[i];
else if(i>m) return QuickSort(a,l,i-1);
else return QuickSort(a,i+1,r);
参考代码:
#include <iostream>
using namespace std;
int m;
int QuickSort(int a[],int l,int r) {
if(l==r) return a[l];
else if(l<r) {
int mid=(l+r)/2;
swap(a[mid],a[r]);
int i=l,j=r-1;
while(i<=j) {
while(a[i]<a[r]) {
i++;
}
while(a[j]>a[r]) {
j--;
}
if(i<=j) {
swap(a[i++],a[j--]);
}
}
swap(a[i],a[r]);
if(i==m) return a[i];
else if(i>m) return QuickSort(a,l,i-1);
else return QuickSort(a,i+1,r);
}
}
int main() {
int n;
cin>>n>>m;
m--;
int arr[n];
for(int i=0;i<n;i++)
cin>>arr[i];
cout<<QuickSort(arr,0,n-1);
return 0;
}