一个元素在序列当中的名次,例如{4,3,9,3,7},最左边出现的3 名次记成0,后面出现的3记1,从小到大从左到右可以将名次记为{2,0,4,1,3}。现在需要对于一组序列进行名次计算,并根据名次对于原序列重新进行排列。这次的方法使用的是原地重排法。
原地重排法介绍:i是循环变量,r[i]存放的是a[i]数组里面的名次,当i!=r[i]时,将r[i]与r[r[i]]交换,对应的a[i]也进行交换,当i=r[i]时,i++进入下一个。
i=0,1,2,3,4
r[i]=2,0,4,1,3
a[i]=4,3,9,3,7
重排1次时:
i=0,1,2,3,4
r[i]=4,0,2,1,3
a[i]=9,3,4,3,7
重排2次时:
i=0,1,2,3,4
r[i]=3,0,2,1,4
a[i]=7,3,4,3,9
重排3次时:
i=0,1,2,3,4
r[i]=1,0,2,3,4
a[i]=3,3,4,7,9
重排4次时:
i=0,1,2,3,4
r[i]=0,1,2,3,4
a[i]=3,3,4,7,9
然后遍历一遍正好满足所求。
具体见代码:
#include<iostream>
using namespace std;
template<class T>
void swap(T *a,T *b) //交换
{
T temp;
temp=a;
a=b;
b=temp;
}
template<class T>
void rearrange(T a[],T r[],int n) //原地重排法
{
for(int i=0;i<n;i++)
while(r[i]!=i)
{
swap(a[i],a[r[i]]);
swap(r[i],r[r[i]]);
}
}
template<class T>
void range(T a[],T r[],int n)
{
for(int i=0;i<n;i++)
r[i]=0;
for(int i=0;i<n;i++)
for(int j=0;j<i;j++)
if(a[j]>a[i])r[j]++;
else r[i]++;
}
int main()
{
int a[ ]={'d','a','e','f','c','b'};
int r[10];
range(a,r,6);
for(int i=0;i<6;i++)
cout<<r[i];
cout<<'\n';
rearrange(a,r,5);
for(int i=0;i<6;i++)
printf("%c",a[i]);
system("pause");
return 0;
}