【问题标题】:Sorting two corresponding arrays对两个对应的数组进行排序
【发布时间】:2011-04-23 23:34:55
【问题描述】:

我这里有这段代码,它有两个数组。它对 arr[] 进行排序,因此最高值将位于索引 0 中。现在第二个数组 arr1[] 包含字符串,我希望代码应用任何内容将 arr[] 更改为 arr1[]。这样 arr[0] 将返回 6,而 arr1[0] 将返回字符串 "d1"。注意 "d1" 如何与 6 处于同一索引中?排序后,我希望相同的值仍然具有对应的字符串。

我该怎么做呢?

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <functional>
using namespace std;

int main() {
  int arr[ 5 ] = { 4, 1, 3, 6, 2 };  
  string arr1[ 5 ] = { "a1", "b1", "c1", "d1", "e1" };

  std::sort( arr, arr + 5, std::greater< int >() );
  cout << arr[0] << arr1[0] << endl;

  system("pause");
}

【问题讨论】:

  • 一旦您对arr 进行了排序,就不再知道原始排序顺序。如果要通过简单赋值对另一个数组进行排序,则需要存储原始顺序。
  • 如果arr 和arr1 是相关的,为什么它们不首先存储在一起(比如作为一个结构)?

标签: c++ arrays


【解决方案1】:

您需要将它们组合在一起,然后对组合的对进行排序,然后取消组合。

int arr[ 5 ] = { ... };
string arr1[ 5 ] = { ... };
pair<int, string> pairs[ 5 ];

for ( int i = 0; i < 5; ++i )
  pairs[ i ] = make_pair( arr[ i ], arr1[ i ] );

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

for ( int i = 0; i < 5; ++i )
{
  arr[ i ] = pairs[ i ].first;
  arr1[ i ] = pairs[ i ].second;
}

真的,如果arr 和arr1 相关,那么无论如何它们都应该存储为pair(或者至少是自定义的struct)。这样您就不需要将其用作中间步骤。

【讨论】:

    【解决方案2】:

    不是对数组进行排序,而是对索引进行排序。也就是说,你有

    int arr[5]={4,1,3,6,2}
    string arr1[5]={"a1","b1","c1","d1","e1"};
    

    你做

    int indices[5]={0,1,2,3,4};
    

    现在您制作了一个看起来像这样的排序索引比较器(只是想法,您可能需要稍微修复一下)

    class sort_indices
    {
       private:
         int* mparr;
       public:
         sort_indices(int* parr) : mparr(parr) {}
         bool operator()(int i, int j) const { return mparr[i]<mparr[j]; }
    }
    

    现在你可以使用 stl 排序了

    std::sort(indices, indices+5, sort_indices(arr));
    

    完成后,索引数组将使得arr[indices[0]] 是第一个元素。同样arr1[indices[0]] 是对应的对。

    当您尝试对大型数据对象进行排序时,这也是一个非常有用的技巧,您不需要在每次交换时移动数据,只需移动索引即可。

    【讨论】:

    • 很好的答案,除了他正在降序排序的小问题,但是是的,这就是这样做的方法。
    • 是的,并且 operator() 也需要为 const 才能正常工作。 :)
    • 请注意,如果您确实需要对两个数组进行排序,那么使用索引数组将原始数组排序并非易事。
    • @SteveJessop 在我看来微不足道?创建新数组 ar[] 和 ar1[] 然后用 ar[i] = arr[indices[i]] 和 ar1[i] = arr1[indices[i]] 循环
    • @rint:这几乎是微不足道的,但我想说不完全。在示例中,数组属于可复制分配的类型。情况总是如此并非易事 :-) 此外,使用第二个数组可能需要比单独使用 std::sort 更多的内存。因此,移动到第二个数组然后移回编写起来是微不足道的,但不是最佳的,您可能会也可能不会在意。
    【解决方案3】:

    编写您自己的迭代器并使用 STD:sort。无需 3rd 方库即可轻松编写不到 50 行代码。 交换功能在这里非常重要。

    #include <iostream>
    #include <iterator>     // std::iterator, std::input_iterator_tag
    #include <algorithm>
    
    using namespace std;
    
    struct Tuple;
    struct RefTuple;
    #define TUPLE_COMMON_FUNC(C, D, E, F)            \
        C##::C## (Tuple& t) ##D                        \
        C##::C## (RefTuple& t) ##D                    \
        void C##::operator = (Tuple& t) ##E        \
        void C##::operator = (RefTuple& t) ##E    \
        bool C##::operator < (const Tuple& t) const ##F        \
        bool C##::operator < (const RefTuple& t) const ##F
    #define ASSIGN_1    : i(t.i), j(t.j), s(t.s) {}
    #define ASSIGN_2    { i = t.i; j = t.j; s = t.s; }
    #define SORT_CRITERIA \
        return (j < t.j) || (j == t.j && (i < t.i));
    struct Tuple {
        int i, j, s;
        TUPLE_COMMON_FUNC(Tuple, ; , ; , ;)
    };
    struct RefTuple {
        int &i, &j, &s;
        RefTuple(int &x, int &y, int &z): i(x), j(y), s(z) {}
        TUPLE_COMMON_FUNC(RefTuple, ; , ; , ;)
    };
    TUPLE_COMMON_FUNC(Tuple, ASSIGN_1, ASSIGN_2, {SORT_CRITERIA})
    TUPLE_COMMON_FUNC(RefTuple, ASSIGN_1, ASSIGN_2, {SORT_CRITERIA})
    
    void swap(RefTuple& t1, RefTuple& t2) {
        t1.i ^= t2.i; t2.i ^= t1.i; t1.i ^= t2.i;
        t1.j ^= t2.j; t2.j ^= t1.j; t1.j ^= t2.j;
        t1.s ^= t2.s; t2.s ^= t1.s; t1.s ^= t2.s;
    }
    
    class IterTuple : public iterator<random_access_iterator_tag, Tuple> {
        int *i, *j, *s, idx;
    public:
        IterTuple(int* x, int*y, int* z, int l) : i(x), j(y), s(z), idx(l) {}
        IterTuple(const IterTuple& e) : i(e.i), j(e.j), s(e.s), idx(e.idx) {}
        RefTuple operator*() { return RefTuple(i[idx], j[idx], s[idx]);  }
        IterTuple& operator ++ () { idx++; return *this; }
        IterTuple& operator -- () { idx--; return *this; }
        IterTuple operator ++ (int) { IterTuple tmp(*this); idx++; return tmp; }
        IterTuple operator -- (int) { IterTuple tmp(*this); idx--; return tmp; }
        int operator - (IterTuple& rhs) { return idx - rhs.idx;    }
        IterTuple operator + (int n) { IterTuple tmp(*this); tmp.idx += n; return tmp; }
        IterTuple operator - (int n) { IterTuple tmp(*this); tmp.idx -= n; return tmp; }
        bool operator==(const IterTuple& rhs) {        return idx == rhs.idx;    }
        bool operator!=(const IterTuple& rhs) {     return idx != rhs.idx;  }
        bool operator<(IterTuple& rhs) {     return idx < rhs.idx;   }
    };
    
    int Ai[10] = {0, 0, 2, 3, 2, 4, 1, 1, 4, 2};
    int Aj[10] = {0, 2, 3, 4, 4, 4, 0, 1, 0, 2};
    int Ax[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    int main () {
        IterTuple from(Ai, Aj, Ax, 0);
        IterTuple until(Ai, Aj, Ax, 10);
    
        sort(from, until);
    
        for (IterTuple it = from; it != until; it++)
            cout << (*it).i << ' ' << (*it).j << ' ' << (*it).s << '\n';
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      我相信编写自己的 QuickSort 变体更简单,并且结果会比使用索引映射自定义迭代器或数组更好。

      QuickSort 不是稳定排序。

      template<class A, class B> void QuickSort2Desc(A a[], B b[], int l, int r)
      {               
          int i = l;
          int j = r;
          A v = a[(l + r) / 2];
          do {
              while (a[i] > v)i++;
              while (v > a[j])j--;
              if (i <= j)
              {
                  std::swap(a[i], a[j]);
                  std::swap(b[i], b[j]);          
                  i++;
                  j--;
              };
          } while (i <= j);
          if (l < j)QuickSort2Desc(a, b, l, j);
          if (i < r)QuickSort2Desc(a, b, i, r);
      }
      

      【讨论】:

      • 这段代码看起来不太可能是正确的,因为它说if (i &lt;= j) { std::swap(a[i], a[j]) ... 这将导致每当i == j 时与它自己交换a[i]。所以我认为“编写自己的快速排序”可能是最好的解决方案,但“剪切和粘贴此特定代码”在 2019 年 1 月 31 日绝对不是一个好主意。
      猜你喜欢
      • 2016-03-12
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      • 2014-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多