今天学习了一下关于排序的一点东西,发现是真多,下面说一下一个我觉得非常牛的排序,归并排序
网上很多都做过归并排序与sort()快速排序的排序时间的对比,结果归并排序比c++标准库定义的sort()还快
但它也不是没有缺点,就是空间的浪费的比较严重,它不是在原地址上进行修改,而是创建一个临时数组来
储存,再排序。下面我简单说一下我对它的理解:
感觉它有点像二分法的,就是先将数组分为两个部分,然后在将左右两部分在各分为两部分。。。。。。直到分为每一个
小组都是俩个元素,然后在对这两个元素排序(这里是要用那个创建的临时数组的),先将两个元素派完序后放入临时
数组中,然后在将临时数组放入要排序的数组,然后就是在将两两排序后的含有两个元素的子数组合并(这里合并的意思
也就是在把两个子数组当成两个元素,再进行排序,当然这里可以看出是递归的思想)。。。。。。然后到最后又将很多
的子数组有合并成一个大数组。
也就是
一个数组 (要排序的数组)--------------分成很多只含两个元素的子数组--------------------------在合并成一个数组(已经排完序的)
这里我觉的用递归的思想实现比较简单而且容易理解:
这里我觉得它就像是以前老师讲的递归的应用:
下面给出我的代码:
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
//这是主要的功能函数,既包含了排序的功能,又包含了合并数组的功能
void mergearray(ll a[],ll first,ll mid,ll last,ll temp[])
{
ll i = first,j=mid+1;
ll m = mid,n=last,k=0;
while(i<=m&&j<=n)
{
if(a[i] < a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while(i<=m)
temp[k++] = a[i++];
while(j<=m)
temp[k++] = a[j++];
for(ll i =0; i<k; i++)
{
a[i] = temp[i];
}
}
//这个是对函数进行排序功能函数也就是分割数组
void mergesort(ll a[],ll first,ll last,ll temp[])
{
if(first < last)//这里我觉得很重要,因为它将判断并将数组分为元素为两个的子数组
{
ll mid = (first+last)/2;
mergesort(a,first,mid,temp);
mergesort(a,mid+1,last,temp);
mergearray(a,first,mid,last,temp);
}
}
//下面的这个函数是像是一个用户的接口
void MergeSort(ll a[],ll n)
{
ll *p = new ll[n];//创建一个临时数组,这里也可以不使用动态数组
mergesort(a,0,n-1,p);//调用排序函数
delete []p;
}
int main()
{
ll a[5] = {5,6,4,2,8};
MergeSort(a,5);
for(ll i=0; i<5; i++)
{
cout << a[i] << " ";
}
return 0;
}
代码,中我觉得可能难理解的是关于递归的部分,前提你必须理解关于递归的思想(一条路走到尽头后,在走分路),
还有就是注意我这里是传入的数组的所以,所以在第一函数中遍历数组时要写等号,
一个数列有逆序数的性质,详情见线性代数。。。。
关于逆序数的应用有很多,这里只说我今天遇到的,就是求一个数列每次只能交换相邻的元素,最少经过多少次可以将其
变为有序的数列,注意这里只能交换相邻的元素而且是最少的次数,这里的最少次数就等于它的逆序数,其实这跟冒泡排序的的原理有点像,你可以自己退一下,上面的程序只要将mergearray()函数改一下就可以求一个数组的逆序数了,是不是觉得很神奇,也可能有的人会说没必要,但是在小中数据量上很快,下面给出我的代码:
#include <iostream> | |
#include <string> | |
#include <algorithm> | |
#include <map> | |
#define ll long long | |
using namespace std; | |
ll cnt = 0; | |
void mergearray(ll a[], ll first, ll mid, ll last, ll temp[]) | |
{ | |
ll i = first, j = mid + 1; | |
ll m = mid, n = last; | |
ll k = 0; | |
while (i <= m && j <= n) | |
{ | |
if (a[i] <= a[j]) | |
temp[k++] = a[i++]; | |
else | |
{ | |
temp[k++] = a[j++]; | |
cnt += m-i+1; | |
} | |
} | |
while (i <= m) | |
temp[k++] = a[i++]; | |
while (j <= n) | |
temp[k++] = a[j++]; | |
for (i = 0; i < k; i++) | |
a[first + i] = temp[i]; | |
} | |
void mergesort(ll a[], ll first, ll last, ll temp[]) | |
{ | |
if (first < last) | |
{ | |
ll mid = (first + last) / 2; | |
mergesort(a, first, mid, temp); | |
mergesort(a, mid + 1, last, temp); | |
mergearray(a, first, mid, last, temp); | |
} | |
} | |
bool MergeSort(ll a[], ll n) | |
{ | |
ll *p = new ll[n]; | |
if (p == NULL) | |
return false; | |
mergesort(a, 0, n - 1, p); | |
delete[] p; | |
return true; | |
} | |
int main() | |
{ | |
ios::sync_with_stdio(false); | |
cin.tie(0);cout.tie(0); | |
ll n,m; | |
cin >> n; | |
for(ll i = 1; i <= n;i++) | |
{ | |
cin >> m; | |
cnt =0; | |
ll* p = new ll[m]; | |
for(int i = 0;i<m;i++) | |
{ | |
cin >> p[i]; | |
} | |
MergeSort(p,m); | |
delete []p; | |
cout << "Scenario #"<<i<<":\n"; | |
cout << cnt<<"\n\n"; | |
} | |
return 0; | |