2017-05-17 89 views
0

我想實現一個函數,它類似於2d矢量(矩陣)的輸入,包含它的原點元素,並根據輸入的列數和行數返回一個重定形的版本。重構後的矩陣需要以原始矩陣的所有元素以相同的行遍歷順序填充。用C++重塑2D矢量

我完成了下面的代碼:

vector<vector<int>> matrixReshape(vector<vector<int>>& nums, int r, int c) { 
    int r_old = nums.size(); 
    int c_old = nums[0].size(); 


    if(r*c != r_old*c_old) return nums; 

    vector<vector<int>> new_nums; 
    new_nums.resize(r); 

    // get the new matrix proper size 
    for (int i =0; i< r; i++){ 
     new_nums[i].resize(c); 
    } 

    int c_curr =0; 
    int r_curr =0; 

    // assign element 
    for (int i = 0; i < r_old; i ++){ 
     for (int j =0; j < c_old; j++){ 

      if(c_curr == c){ 
       r_curr++; 
       c_curr =0; 
      } 
      new_nums[r_curr][c_curr] = nums[i][j]; 
      c_curr++; 
     } 
    } 
    return new_nums; 
} 

不過,我覺得必須有這樣做的更好的方法。我搜索計算器,發現幾個問題

How can I resize a 2D C++ vector?

How can I resize a 2D vector of objects given the width and height?

然而,這些問題的答案都「復位」當前矩陣這是不是我想要的。所以我的問題是,是否有更快的方法通過將其元素重新排列到所需的新形狀來從2D矢量生成2D矢量?

+1

你要做的不是簡單的清理,但創建一個新的二維數組(也許有不同的大小),並用舊數組中的數據填充它。提示:像這樣初始化'new_nums':'vector > new_nums(r,vector (c));'。我沒有一個好主意來避免這兩個'for'循環,我不確定是否有辦法實現這種更有效的方法......(當然,您可以計算當前行中空閒列的數量並複製一次一堆的變量,但我希望這不會加速優化標誌被使用時的複製。) – Shadow

+0

要去你的XY。使用帶有包裝類的1D'vector',使其看起來像'vector'的'vector's所有你需要做的就是將源代碼的包裝vector'複製到目的地的包裝vector'(簡單的' data = src.data')並更改行和列的尺寸。這很好地包裝成構造函數。 – user4581301

回答

1

決定通過我的評論。這個答案頭很遠成XY領土,但它應該簡化事情很大

#include <iostream> 
#include <iomanip> 
#include <vector> 
#include <exception> 

// wrapping class for 2D matrixes  
class Matrix 
{ 
private: 
    size_t rows, columns; // large, unsigned datatype. Don't want negative 
          // indices, so why allow them? 
    std::vector<int> matrix; // 1D vector. Simple and easy to handle. 
          // also often much faster than vector of vectors 
          // due to improved spatial locality helping 
          // predictability of data access 
public: 
    // catchable exception should user request impossible dimension transformation 
    class BadDimsException: public std::exception 
    { 
    public: 
     const char* what() const noexcept 
     { 
      return "Invalid dimensions specified"; 
     } 
    }; 

    // build zero-filled Matrix 
    Matrix(size_t numrows, size_t numcols) : 
      rows(numrows), columns(numcols), matrix(rows * columns) 
    { 
    } 

    // build Matrix based on another Matrix with convertable dimensions 
    // All of the heavy lifting is performed in the member initializer list 
    // by simply copying data store of source Matrix 
    // if matrix cannot be transformed, the thrown exception leaves user with 
    // nothing to work with and no chance of trying to continue with an un- 
    // transformed matrix 
    Matrix(size_t numrows, size_t numcols, const Matrix & source) : 
      rows(numrows), columns(numcols), matrix(source.matrix) 
    { 
     if (rows * columns != source.rows * source.columns) 
     { // Bad dimensions. Blow up. 
      throw BadDimsException(); 
     } 
    } 

    // 2D to 1D mapping accessor 
    int & operator()(size_t row, size_t column) 
    { 
     // check bounds here 
     return matrix[row * columns + column]; 
    } 

    // 2D to 1D mapping accessor for constant Matrix 
    int operator()(size_t row, size_t column) const 
    { 
     // check bounds here 
     return matrix[row * columns + column]; 
    } 

    // dimension accessors 
    size_t getRows() const 
    { 
     return rows; 
    } 
    size_t getColumns() const 
    { 
     return columns; 
    } 
}; 


// stream formatter 
std::ostream & operator<<(std::ostream & out, const Matrix & mat) 
{ 
    for (size_t row = 0; row < mat.getRows(); ++row) 
    { 
     for (size_t col = 0; col < mat.getColumns(); ++col) 
     { 
      std::cout << std::setw(5) << mat(row, col); 
     } 
     std::cout << '\n'; 
    } 
    return out; 
} 

,並測試/演示用法:

int main() 
{ 
    Matrix one(2, 6); // make 2x6 matrix 
    int count = 0; 

    // set inputs to make errors really stand out 
    for (size_t row = 0; row < one.getRows(); ++row) 
    { 
     for (size_t col = 0; col < one.getColumns(); ++col) 
     { 
      one(row, col) = count++; 
     } 
    } 

    // print initial matrix 
    std::cout << one << '\n'; 

    // make reshaped matrix 
    Matrix two(3,4, one); 

    //print reshaped Matrix 
    std::cout << two << '\n'; 
    try 
    { 
     // make invalid reshaped matrix 
     Matrix three(3, 3, one); 

     // This should never print 
     std::cout << three << '\n'; 
    } 
    catch (const Matrix::BadDimsException & bde) 
    { 
     // Yay! Caught error! 
     std::cout << bde.what() << '\n'; 
    } 
} 
+0

只是一個小提示:爲了我的理解,在複製構造函數中,在檢查大小是否匹配(換句話說,在複製數據後引發異常)之前複製數據。在成員初始化列表中使用一個輔助函數,比如'rows(checked_rows(numrows,numcolumns,source.rows,source.columns)),...'會在複製之前產生異常。 –

+0

你是對的@Bob__。我還考慮過在測試和例外之後將副本移交給作業,但決定最好使用最簡單,最簡單的演示選項。 – user4581301

+0

哇!非常感謝您花時間。這是一個非常好的設計,閱讀你的答案幫助我學習一堆。 – SunnyIsaLearner