如何在排序后获得索引排列

时间:2013-07-09 17:11:40

标签: c++ algorithm

给定数组arr = {5, 16, 4, 7},我们可以通过sort(arr, arr+sizeof(arr)/sizeof(arr[0]))对其进行排序。 所以现在数组arr = {4, 5, 7, 16}和排序数组的排列索引是{2, 0, 3, 1}。 换句话说,原始数组中的arr[2]现在是位置0中排序数组中的最小元素。

是否有一种有效的方法可以获得排列索引?

谢谢

8 个答案:

答案 0 :(得分:40)

创建索引数组,用数字0..N-1填充它,并使用自定义比较器对其进行排序。比较器应比较索引lhsrhs的原始数组中的项目。以这种方式对索引数组进行排序将它们重新排序为排列:

vector<int> data = {5, 16, 4, 7};   
vector<int> index(data.size(), 0);
for (int i = 0 ; i != index.size() ; i++) {
    index[i] = i;
}
sort(index.begin(), index.end(),
    [&](const int& a, const int& b) {
        return (data[a] < data[b]);
    }
);
for (int i = 0 ; i != index.size() ; i++) {
    cout << index[i] << endl;
}

这会打印2, 0, 3, 1

这是demo on ideone

注意:您可以使用index按排序顺序检索data

for (int i = 0 ; i != index.size() ; i++) {
    cout << data[index[i]] << endl;
}

答案 1 :(得分:5)

为什么不放一些卫星数据?不是对数字进行排序,而是对数字对及其索引进行排序。由于排序首先在对的第一个元素上完成,因此不应该破坏稳定的排序算法。

对于不稳定的算法,这会将其更改为稳定的算法。

但请注意,如果您尝试按这种方式进行排序,则会在排序时生成索引,而不是在。

之后

此外,由于知道排列索引会导致O(n)排序算法,所以你不能比O(nlogn)更快地完成它。

答案 2 :(得分:4)

在c ++中,我们可以使用pair数据类型轻松完成此操作。以下示例代码;

arr = {5, 16, 4, 7};
vector<pair<int,int> >V;
for(int i=0;i<4;i++){
    pair<int,int>P=make_pair(arr[i],i);
    V.push_back(P);
}

sort(V.begin(),V.end());

所以V [i] .first是第i个值而V [i] .second是第i个索引。所以要在排序数组中打印索引。

for(int i=0;i<4;i++)cout<<V[i].second<<endl;

请注意,在对对象项的数组(或向量)进行排序时,首先会根据第一个值对数组进行排序。如果两对具有相同的第一个值,那么它们将根据它们的第二个值进行排序。

答案 3 :(得分:1)

Multimap可以解决问题

template<typename TIn, typename TOut>
sortindex(const TIn &first, const TIn &last, TOut &out) {
    using ValT = typename std::decay<decltype(*first)>::type;
    std::multimap<ValT, size_t> sindex;

    for(auto p=first; p != last; p++)
        sindex.emplace(*p, std::distance(first, p));

    for(auto &&p: sindex)
        *out++ = p.second;
}

可以这样使用:

std::vector<size_t> a{32, 22, 45, 9, 12, 15};
std::vector<size_t> indexes;

sortindex(a.begin(), a.end(), std::back_inserter(indexes));

如果需要在排序值和索引之间进行耦合,则可以直接返回multimap,而不是将索引写入输出迭代器。

template<typename TIn>
auto
sortindex(const TIn &first, const TIn &last)
    --> std::multimap<typename std::decay<decltype(*first)>::type, size_t> 
{  // return value can be commented out in C++14
    using ValT = typename std::decay<decltype(*first)>::type;
    std::multimap<ValT, size_t> sindex;

    for(auto p=first; p != last; p++)
        sindex.emplace(*p, std::distance(first, p));

    return sindex;
}

答案 4 :(得分:0)

我最近不得不在PHP中解决类似的问题。 您可以创建一个本地比较函数,供PHP的UASORT排序算法使用。在排序的数组上调用array_keys(),这应该吐出你的排列数组。

// test array

$ tArray = array(&#39; 2&#39;,&#39; 10&#39;,&#39; 1&#39;,&#39; 23&#39;,&#39; 8&# 39;,&#39; 3&#39;);

//排序数组;维护索引关联,使用uasort;否则使用usort等

uasort($ tArray,&#39; compareSize&#39;);

//生成的密钥是您的排列索引(如果在上一步中使用了uasort)

$ Keys = array_keys($ tArray);

//本地比较功能

function compareSize($ a,$ b) {

if($ a == $ b){return 0; } else {return($ a&lt; $ b)? -1:1; }

}

=============================================== ======================== 结果:

sorted =:Array([2] =&gt; 1 [0] =&gt; 2 [5] =&gt; 3 [4] =&gt; 8 [1] =&gt; 10 [3] =&gt; 23 )

keys =:Array([0] =&gt; 2 [1] =&gt; 0 [2] =&gt; 5 [3] =&gt; 4 [4] =&gt; 1 [5] =&gt; 3 )

答案 5 :(得分:0)

我认为我们可以在不使用vector的情况下解决这个问题。 我是新手,说实话,我不明白你上面写的是什么,你们所有人都使用了我将要学习的矢量:)))(我很懒) 这是我的方式:

//首先,将数组a []复制到数组b []

   void copyarray(double b[],double a[],int n){
     for(int i=0;i<n;i++)b[i]=a[i];
    }

//其次,排序数组a [](减少)

/ *第三,“sorter”数组a [],表示:在数组a []中,如果存在相同的值,它们将合并为一个!   我将设置数组o []是“排序数组a []”* /

 void sorter(double o[],double a[],int n,int &dem){   
     int i;
     o[0]=a[0];
     for(i=1;i<n;i++){
        if(a[i]!=a[i-1]){
          dem++; o[dem]=a[i];
         }
      }
      dem++;
 }

/ * 4,我们的主要目标:获取索引:我将索引放入数组c [] * /

void index_sort(double o[],double b[], double c[], int dem, int n){
    int i,j,chiso=0;
    for(j=0;j<dem;j++){
       for(i=0;i<n;i++){
          if(b[i]==o[j]){
             c[chiso]=i;
             chiso++;
           }
        }
     }
 }

  // DONE!
 int main(){
        int n,dem=0;
         double a[100],b[100],c[100],o[100];
         cin>>n;
         input(a,n);
         copyarray(b,a,n);
         copyarray(c,a,n);
         sort(a,n);
         sorter(o,a,n,dem); 
         index_sort(o,b,c,dem,n); 
         for(int i=0;i<n;i++) cout<<c[i]<<" ";
   }

答案 6 :(得分:0)

对于那些正在研究 @Sergey Kalinichenko 解决方案的 C++17 接口的人,以下代码段可能有用。

template <class ExecutionPolicy, typename RandomIt>
auto sort_permutation(ExecutionPolicy&& policy, RandomIt cbegin, RandomIt cend) {
    auto len = std::distance(cbegin, cend);
    std::vector<size_t> perm(len);
    std::iota(perm.begin(), perm.end(), 0U);
    std::sort(policy, perm.begin(), perm.end(),
          [&](const size_t& a, const size_t& b)
    {
        return *(cbegin+a) < *(cbegin+b);
    });
    return perm;
}

你可以这样使用:

std::vector<int> a {2, 3, 1, 2, 3, 6, 8, 5};
auto r = sort_permutation(std::execution::par, a.cbegin()+1, a.cend()-1);

如果您不想与 tbb 链接,请删除执行策略争论。

答案 7 :(得分:-1)

是的,有一个O(NlogN)时间。因为排序需要花费O(NlogN)时间,这不会影响整体时间复杂度。
时间复杂度O(NlogN)
空间复杂性O(N)
其中 N =输入数组中的元素数

<强>算法:

  1. 复制输入数组(P)称之为Q。
  2. 对输入数组P进行排序。
  3. 对于Q中的每个数字,执行二进制搜索以在P中找到该元素的索引。