LINUX.ORG.RU

Hello, Matrix!

 , , ,


0

3

Недавно тут пришлось тряхнуть стариной, а именно написать код который выводит диагонали (в простейшем случае квадратной матрицы) от a(11) до a(33), соответственно, сверху вниз, слева направо.

Пример достаточно эффективной реализации описан тут

Решение задачи «в лоб»

#include <stdio.h>

 
int main(){
    int row_count, col_count, cur_row, cur_col;
    int matrix[3][3] = { 1, 2, 3,
			 4, 5, 6,
			 7, 8, 9};
    printf("Printing matrix diagonally\n");
    for(col_count = 0; col_count < 3; col_count++){
        cur_col = col_count; cur_row = 0;
        for(;cur_col >= 0 && cur_row < 3; cur_col--, cur_row++){
            printf("%d ", matrix[cur_row][cur_col]); 
        }
        printf("\n");
    }
    for(row_count = 1; row_count < 3; row_count++){
        cur_col = 2; cur_row = row_count;
        for(;cur_col >= 0 && cur_row < 3; cur_col--, cur_row++){
            printf("%d ", matrix[cur_row][cur_col]); 
        }
        printf("\n");
    }
     
    getchar();
    return 0;
}

Но все же, господа, хочется, чтобы код был читабельным и эффективным. А посему, версии на Си++ с обертками на основе std::vector также очень приветствуются.

Так как принцип обхода элементов матрицы я вроде бы понял, но ощущения неуклюжести от применяемых методов меня не покинуло.

Вот запостил эту фигню сюда :-)

★★★★★

use MTL/zkcm/любую библиотеку для работы с матрицами. В таком виде код делать, вообще говоря, не здорово, так как размер матрицы может измениться, может потребоваться след посчитать, может потребоваться вывести n-ю побочную диагональ. Много чего может потребоваться. За GSL браться не советую - уж больно громоздкие названия, работать не удобно с ней.

Также, в реальной жизни матрицы будут размером побольше раз так минимум в 1000 и лежать на куче, следовательно, нужна аккуратная работа с памятью.

aido ★★ ()
Ответ на: комментарий от aido

В таком виде код делать, вообще говоря, не здорово, так как размер матрицы может измениться.

И ежу понятно. Этот пример описывает решение задачи наименее эффективным способом, простым перебором. Именно потому, что для практических задач в здравом уме так никто делать не будет, я и создал топик... хочется обобщенного эффективного подхода, размером до 50 кода строк максимум.

Twissel ★★★★★ ()

Простой вопрос: matrix[1][2] = 2 или 4?

Xintrea ★★★★★ ()
Ответ на: комментарий от vvviperrr

Надо было быстро набросать, к теме треда это отношения не имеет :-)

В остальном согласен.

Twissel ★★★★★ ()
Ответ на: комментарий от Twissel

Надо было быстро набросать

и для этого ты ввел лишние 10 символов?

vvviperrr ★★★★★ ()
Ответ на: комментарий от vvviperrr

Печать вслепую :-)

Но давайте по существу дела

Twissel ★★★★★ ()

Как вариант:

#include <array>
#include <stdio.h>

template <class T, size_t D>
using Matrix = std::array<std::array<T, D>, D>;

// 9'012 инструкций процессора
int main()
{
    constexpr int dim = 3;
    constexpr Matrix<int, dim> matrix{{
        { 1, 2, 3 },
        { 4, 5, 6 },
        { 7, 8, 9 },
    }};

    puts("Printing matrix diagonally");

    for (int r = 0; r < dim * 2; ++r) {
        for (int c = r, tr = 0; c >= 0; --c, ++tr) {
            if (tr < dim && c < dim)
                printf("%i ", matrix[tr][c]);
        }
        puts("");
    }

    return 0;
}
anonymous ()
Ответ на: комментарий от vvviperrr

он ввел, потому что вендузятник и студия открывает и закрывает консоль не показывая результат :)

invy ★★★★★ ()
Ответ на: комментарий от invy

Да, да, да!

И сейчас же верните мой conio.h :-)

А если серьезно, я не знал под какой ОС будет запускаться код, вот и перестраховался (это было вроде теста на сообразительность).

Вдруг действительно под офтопом.

Twissel ★★★★★ ()
Ответ на: комментарий от invy

а нехер с дебагом запускать. жмешь контрол ф5 - вуаля.

vvviperrr ★★★★★ ()
Ответ на: комментарий от Xintrea

Простой вопрос: matrix[1][2] = 2 или 4?

Хороший вопрос с подвохом. :)

Sorcerer ★★★★★ ()
Ответ на: комментарий от Sorcerer

Ты это к тому, что индексация с нуля или я не вкурил?

Twissel ★★★★★ ()

Последнее исправление: cetjs2 16.02.2016 18:14:32

Что, опять спам уведомлениями? Мегабакса забыли?

d ★★★ ()

Надо было так:

(defun main ()
  (let* ((matrix #2A((1 2 3)
                     (4 5 6)
                     (7 8 9)))
         (min-dim-1 (- (apply #'min (array-dimensions matrix))
                       1)))
    (loop :for i :from 0 :to min-dim-1 
          :collect (aref matrix i i)
            :into d1
          :collect (aref matrix i (- min-dim-1 i))
            :into d2
          :finally (return (values d1 d2)))))
ados ★★★★★ ()

В boost::math есть же матрицы и методы работы с ними.

DELIRIUM ★★★★★ ()
Ответ на: комментарий от DELIRIUM

Гляну при случае.

Хотя задача не особо и практическая.

Twissel ★★★★★ ()

А посему, версии на Си++ с обертками на основе std::vector также очень приветствуются.

Хотя задача не особо и практическая.

Тогда вариант на учебном классе матрицы:

#include <iostream>
#include <sstream>
#include <vector>

class Matrix {
private:
  size_t m_; // количество строк
  size_t n_; // количество столбцов
  std::vector<double> a_; // храним матрицу в одномерном массиве с доступом к i,j элементу как i*n_+j
public:

  // Конструктор, передаём количество строк m и количество столбцов n
  Matrix(size_t m, size_t n)
    : m_(m),  // инициализация m_
      n_(n),  // инициализация n_
      a_(m*n) // инициализация вектора размером m*n
  {} // больше делать нечего

  Matrix(size_t m, size_t n, const std::vector<double> &a)
    : m_(m),
      n_(n),
      a_(a)
  {
    if (a_.size() != m*n)
      a_.resize(m*n);
  }

  // деструктор и т.п. нам реализовывать незачем, "правило нуля" не нарушали.

  // для внешних пользователей класса определим возможность прямого доступа к элементам
  // нарушаем ряд канонов об правилах изменения данных класса, но нам побоку :)
  // не забываем про проверку диапазона
  double& operator() (size_t i, size_t j) { return a_.at(i*n_+j); };

  size_t rows() const { return m_; };
  size_t cols() const { return n_; };

  // это пример использования матрицы внутри класса
  void test() {
    (*this)(1,1) = 100;
  }

  // остальное реализуй по необходимости
};

int main() {

  size_t n = 3;
  Matrix M(n,n,
    { 1.0, 2.0, 3.0,
      4.0, 5.0, 6.0,
      7.0, 8.0, 9.0 });

  std::stringstream ss;

  for (size_t slice = 0; slice < 2 * n - 1; ++slice) {
    ss << "Slice " << slice << ":";
    size_t z = slice < n ? 0 : slice - n + 1;
    for (size_t j = z; j <= slice - z; ++j) {
      ss << " " << M(j,slice - j);
    }
    ss << std::endl;
  }

  std::cout << ss.str();

  return 0;
};
AlexVR ★★★★★ ()
Ответ на: комментарий от AlexVR

Спасибо за реализацию через класс.

Хотя с чисто «алгоритмической» точки зрения проще чем итерация по самим диагоналям коих имеется 2N-1 не придумаешь, да и не нужно, по здравому размышлению.

Twissel ★★★★★ ()
Последнее исправление: Twissel (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.