Я пытаюсь сделать треугольник Паскаля в C ++. Но я не мог этого сделать! Что не так с моим кодом?
#include <iostream>
using namespace std;
int main()
{
int rows = 5;
int currentNumber = 1;
int numbers;
int tempNumber;
bool odd;
for(int i = 0; i < rows; i++)
{
numbers = i+1;
if(i%2 != 0) {
odd = true;
} else {
odd = false;
}
for(int j = 0; j < (rows/2)-(numbers/2); j++)
{
cout << " ";
}
if(odd)
{
cout << " ";
}
currentNumber = 1;
tempNumber = 0;
for(int k = 0; k < numbers; k++)
{
cout << currentNumber << " ";
if(k > numbers/2) {
currentNumber-=tempNumber;
tempNumber-=currentNumber;
} else {
currentNumber+=tempNumber;
tempNumber+=currentNumber;
}
}
cout << endl;
}
cout << "test";
}
И вывод ниже:
1
1 1
1 1 2
1 1 2 5
1 1 2 5 -3
test
Первое, что я хотел бы сделать, это не беспокоиться о фактическом расположении чисел, когда они напечатаны. Это схожая концепция во всем программировании, вы хотите отделить заботу о том, как вещи отображаются, «представление» от того, как вещи находятся в данных, «модель». Теперь, когда у вас есть концептуальная основа для структурирования кода, я бы также использовал структуры и объекты классов, поскольку вы говорите, что C ++ — это то, что вы пытаетесь практиковать, которое в основном сосредоточено вокруг парадигмы объектно-ориентированного программирования (ООП). С этими идеями мы можем начать искать способ, как мы хотим создать треугольник.
Мы хотим добиться процедурного производства следующей структуры:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
чтобы добиться этого эффекта, мы действительно хотим создать:
1
1,1
1,2,1
1,3,3,1
1,4,6,4,1
Если вы заметите из вышеприведенных диаграмм, мы можем сделать вывод, что начиная с аксиомы (самой первой итерации / чего-то, что должно быть до того, как мы начнем), которая в этом случае представляет собой просто строку, содержащую только число 1
, мы можем видеть, что каждая продукция (любая данная итерация, которая имеет какое-то правило для ее производства, начиная сначала с аксиомы, 1
) задается добавлением двух значений в строке над ним, имеющих одинаковый индекс, и следующего индекса. Для алгоритма мы будем предполагать, что если производственный процесс не может найти число, мы скажем, что число существует, но не показано, и мы предположим, что это 0. (Если это все с левой стороны, нет первого значения, а если все с правой стороны, второго значения нет)
Так что это означает, что если вы посмотрите на мою вторую диаграмму, у нас есть первая строка, которая просто 1
но мы будем делать вид, что это действительно 0,1,0
, Это дает нам более похожую на пирамиду:
0,1,0
0,1,1,0
0,1,2,1,0
0,1,3,3,1,0
0,1,4,6,4,1,0
Наиболее важной частью является аксиома 1
который мы будем считать 0,1,0
, Теперь давайте выясним код для нашей «продукции», то есть метода для создания строки с учетом строки перед ней. Мы хотим создать функцию, которая будет брать список чисел из предыдущей строки и создавать следующую строку, предполагая, что она дополняется нашей 0
с обеих сторон. Эта функция может выглядеть примерно так:
std::vector<int> produceNextRow(std::vector<int> previousRow) {
std::vector<int> nextRow;
int left, right = 0;
/* For each of the numbers in the previous row, plus one more
because each next row has one more value than the last */
for( int i = 0; i < previousRow.size()+1 ; i++ ) {
// If we're all the way on the left we need 'left' to be our imaginary 0
if( i == 0 ) {
left = 0;
} else {
/* Otherwise we want it to be the value in the same position of the
previous row which is slightly to the left, hence -1 */
left = previousRow[i-1];
}
// If we're all the way on the right, we need 'right' to be our imaginary 0
if( i == previousRow.size() ) {
right = 0;
} else {
/* Otherwise we want it to be the value of the previous row, at the same
position */
right = previousRow[i];
}
/* Finally we add left and right, to get our new number, then we put it into
the next row */
nextRow.push_back(left+right);
}
// Let's return our new row we created
return nextRow;
}
На самом деле это все, что нам нужно. Теперь вам просто нужно использовать трюк, чтобы поместить пробелы между ними и распечатать их. Я не буду этого делать здесь, но я покажу вам, как использовать эту функцию для создания нескольких строк треугольника:
int main(int argc, char *argv[]) {
// Vector of vectors of ints! This is our entire triangle
std::vector<std::vector<int>> triangle;
std::vector<int> axiom {1};
// Lets put our axiom into the triangle first
triangle.push_back(axiom);
// Alright, for the sake of example lets do some number of productions like 6
int productions = 6;
for( int i=0; i < productions ; i++ ) {
triangle.push_back(produceNextRow(triangle[i]));
}
/* Now lets print out our triangle, you'd replace this with something fancy
that maybe computs how many spaces are required, and makes the triangle look
better. I'll leave that as an excersize for you */
// For each row in the triangle
for( int i=0; i < triangle.size() ; i++ ) {
// For each number in the row
for( int j=0; j < triangle[i].size() ; j++ ) {
// print that number followed by a comma and a space
std::cout << triangle[i][j] << ", ";
}
// print a new line after each row
std::cout << std::endl;
}
return 0;
}
Я оставил помещать это в объект класса, а также красиво печатать его, как настоящий паскальский треугольник, в качестве упражнений для вас, я думаю, вы должны попробовать это и потратить время на то, чтобы действительно подумать о том, что происходит в produceNextRow
метод.
Если вы представляете свой треугольник как выровненный по левому краю (https://en.wikipedia.org/wiki/Pascal%27s_triangle#Overall_patterns_and_properties) тогда он может быть представлен как 2d массив:
#include <iomanip> //setw
....
static int const size = 20;
int const width = 6;
int cell[size][size+1];
for (int i = 0; i < size; ++i)
{
cell[i][0] = 1;
cell[i][i + 1] = 0;
std::cout << std::string((size - i) * width / 2, 0x20) << cell[i][0];
for (int j = 1; j <= i; ++j)
{
cell[i][j] = cell[i - 1][j - 1] + cell[i - 1][j];
std::cout << std::setw(width) << cell[i][j];
}
std::cout << std::endl;
}
Печать: