数组元素排序
概述
通过这篇博文,你将清楚的知道如何对无序数组进行排序。
我会讲的很清晰透彻,完整。
有C/C++的代码附上给你参考,如果你不会C/C++,没关系,只要看下去,你一定能用自己掌握的语言写出解决代码。
问题描述
数组a中的元素无序,要求将a中的元素由小到大排序。
解决方法
先求出该数组中每个元素的名次,再根据名次进行排序。
名次求解法
1.要想得到每个元素的名次,首先要知道什么是一个元素的名次。一个元素的名次是所有比它小的元素以及在它左边出现的与它相同的元素个数。比如:数组a[]={3,7,8,7,2},各元素的排名如下(由小到大)r[]={1,2,4,3,0}。这就是元素的名次。
2.然后,根据名次的定义按照一个方法求解。
以数组a为例:3 7 8 7 2。
每一个元素都需要与其它元素比较,根据大小,在r中的对应下标位置++,所以,在这之前,r需要将元素初始化为0.
从下标为0的元素开始,下标为1、2、3、4的元素进行比较,如果a[0]更大,则r[0]++,否则,让下标为i的元素对应的名次r[i]++。在这一轮比较中,a[0]与所有元素都比较了,而所有元素也都与a[0]比较了。所以,在下一轮,a[1]只需要与之后的元素进行比较,不需要与a[0]进行比较了。
3.现在,让我们把2中介绍的比较方法稍微变通一下。
第一轮:a[0]与a[1]比较
第二轮:a[0]与a[2]比较,a[1]与a[2]比较
第三轮:a[0]、a[1]、a[2]与a[3]比较
第四轮:a[0]、a[1]、a[2]、a[3]与a[4]比较
这样也能完成比较,你是不是发现了这就是2中介绍的方法的倒版?
名次求解的C++代码实现
2和3中介绍的方法都可以用代码实现,这里实现3中的代码。有兴趣可以尝试实现2中的代码,只需要让i从0开始,让j从大于i开始
template<class T>
void rank(T a[], int len, int r[])
{
int i = 0;
//首先,让r中的元素初始化为0
for (i; i < len; ++i)
r[i] = 0;
//开始排序
for (i = 1; i < len; ++i)
{
for (int j = 0; i < i; ++j)
{
if (a[j] <= a[i])//所有比它小的元素以及在它左边出现的与它相同的元素个数
++r[i];
else
++r[j];
}
}
}
名次求解总比较次数计算
外层for循环执行len-1次。
内层for循环第一次执行1次(这时i为1),最后一次执行len-1次(这时i为len-1)。所以,平均下来,内层for循环每次执行(len-1+1)/2=len/2。
总的比较次数是:(len-1)*len/2。
根据求得的名次排序
求得名次是为了排序,那么,怎么根据名次来排序呢?
要解决这个问题,首先,要知道什么是排序。先观察一个顺序序列:
a[5]={1,2,3,4,5}。下标是0的元素排序是0,下标是1的元素排序是1,a[2]排序是2,…,下标是n的元素排序是n。
没错,你发现了,下标就对应着元素的名次。而名次,刚才已经得到了,只需要根据这个名次来重新排序。为此,我们需要一个新的数组,让新的数组每个下标都对应着一个值,也就是名次,再让这个名次等于相应的值。
举例如下:
数组a[3,7,8,7,2],各元素的排名如下(由小到大)r=[1,2,4,3,0]。
新的数组temp。temp[1]=a[0],temp[2]=a[1],temp[4]=a[2],
temp[3]=a[3],temp[0]=a[4]。
接下来,换一种方式表示:
temp[r[0]]=a[0],temp[r[1]]=a[1],temp[r[2]]=a[2],
temp[r[3]]=a[3],temp[r[4]]=a[4]。
数组r中已经存储了数组a中对应下标位的名次,相同的下标,就能表示要求得的有序序列temp的下标和值。
根据名次排序的C++代码实现
template<class T>
void sortByRank(T a[], int len, int r[])
{
T * tempArr = new T[len];
int i = 0;
//把a中的元素按照名次赋值给tempArr
for (i; i < len; ++i)
tempArr[r[i]] = a[i];
for (i = 0; i < len; ++i)
a[i] = tempArr[i];
delete[] tempArr;
}
总的时间复杂度计算
rank中,总的比较次数是:(len-1)*len/2。
在sortByRank中,总的移动次数是2len次。
所以,完成排序需要(len-1)*len/2次比较和2len次元素移动。
所以,时间复杂度为:
(len-1)*len/2=O(len2)
最后,给出完整的代码,你可以在vs2013中直接运行
#include "stdafx.h"
#include<iostream>
using namespace std;
template<class T>
void rank(T a[], int len, int r[])
{
int i = 0;
//首先,让r中的元素初始化为0
for (i; i < len; ++i)
r[i] = 0;
//开始排序
for (i = 1; i < len; ++i)
{
for (int j = 0; j < i; ++j)
{
if (a[j] <= a[i])
++r[i];
else
++r[j];
}
}
}
template<class T>
void sortByRank(T a[], int len, int r[])
{
T * tempArr = new T[len];
int i = 0;
//把a中的元素按照名次赋值给tempArr
for (i; i < len; ++i)
tempArr[r[i]] = a[i];
for (i = 0; i < len; ++i)
a[i] = tempArr[i];
delete[] tempArr;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[5] = { 3, 7, 8, 7, 2 };
int len = 5;
int r[5] = { 0, 0, 0, 0, 0 };
cout << "排序前:" << endl;
for (int i = 0; i < len; ++i)
cout << a[i] << ' ';
cout << endl;
::rank(a, len, r);
cout << "名次:" << endl;
for (int i = 0; i < len; ++i)
cout << r[i] << ' ';
cout << endl;
::sortByRank(a, len, r);
cout << "排序后:" << endl;
for (int i = 0; i < len; ++i)
cout << a[i] << ' ' ;
cout << endl;
return 0;
}