LINUX.ORG.RU

Hello, Matrix!

 , , ,


0

3

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

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

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

#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 также очень приветствуются.

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

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

★★★★★

Последнее исправление: Twissel (всего исправлений: 5)

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

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

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

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

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

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

2 — строка идет как первый индекс

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

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

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

Twissel ★★★★★
() автор топика
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от 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)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.