使用std :: sort来排序Matrix

时间:2018-05-14 10:01:06

标签: c++ sorting stl

有没有办法可以使用std?

中的sort函数对矩阵元素进行排序
//Using this matrix
vector<vector<string>> mat;

例如,如果你有

5 2 1
0 0 2
1 4 3

结果将是

0 0 1
1 2 2
3 4 5

2 个答案:

答案 0 :(得分:2)

要存储矩阵,std::vector的嵌套不是最佳解决方案。由于任何行都管理自己的大小,因此矩阵类没有内在授予的唯一列大小。

假设OP被认为使用现有类型(可能没有改变),我基于此编写了我的样本。

一个解决方案(实施工作量最少)将是

  1. 将矩阵(std::vector<std::vector<std::string> >)复制到std::vector<std::string>
  2. 类型的临时表中
  3. std::sort()应用于此临时
  4. 再次将排序后的矢量分配给矩阵。
  5. 考虑到元素的移动可能很昂贵,可以选择

    1. 建立索引对向量
    2. std::sort()使用自定义较少的仿函数(考虑矩阵元素)。
    3. 之后,索引对向量可用于按排序顺序访问原始矩阵元素。

      后者显示在我的示例代码中:

      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      
      typedef std::vector<std::string> Row;
      typedef std::vector<Row> Matrix;
      typedef std::pair<size_t, size_t> IndexPair;
      
      struct LessMatrix {
        const Matrix &mat;
        LessMatrix(const Matrix &mat): mat(mat) { }
        bool operator()(const IndexPair &i1, const IndexPair &i2)
        {
          return mat[i1.first][i1.second] < mat[i2.first][i2.second];
        }
      };
      
      std::ostream& operator<<(std::ostream &out, const Matrix &mat)
      {
        for (const Row row : mat) {
          for (const std::string elem : row) out << ' ' << elem;
          out << '\n';
        }
        return out;
      }
      
      int main()
      {
        Matrix mat = {
          { "5", "2", "1" },
          { "0", "0", "2" },
          { "1", "4", "3" }
        };
        // print input
        std::cout << "Input:\n" << mat << '\n';
        // indexify matrix
        std::vector<IndexPair> indices;
        for (size_t i = 0, n = mat.size(); i < n; ++i) {
          const std::vector<std::string> &row = mat[i];
          for (size_t j = 0, m = row.size(); j < m; ++j) {
            indices.push_back(std::make_pair(i, j));
          }
        }
        // sort matrix
        LessMatrix less(mat);
        std::sort(indices.begin(), indices.end(), less);
        // print output
        Matrix matOut;
        { size_t i = 0; const size_t nCols = 3;
          for (const IndexPair &index : indices) {
            if (i % nCols == 0) matOut.push_back(Row());
            matOut.back().push_back(mat[index.first][index.second]);
            ++i;
          }
        }
        std::cout << "Output:\n" << matOut << '\n';
        // done
        return 0;
      }
      

      输出:

      Input:
       5 2 1
       0 0 2
       1 4 3
      
      Output:
       0 0 1
       1 2 2
       3 4 5
      

      Life demo on coliru

      OP抱怨创建一个单独的索引向量。我怀疑自定义随机访问迭代器可能是替代(直接对矩阵排序)。我必须承认我之前没有这样做,但出于好奇,我试图解开这个问题:

      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <cassert>
      
      typedef std::vector<std::string> Row;
      typedef std::vector<Row> Matrix;
      
      struct MatrixIterator {
        typedef size_t difference_type;
        typedef std::string value_type;
        typedef std::string* pointer;
        typedef std::string& reference;
        typedef std::random_access_iterator_tag iterator_category;
      
        // accessed matrix
        Matrix &mat;
        // index of row, index of column
        size_t i, j;
      
        MatrixIterator(Matrix &mat, size_t i = 0, size_t j = 0): mat(mat), i(i), j(j) { }
      
        MatrixIterator& operator =(const MatrixIterator &iter)
        {
          assert(&mat == &iter.mat);
          i = iter.i; j = iter.j;
          return *this;
        }
      
        size_t nCols() const { return mat.front().size(); }
      
        std::string& operator *() { return mat[i][j]; }
        const std::string& operator *() const { return mat[i][j]; }
      
        MatrixIterator& operator ++() { return *this += 1; }
        MatrixIterator operator ++(int) { MatrixIterator iter(*this); ++*this; return iter; }
      
        MatrixIterator& operator --() { return *this -= 1; }
        MatrixIterator operator --(int) { MatrixIterator iter(*this); --*this; return iter; }
      
        MatrixIterator& operator += (size_t n)
        {
          j += i * nCols() + n; i = j / nCols(); j %= nCols(); return *this;
        }
      
        MatrixIterator operator + (size_t n) const
        {
          MatrixIterator iter(*this); iter += n; return iter;
        }
        friend MatrixIterator operator + (size_t n, const MatrixIterator &iter)
        {
          MatrixIterator iter2(iter); iter2 += n; return iter2;
        }
      
        MatrixIterator& operator -= (size_t n)
        {
          j += i * nCols() - n; i = j / nCols(); j %= nCols();
          return *this;
        }
      
        MatrixIterator operator - (size_t n) const
        {
          MatrixIterator iter(*this); iter -= n; return iter;
        }
        size_t operator - (const MatrixIterator &iter) const
        {
          return (i * nCols() + j) - (iter.i * iter.nCols() + iter.j);
        }
      
        std::string& operator[](size_t i) { return mat[i / nCols()][i % nCols()]; }
        const std::string& operator[](size_t i) const { return mat[i / nCols()][i % nCols()]; }
      
        bool operator == (const MatrixIterator &iter) const
        {
          return i == iter.i && j == iter.j;
        }
        bool operator != (const MatrixIterator &iter) const { return !(*this == iter); }
      
        bool operator < (const MatrixIterator &iter) const
        {
          return i * nCols() + j < iter.i * iter.nCols() + iter.j;
        }
        bool operator > (const MatrixIterator &iter) const { return iter < *this; }
        bool operator <= (const MatrixIterator &iter) const { return !(iter > *this); }
        bool operator >= (const MatrixIterator &iter) const { return !(*this < iter); }
      };
      
      MatrixIterator begin(Matrix &mat) { return MatrixIterator(mat, 0, 0); }
      MatrixIterator end(Matrix &mat) { return MatrixIterator(mat, mat.size(), 0); }
      
      std::ostream& operator<<(std::ostream &out, const Matrix &mat)
      {
        for (const Row row : mat) {
          for (const std::string elem : row) out << ' ' << elem;
          out << '\n';
        }
        return out;
      }
      
      int main()
      {
        Matrix mat = {
          { "5", "2", "1" },
          { "0", "0", "2" },
          { "1", "4", "3" }
        };
        // print input
        std::cout << "Input:\n" << mat << '\n';
        // sort matrix
        std::sort(begin(mat), end(mat));
        // print output
        std::cout << "Output:\n" << mat << '\n';
        // done
        return 0;
      }
      

      输出:

      Input:
       5 2 1
       0 0 2
       1 4 3
      
      Output:
       0 0 1
       1 2 2
       3 4 5
      

      Life demo on coliru

      注意:

      我使用了cppreference.com上的描述

      作为&#34;要求 - 作弊表&#34;并实现了那里描述的一切。一些细节,我决定猜测。 (特别是关于typedef我不太确定如何纠正它们。)

答案 1 :(得分:1)

您可以通过创建自定义包装器矩阵类并定义自己的迭代器来对嵌套向量进行排序而无需额外的数据复制:

#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

class MyMatrix {
 public:
  using DataStore = std::vector<std::vector<std::string> >;

  // Note: Make sure MyMatrix DO NOT out-live its `data` argument!
  MyMatrix(DataStore& data) : data_(data) {
    // Check that
    //  1. data.size() > 0;
    //  2. data[i].size() > 0 and same for all valid i.
  }

  class Iterator : public std::iterator<std::random_access_iterator_tag,
                                        std::string, int> {
   public:
    Iterator(DataStore& data) : data_(&data), index_(0) {}
    Iterator(DataStore& data, int index) : data_(&data), index_(index) {}
    Iterator(const Iterator& it) : data_(it.data_), index_(it.index_) {}

    Iterator& operator=(const Iterator& it) {
      data_ = it.data_;
      index_ = it.index_;
    }
    operator bool() const {
      return index_ >= 0 && index_ < data_->size() * (*data_)[0].size();
    }

    bool operator==(const Iterator& it) const {
      return data_ == it.data_ && index_ == it.index_;
    }
    bool operator!=(const Iterator& it) const {
      return data_ != it.data_ || index_ != it.index_;
    }

    Iterator& operator++() { ++index_; return *this; }
    Iterator& operator--() { --index_; return *this; }
    Iterator operator++(int) { return Iterator(*data_, index_++); }
    Iterator operator--(int) { return Iterator(*data_, index_--); }

    Iterator& operator+=(int offs) { index_ += offs; return *this; }
    Iterator& operator-=(int offs) { index_ -= offs; return *this; }
    Iterator operator+(int offs) { return Iterator(*data_, index_ + offs); }
    Iterator operator-(int offs) { return Iterator(*data_, index_ - offs); }
    int operator-(const Iterator& it) { return index_ - it.index_; }

    std::string& operator*() {
      return (*data_)[index_ / data_->size()][index_ % (*data_)[0].size()];
    }
    const std::string& operator*() const { return operator*(); }

   private:
    DataStore* data_;
    int index_;
  }; // class Iterator

  Iterator iterator() { return Iterator(data_); }
  Iterator begin() { return Iterator(data_, 0); }
  Iterator end() { return Iterator(data_, data_.size() * data_[0].size()); }

 private:
  DataStore& data_;
};  // class MyMatrix

然后sort可以应用于MyMatrix,如下所示:

#include <iostream>

int main()
{
  std::vector<std::vector<std::string> > store = {
    { "5", "2", "1" },
    { "0", "0", "2" },
    { "1", "4", "3" }
  };

  MyMatrix matrix(store);

  for (const auto& row : store) {
    for (const auto& item : row) { std::cout << item <<' '; }
    std::cout <<'\n';
  }
  std::cout <<'\n';

  std::sort(matrix.begin(), matrix.end());

  for (const auto& row : store) {
    for (const auto& item : row) { std::cout << item <<' '; }
    std::cout <<'\n';
  }
  std::cout <<'\n';
}

运行上面的代码将产生以下输出:

5 2 1 
0 0 2 
1 4 3 

0 0 1 
1 2 2 
3 4 5