Матрица треугольника Паскаля с использованием векторов в C++

Мне нужно сделать матрицу треугольника Паскаля с использованием векторов, а затем распечатать ее.

Этот алгоритм будет работать с массивами, но почему-то он не работает с матрицей, использующей векторы.

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

typedef std::vector<std::vector<int>> Matrix;

int NumberOfRows(Matrix m) { return m.size(); }
int NumberOfColumns(Matrix m) {
  if (m.size() != 0)
    return m[0].size();
  return 0;
}

Matrix PascalTriangle(int n) {
  Matrix mat;
  int a;
  for (int i = 1; i <= n; i++) {
    a = 1;
    for (int j = 1; j <= i; j++) {
      if (j == 1)
        mat.push_back(j);
      else
        mat.push_back(a);
      a = a * (i - j) / j;
    }
  }
  return mat;
}

void PrintMatrix(Matrix m, int width) {
  for (int i = 0; i < NumberOfRows(m); i++) {
    for (int j = 0; j < NumberOfColumns(m); j++)
      std::cout << std::setw(width) << m[i][j];
    std::cout << std::endl;
  }
}

int main() {
  Matrix m = PascalTriangle(7);
  PrintMatrix(m, 10);

  return 0;
}

Я ничего не получаю на экране, и вот тот же код, только без матрицы с использованием векторов программа (что работает нормально).

Не могли бы вы помочь мне исправить этот код?

Matrix mat; -- Как добавить элементы в пустой вектор? Я не вижу обращений к push_back, insert, emplace_back, resize и т. д.
PaulMcKenzie 19.03.2022 23:08

Я пробовал push_back не работает

user18516112 19.03.2022 23:11
у меня ничего не появляется на экране -- Ну, я конечно увидеть что-то (ошибка сегментации), и это связано с первым комментарием.
PaulMcKenzie 19.03.2022 23:11

Поскольку мы не видим код с push_back, проблема в том, что вы каким-то образом неправильно его используете. В push_back нет абсолютно ничего плохого. Несмотря на это, текущий код, который у вас есть, не является стартовым — вы не добавляете элементы в вектор с помощью [].

PaulMcKenzie 19.03.2022 23:12

Я добавил push_back в свой код

user18516112 19.03.2022 23:14

Ваш Matrix имеет два векторов, а не один. Где вызов для добавления элементов во «внутренний» вектор? Таким образом, это выглядит как проблема с вашей логикой — вы должны учитывать, что у вас есть «внешний» вектор и «внутренний» вектор, о которых нужно позаботиться.

PaulMcKenzie 19.03.2022 23:15

Я не знаю, как добавить элементы во «внутренний» вектор. Не могли бы вы помочь мне?

user18516112 19.03.2022 23:16

Пожалуйста, не меняйте исходный код. Добавьте новый код в качестве редактирования.

PaulMcKenzie 19.03.2022 23:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш код не скомпилируется, потому что у вас много ошибок в PascalTriangle.

Во-первых, вы инициализируете матрицу без элементов. Кроме того, вы используете матричные индексы, начинающиеся с 1, а не с 0.

Следующее печатает вещи для меня:

Matrix PascalTriangle(int n) {
  Matrix mat(n, std::vector<int>(n, 0)); // Construct Matrix Properly
  int a;
  for (int i = 0; i < n; i++) { // Start index at 0
    a = 1;
    for (int j = 0; j < i + 1; j++) { // Start index at 0
      if (j == 0) // Changed 1 to 0
        mat[i][j] = 1;
      else
        mat[i][j] = a;
      a = a * (i - j) / (j+1); // Changed j to j+1 since j starts at 0
    }
  }
  return mat;
}

большое спасибо, но это не выводит правильный вывод, как здесь onlinegdb.com/LdhxIlUtL

user18516112 19.03.2022 23:33

Извините, у меня была небольшая опечатка (я только что исправил). Вам нужно зациклить j < i+1 вместо j<i

QWERTYL 19.03.2022 23:39

Единственная проблема заключается в том, что вы создаете матрицу n x n, тогда как на самом деле размер может быть меньше, чем n x n для треугольника Паскаля. Решением будет добавление данных в строку только при необходимости.

PaulMcKenzie 19.03.2022 23:53

@PaulMcKenzie да, но ОП не находится в ситуации, когда ему нужно сохранять каждый байт памяти, который он может получить. В любом случае, сложность памяти одинакова.

QWERTYL 20.03.2022 00:00
Ответ принят как подходящий

Основная проблема заключается в том, что в PascalTriangle вы начинаете с пустым Matrix как в количестве строк, так и в столбцах.

Поскольку в моих комментариях упоминается push_back, вот способ его использования, если вы не инициализировали Matrix количеством переданных элементов.

Другая проблема заключается в том, что NumberOfColumns должен указывать строку, а не только вектор матрицы.

Последняя проблема заключается в том, что вы должны передавать Matrix по константной ссылке, а не по значению.

Решение всех этих проблем приводит к следующему:

Matrix PascalTriangle(int n) 
{
    Matrix mat;
    for (int i = 0; i < n; i++)
    {
        mat.push_back({}); // creates a new empty row
        std::vector<int>& newRow = mat.back(); // get reference to this row
        int a = 1;
        for (int j = 0; j < i + 1; j++) 
        { 
            if (j == 0) 
                newRow.push_back(1);
            else
                newRow.push_back(a);
            a = a * (i - j) / (j + 1); 
        }
    }
    return mat;
}

А затем в NumberOfColumns:

int NumberOfColumns(const Matrix& m, int row) 
{
    if (!m.empty())
        return m[row].size();
    return 0;
}

А потом NumberOfRows:

int NumberOfRows(const Matrix& m) { return m.size(); }

И последнее, PrintMatrix:

void PrintMatrix(const Matrix& m, int width) 
{
    for (int i = 0; i < NumberOfRows(m); i++) 
    {
        for (int j = 0; j < NumberOfColumns(m, i); j++)
            std::cout << std::setw(width) << m[i][j];
        std::cout << std::endl;
    }
}

Вот живая демонстрация

есть ли способ сделать это без получения ссылки на строку? Потому что мы еще не выучили ссылки

user18516112 19.03.2022 23:59

Я получил ссылку на последнюю строку, потому что ее легче обрабатывать с точки зрения ввода и простоты использования. Например, вы могли бы использовать mat.back().push_back(1);. И да, чтобы правильно получить последний элемент вектора, нужно использовать back(). Если вы действительно не хотите использовать back(), то mat[mat.size()-1].push_back(1) будет сделано. Но что кажется вам проще и менее подвержено ошибкам?

PaulMcKenzie 20.03.2022 00:00

не могли бы вы отредактировать свой код, чтобы он работал без ссылки?

user18516112 20.03.2022 00:02

На какую ссылку вы ссылаетесь? Я не буду редактировать ответ, если вы говорите о передаче Matrix по ссылке. Это большая часть ответа, который я опубликовал.

PaulMcKenzie 20.03.2022 00:03

Я говорю обо всех использованных ссылках

user18516112 20.03.2022 00:04

Я оставляю это вам, чтобы удалить ссылки. У меня есть привычка не публиковать плохой код C++. Ответы на StackOverflow должны отражать правильный стиль кодирования.

PaulMcKenzie 20.03.2022 00:05

будет ли это работать, если const Matrix &m изменится на Matrix m?

user18516112 20.03.2022 00:06

Да, это сработает, но каждый раз, когда вы проходите Matrix m, вы создаете временную копию всей этой матрицы. Вот почему его следует передавать по константной ссылке, чтобы не создавать временную копию. Я не знаю, исходите ли вы из Java, С# или подобного языка, но С++ по умолчанию передает нет по ссылке (как и в других языках). Важно знать разницу между прохождением Matrix m и прохождением Matrix& m.

PaulMcKenzie 20.03.2022 00:09

так что однозначно лучше пользоваться референсами, большое спасибо, я иду с С, так же как я выучил С, так и пришел в бездонный океан С++ :)

user18516112 20.03.2022 00:11

У меня проблема с попыткой не использовать ссылку для строки... Не могли бы вы помочь мне исправить эту ошибку onlinegdb.com/ob6_QZh80: conversion from ‘void’ to non-scalar type ‘std::vector’ requested

user18516112 20.03.2022 00:24

Избавьтесь от newRow вообще, если вы не хотите использовать ссылки, и, пожалуйста, обратитесь к моему предыдущему комментарию о mat.back(). И ваша попытка подтверждает мою предыдущую точку зрения - какой способ проще и менее подвержен ошибкам? Странно то, что получение ссылки - это точно того, что вы пытаетесь сделать в обычном режиме, поэтому я действительно не знаю, почему вы настаиваете на выполнении 2 + 2 + 2 + 2 вместо 2 x 4.

PaulMcKenzie 20.03.2022 00:34
Использование мат.назад()
PaulMcKenzie 20.03.2022 00:42

Другие вопросы по теме