Умный дом

Как использовать массивы и векторы

Ниже приведены первые восемь элементов из шести число­вых последовательностей:

Fibonacci: 1, 1, 2, 3, 5, 8, 13, 21 Lucas: 1# 3, 4, 7, 11, 18, 29, 47 Pell: 1, 2, 5, 12, 29, 70, 169, 408 Triangular: 1, 3, 6, 10, 15, 21, 28, 36 Square: 1, 4, 9, 16, 25, 36, 49, 64 Pentagonal: 1, 5, 12, 22, 35, 51, 70, 92

Наша программа должна выводить на дисплей пары эле­ментов из последовательности и позволить пользователю угадать следующий элемент. Если пользователь угадывает и желает продолжить, программа должна вывести на дисплей следующую пару элементов, затем третью, и так далее. Как мы можем это сделать?

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

Теперь будем выводить на дисплей максимум шесть пар элементов за сессию: по одной паре из каждой из шести пос­ледовательностей. Мы постараемся сделать это так, чтобы при выводе на дисплей пары элементов не знать, из какой числовой последовательности будет взята пара при следую­щем проходе цикла. Каждый проход должен иметь доступ к трем значениям: паре элементов и элементу, следующему за ней в последовательности.

Решение, которое мы обсудим в этом разделе, использует контейнерный тип, способный поддержать смежную после­довательность целых значений, которые могут быть доступ­ны не по имени, а по позиции в контейнере. Мы запомнили 18 значений в контейнере как подборку шести групп: первые два в группе представляют пару для вывода на дисплей, тре­тий - следующий элемент в последовательности. При каждом проходе цикла мы добавляем три индексных значения, про­ходя по шести группам по очереди.

В С++ мы можем определить контейнер либо как встроен­ный массив, либо как вектор класса стандартной библиоте­ки. В основном, я рекомендую использовать класс векторов, а не встроенные массивы. Однако есть резон использовать массив, и важно понять, как использовать оба варианта.

Для определения встроенного массива мы должны обо­значить тип элементов массива, дать ему имя и обозначить размер - количество элементов, которые массив должен со­держать. Размер должен быть константой, то есть выражени­ем, которое не меняется во время выполнения программы. Например, следующий код объявляет pell_jseq массивом из 18 целых элементов.

Const int seq_size = 18; int pell_seq[seq_jsize] ;

Для определения объектов класса векторов мы должны вначале включить файл заголовка vector. Класс векторов - шаблон, поэтому мы определяем тип элементов в угловых скобках, следующих за именем класса. Размер помещается в круглых скобках, он не обязательно должен быть постоян­ным выражением. Следующий код определяет pell_seq как объект класса векторов, содержащий 18 элементов типа int. По определению каждый элемент инициализируется в «О».

#include <vector>

Vector<int> pell_seq(seq_size);

Мы добираемся до элементов: массива или вектора, опреде­ляя его позицию в контейнере. Этот элемент индексируется с использованием оператора списка индексов ([ ]). Одна потен­циальная «незадача» в том, что первый элемент находится в позиции «О», а не «1». Последний элемент индексируется на 1 меньше, чем размер контейнера. Для pell_seq правильные индексы - от 0 до 17, а не от 1 до 18. (Эта ошибка настолько распространена, что заслуживает иметь собственное имя: пе­чально известная off-by-one-ошибка). Например, для получе­ния первых двух элементов последовательности Pell мы пишем:

Pell_seq[0] = 1; // присваиваем 1 первому элементу pell_seq[l] =2; // присваиваем 2 второму элементу

Вычислим следующие десять элементов последовательнос­ти Pell. Для прохождения через элементы вектора или масси­ва мы обычно используем цикл for - другой базовый цикл С++. Например,

For (int ix = 2; ix < seq_size; ++ix)

Pell_seq[ix] = pell_seq[ix - 2] + 2*pell_seq[ix - 1] ;

Цикл for состоит из следующих элементов:

For (начальное значение; условие; индексация) выражение;

Начальное значение выполняется единожды перед вы­полнением цикла. В нашем примере ix инициализируется как «2» перед началом выполнения цикла.

Условие служит для контроля над циклом. Оно вычисляет­ся перед каждой итерацией цикла. Так что, сколько итераций при вычисленном условии равном true, столько раз выраже­ние выполняется. Выражение может быть единственным или блочным. Если первое условие не удовлетворяется, выраже­ние не выполнится никогда. В нашем примере условие прове­ряет, меньше ли ix, чем seq_size?

Индексация вычисляется после каждой итерации цикла. Она обычно используется для модификации начального зна­чения объекта и проверяется в условии. Если первое вычис­ление условия принимает значение false, индексация не выполнится никогда. В нашем случае ix увеличивается с каж­дой итерацией цикла.

Для вывода элементов мы проходим через следующие операции:

Cout « "The first " « seq_size« " elements of the Pell Series:nt";

For (int ix = 0; ix < seq_size; ++ix)cout « pell_seq[ix] « " "; cout « "n";

При желании мы можем обойтись без начального значения, индексации или (реже) условия для цикла for. Например, мы можем переписать предыдущий цикл как:

Int ix = 0; // ...

For (; ix < seq_size; ++ix)// ...

Точка с запятой необходима, чтобы показать пустое на­чальное значение.

Наш контейнер содержит второй, третий и четвертый элементы каждой из шести последовательностей. Как мы за­полним контейнер подходящими значениями? Встроенный массив может специфицироваться инициализационным списком, содержащим список значений, разделенных запя­тыми для всех элементов или подмножества элементов:

Int elem_seq[seq_size] = {

1, 2, 3, // Fibonacci

3, 4, 7, // Lucas

2, 5, 12, // Pell

3, 6, 10, //Triangular

4, 9, 16, // Square

5, 12, 22 // Pentagonal };

Количество значений, записанных в список инициализа­ции, не должно превышать размера массива. Если мы предла­гаем меньше значений, чем размер массива, недостающие эле­менты инициализируются как «О». При жедании мы можем позволить компилятору вычислить размер массива на основа­нии количества значений, которые включаем в список:

// компилятор рассчитает размер в 18 элементов

Int elem_seq[] = {1, 2, З, 3, 4, 7, 2, 5, 12,3, 6, 10,

4, 9, 16, 5, 12, 22};

Класс векторов не поддерживает список инициализации. Несколько нудным решением будет присвоение значения каждому элементу отдельно:

Vector<int> elem_seq(seq_size); elem_seq[0] = 1; elem_seq[l] =2; // ...

Elem_seq[17] =22;

Еще одна альтернатива - инициализировать встроенный массив и использовать его для инициализации вектора:

Int elem_vals[seq_size] = {1, 2, З, 3, 4, 1, 2, 5, 12,3,

6, 10, 4, 9, 16, 5, 12, 22 };

// инициализация elem_seq значениями elem_vals vector<int> elem_seq(elem_vals, elem_vals+seq_size);

Elem__seq получает два значения. Эти значения в действи­тельности адресованные - они отмечают диапазон элемен­тов, с которым вектор будет инициализирован. В этом случае мы отметили 18 элементов, содержащихся в elem_vals и ко­пируемых в elem_seq.

Д теперь посмотрим, как мы можем использовать elem__seq. Одно различие между встроенными массивами и классом векторов состоит в том, что вектор знает свой раз­мер. Наш предыдущий цикл for проходил через встроен­ный массив. Посмотрим, велика ли разница при использо­вании вектора:

// elem_seq. size() возвращает число элементов // содержащихся в векторе elem_seq

Cout « "The first " « elem_seq. size()« " elements of the Pell Series:nt";

For (int ix = 0; ix < elem_seq. size(); ++ix) cout « pell_seq[ix] « " ";

Cur_tuple представляет собой индекс в текущей после­довательности, выводимой на дисплей. Мы инициализиру­ем его в «0». С каждым проходом цикла мы добавляем «3» в cur_tuple, устанавливая его для индексации первого элемента следующей последовательности для вывода на дисплей:

Int cur_tuple = 0;

While (next_seq == true &&cur_tuple < seq_size) { cout « "The first two elements of the sequence are: " « elem_seq[cur_tuple] « ", " « elem_seq[cur_tuple + 1] « "nWhat is the next element? "; // ...

If (usr_guess == elem_seq[cur_tuple + 2]) // правильно!

// ...

If (usr_rsp == "N" II usr_rsp == "n")next_seq = false; else cur_tuple += 3;

Полезно было бы сохранять путь к последовательности, которая в настоящий момент активна. Запомним имя каждой последовательности как строку:

Const int max_seq = 6;

String seq_names[max_seq] = {"Fibonacci","Lucas","Pell", "Triangular","Square","Pentagonal"};

Мы можем использовать seq_names следующим образом:

If (usr_guess == elem_seq[cur_tuple + 2]) { ++num_cor;

Cout « "Very good. Yes, " « elem_seq[cur__tuple + 2] « " is the next element in the " « seq_names [cur_tuple / 3] « "sequence.n";

}

Выражение cur_tuple/3 получает по очереди 0, 1, 2, 3, 4 и 5, индексируя в массиве строк элементы, которые иденти­фицируют активную последовательность.

Умный дом

Вторая версия основной программы на языке С++

/****************^ * TOC o "1-3" h z Copyright (С) 2006 by Vladimir Gololobov * * vgololobov@yandex. ru * * * * This program is free software; you can redistribute it …

Циклы

Циклы выполняют выражения или блоки выражений до тех пор, пока выражение условия не становится истинным. Наша программа требует двух циклов (один вложен в дру­гой). Пока пользователь желает угадывать последовательно­сти: { …

Две полезные схемы

Первая схема относится к настенному выключателю, работа­ющему по протоколу XI0. Что полезного можно почерпнуть из этой схемы? Например, организацию сканирования сети и управления триаком. Схему я привожу, как она сохранилась …

Как с нами связаться:

Украина:
г.Александрия
тел./факс +38 05235  77193 Бухгалтерия
+38 050 512 11 94 — гл. инженер-менеджер (продажи всего оборудования)

+38 050 457 13 30 — Рашид - продажи новинок
e-mail: msd@inbox.ru
msd@msd.com.ua
Схема проезда к производственному офису:
Схема проезда к МСД

Оперативная связь

Укажите свой телефон или адрес эл. почты — наш менеджер перезвонит Вам в удобное для Вас время.