矩阵中独立对角线的总和

时间:2018-02-01 20:10:30

标签: c++ matrix diagonal

我目前正在攻读考试,我试图处理动态矩阵。我遇到了关于计算矩阵的每个对角线的总和的问题,该矩阵的值和大小由用户选择。 我的程序的目的是打印,这要归功于一个函数,其参数是矩阵及其大小,即每个对角线和的值。我将向您展示代码并对其进行深入描述。

----------------
| 52 | 35 | 5  |  Example of matrix.
----------------  Imagine the first diagonal to be the one which goes right-to-left
| 2  | 71 | 1  |  and only consists in the number "47".
----------------  The second diagonal would be the one which goes right-to-left and
| 3  | 60 | 25 |  consists in the number "15" and "79".
----------------  So to get the sum of the second diagonal it would be:
| 79 | 55 | 98 |     
----------------  sum = m[n_rows - 1][diag - 2] + m[n_rows - 2][diag - 1]
| 47 | 15 | 66 | 
----------------  When diag > columns, in order to avoid error regarding matrix size,
                  I should lower the quantity "n_rows - 1" by the quantity "diag - n_columns".

根据我的描述,这就是我的想法:

void diag_matrix(int** m, int righe, int colonne){//righe = rows, colonne = columns. 
//M is the matrix.

// diag is the number of the diagonal I'm considering.
    for(int diag = 1; diag < (righe + colonne); diag++){ 

        int sum = 0;// the sum
        int i = 0;// the counter of the cicle
        int l = 0;// this is the value to riallign the row in case diag > column
        int temp = diag;//I use this variable not to modify the value of diag.

        // What I want is: when the column-index/row-index of the matrix reaches 0, the cicle will interrupt (after final iteration);
        while(righe - i - l - 1 > 0 || diag - 1 - i > 0){

            if (diag > colonne){//this condition changes l-value only if diag value is greater than column. Explanation outside the code
                l = diag - colonne;//this is the value to subtract to row-index
                temp = colonne;//this position is necessary to set column-index to its maxium.
            }

            sum = sum + m[righe - 1 - l - i][temp -1 - i];//pretty clear I think.
            i++;//the i is incremented by one.

        }// end of while-statement

        cout << "Somma Diagonale " << diag << " = " << sum << ".\n";

    }// end of for-statement

}//end of function declaration

显然它不起作用,但我无法弄清楚问题。

2 个答案:

答案 0 :(得分:2)

只要坐标停留在矩阵内,您就可以简化代码,找到每个对角线的起始位置,然后单步执行矩阵。 像这样:

#include <iostream>

using namespace std;

void diag_matrix(int** m, int rows, int cols)
{
    for (int diag = 1; diag < rows + cols; diag++)
    {
        int x, y;
        if (diag < rows)
        {
            y = rows - diag;
            x = 0;
        }
        else
        {
            y = 0;
            x = diag - rows;
        }
        int sum = 0;
        cout << "Summing diagonal #" << diag << ":";
        while ((x < cols) && (y < rows))
        {
            sum += m[y][x];
            cout << " " << m[y][x];
            x++;
            y++;
        }
        cout << " result: " << sum << "." << endl;
    }
}

int main(int argc, char* argv[])
{
    int rows = 5, cols = 3;
    int **m = new int*[rows];
    for (int i = 0; i < rows; i++)
        m[i] = new int[cols];
    m[0][0] = 52; m[0][1] = 35; m[0][2] =  5;
    m[1][0] =  2; m[1][1] = 71; m[1][2] =  1;
    m[2][0] =  3; m[2][1] = 60; m[2][2] = 25;
    m[3][0] = 79; m[3][1] = 55; m[3][2] = 98;
    m[4][0] = 47; m[4][1] = 15; m[4][2] = 66;
    diag_matrix(m, rows, cols);
    for (int i = 0; i < rows; i++)
        delete[] m[i];
    delete[] m;
    return 0;
}

答案 1 :(得分:1)

(这里曾经有一段,但是第二眼看,你没有说出它所说的错误。)

由于您没有发布到代码评论,这是一个解决方案,而不是详细的代码审查。 (如果你想让原始方法工作,我建议在调试器中单步执行它并检查变量首先得到错误值的位置。)它有很多样板来编译和运行,但是你最感兴趣的部分是diag_sums()及其评论。

这里的一个想法是使用OOP自动检查数组访问的范围。后者对于捕获一个错误等非常重要。如果需要,可以在生产中关闭它,但是当程序缓冲区溢出时,你真的不想让警告静音。这里的其他优化包括数据访问的位置和操作的强度减少:我们可以简单地提前计算每个对角线的长度,而不是检查每次迭代是否已经到达右边缘和下边缘。 / p>

由于带有 M 行的矩阵a的对角线数 k 的定义等同于:所有元素a[i][j]使得< em> M - k = i - j ,算法通过维持不变量来确保正确性,只要我们加1就保持不变量从 i j 开始,当 i j 为0时开始,并在 i时停止 = M j = N ,也就是说,从左边或上边缘到右边遍历对角线的每一步或下边缘,以先到者为准。

#include <assert.h>
#include <iostream>
#include <stddef.h>
#include <stdlib.h>
#include <utility>
#include <vector>

using std::cin;
using std::cout;

template <typename T>
  class matrix {
    public:
      matrix( const ptrdiff_t rows,
              const ptrdiff_t cols,
              std::vector<T>&& elems )
        : rows_(rows), cols_(cols), elems_(elems)
      {
        assert( rows_ > 0 );
        assert( cols_ > 0 );
        assert( elems_.size() == static_cast<size_t>(rows_*cols_) );
      }

      matrix( const ptrdiff_t rows,
              const ptrdiff_t cols,
              const std::vector<T>& elems )
        : matrix( rows, cols, std::move(std::vector<T>(elems)) )
      {}

      matrix( const matrix<T>& ) = default;
      matrix( matrix<T>&& ) = default;
      matrix& operator= ( const matrix<T>& ) = default;
      matrix& operator= ( matrix<T>&& ) = default;

      T& operator() ( const ptrdiff_t m, const ptrdiff_t n )
      {
        assert( m >= 0 && m < rows_ );
        assert( n >= 0 && n < cols_ );
        return elems_[static_cast<size_t>(m*cols_ + n)];
      }

      const T& operator() ( const ptrdiff_t m, const ptrdiff_t n ) const
      {
       /* Because this call does not modify any data, and the only reason the
        * member function above cannot be const is that it returns a non-const
        * reference to an element of elems, casting away the const qualifier
        * internally and then returning a const reference is a safe way to
        * re-use the code.
        */
        matrix<T>& nonconst = *const_cast<matrix<T>*>(this);
        return nonconst(m,n);
      }

      ptrdiff_t rows() const { return rows_; }
      ptrdiff_t cols() const { return cols_; }

    private:
      ptrdiff_t rows_;
      ptrdiff_t cols_;
      std::vector<T> elems_;
  };

template<typename T>
  std::ostream& operator<< ( std::ostream& out, const matrix<T>& x )
  /* Boilerplate to print a matrix. */
  {
    const ptrdiff_t m = x.rows(), n = x.cols();

    for ( ptrdiff_t i = 0; i < m; ++i ) {
      out << x(i,0);
      for ( ptrdiff_t j = 1; j < n; ++j )
        out << ' ' << x(i,j);

      out << '\n';
    } // end for

    return out;
  }

using elem_t = int;

std::vector<elem_t> diag_sums( const matrix<elem_t>& a )
/* Return a vector of all the diagonal sums of a.
 *
 * The first diagonal sum is a(rows-1,0)
 * The second is a(rows-2,0) + a(rows-1,1)
 * The third is a(rows-3,0) + a(rows-2,1) + a(rows-1,2)
 * And so on.  I.e., the kth diagonal is the sum of all elements a(i,j) such
 * that i - j == rows - k.
 *
 * If a is a M×N matrix, there are M diagonals starting in column zero, and
 * N-1 diagonals (excluding the one containing a(0,0) so we don't count it
 * twice) starting in row 0.  We process them bottom to top, then left to
 * right.
 *
 * The number of elements in a diagonal starting at a(i,0) is min{M-i, N}.  The
 * number of elements in a diagonal starting at a(0,j) is min{M, N-j}.  This is
 * because a diagonal stops at either the bottom edge or the left edge of a.
 */
{
  const ptrdiff_t m = a.rows(), n = a.cols();
  std::vector<elem_t> result;
  result.reserve( static_cast<size_t>(m + n - 1) );

  for ( ptrdiff_t i = m-1; i > 0; --i ) {
    elem_t sum = 0;

    const ptrdiff_t nk = (m-i) < n ? (m-i) : n;
    for ( ptrdiff_t k = 0; k < nk; ++k )
      sum += a(i+k, k);

    result.emplace_back(sum);
  } // end for i

  for ( ptrdiff_t j = 0; j < n; ++j ) {
    elem_t sum = 0;

    const ptrdiff_t nk = m < (n-j) ? m : (n-j);
    for ( ptrdiff_t k = 0; k < nk; ++k )
      sum += a(k, j+k);

    result.emplace_back(sum);
  } // end for j

  return result;
}

matrix<elem_t> read_input_matrix( const int row, const int column )
/* Reads in row*column consecutive elements from cin and packs them into a
 * matrix<elem_t>.
 */
{
  assert(row > 0);
  assert(column > 0);

  const ptrdiff_t nelements = row*column;
  assert(nelements > 0); // Check for overflow.

  std::vector<elem_t> result;
  result.reserve(static_cast<size_t>(nelements));

  for ( ptrdiff_t i = nelements; i > 0; --i ) {
    int x;
    cin >> x;
    assert(cin.good());
    result.push_back(x);
  }

  return matrix<elem_t>( row,
                         column,
                         std::move(result) );
}

template<typename T>
  bool print_sequence( const T& container )
  /* Prints the contents of a container in the format
   * "{47, 94, 124, 160, 148, 36, 5}".
   */
  {
    cout << "{";

    if ( container.begin() != container.end() )
      cout << *container.begin();

    for ( auto it = container.begin() + 1; it < container.end(); ++it )
      cout << ", " << *it;

    cout << "}\n";

    return cout.good();
  }

/* A simple test driver that reads in the number of rows, the number of
 * columns, and then row*columns int values, from standard input.  It
 * then passes the result to diag_matrix(), E.g.:
 *
 * 5 3
 * 52 35  5
 *  2 71  1
 *  3 60 25
 * 79 55 98
 * 47 15 66
 */
int main()
{
  int rows, columns;
  cin >> rows;
  cin >> columns;

  assert(cin.good());

  const matrix<elem_t> input_matrix = read_input_matrix( rows, columns );
  // cout << input_matrix; // Instrumentation.
  const std::vector<elem_t> sums = diag_sums(input_matrix);

  print_sequence(sums);

  return EXIT_SUCCESS;
}

您也可以print_sequence(diag_sums(read_input_matrix( rows, columns )))