
- •1. Информация о дисциплине
- •1.1. Предисловие
- •Содержание дисциплины и виды учебной работы
- •2. Рабочие учебные материалы
- •2.2. Тематический план дисциплины
- •2.3 Структурно-логическая схема дисциплины
- •2.4 Временной график изучения дисциплины
- •2.5. Практический блок
- •2.6. Рейтинговая система по дисциплине «Программирование и основы алгоритмизации»
- •3. Информационные ресурсы дисциплины
- •3.1. Библиографический список
- •3.2. Опорный конспект лекций по дисциплине
- •Раздел 1. ОБЩИЕ ПОЛОЖЕНИЯ
- •Раздел 2. ПРОГРАММИРОВАНИЕ ТИПОВЫХ АЛГОРИТМОВ
- •Раздел 3. МАССИВЫ
- •Раздел 4.ГРАФИКА
- •3.3. Лабораторные работы
- •3.4. Практические занятия
- •Заключение
- •4.Блок контроля освоения дисциплины
- •4.1. Методические указания к выполнению курсового проекта
- •4.2. Блок тестов текущего контроля
- •4.3. Вопросы к экзамену
- •Содержание
Раздел 3. МАССИВЫ
Изучаемые темы:
Тема 3.1. Числовые массивы Тема 3.2. Строковые массив
Тема 3.3. Методы сортировки и поиска в массиве Тема 3.4. Развитые структуры и алгоритм
Лабораторные работы Работа 5: Работа с числовыми массивами»
Тесты:
Тест 9. Обработка массивов Курсовой проект: методы поиска и сортировки Максимальное число баллов: 44
Тема 3.1. Числовые массивы
Впрактическом программировании очень часто приходится иметь дело
смассивами. Типичными операциями при работе с массивами являются:
•вывод массива;
•ввод массива;
•поиск максимального или минимального элемента массива;
•поиск заданного элемента массива;
•сортировка массива.
Для представления одномерных массивов на экране чаще всего используются компоненты Memo и ListBox (см. табл. 16, а также ниже в этом разделе), двумерные массивы отображаются компнентом StringGrid.
Компонент StringGrid
Этот компонент StringGrid используется как для отображения, так и для ввода элементов массива. Массивы могут быть как двумерными, так и одномерными. Значок компонента StringGrid находится на вкладке Additional палитры компонентов.
Компонент StringGrid представляет собой таблицу, ячейки которой содержат строки символов. В табл. 25 перечислены некоторые свойства компонента StringGrid.

|
Таблица 25. Свойства компонента StringGrid |
|
Свойство |
Назначение |
|
Name |
Имя компонента. Используется в программе для |
|
|
доступа к свойствам компонента |
|
ColCount |
Количество колонок таблицы |
|
RowCount |
Количество строк таблицы |
|
Cells |
Соответствующий таблице двумерный массив. |
|
|
Ячейка таблицы, находящаяся на пересечении |
|
|
столбца номер col и строки номер row, определяется |
|
|
элементом cells [col][row] |
|
FixedCols |
Количество зафиксированных слева колонок |
|
|
таблицы. Зафиксированные колонки выделяются |
|
|
цветом и при горизонтальной прокрутке таблицы |
|
|
остаются на месте |
|
FixedRows |
Количество зафиксированных сверху строк таблицы. |
|
|
Зафиксированные строки выделяются цветом и при |
|
|
вертикальной прокрутке таблицы остаются на месте |
|
Options . goEditing |
Признак допустимости редактирования содержимого |
|
|
ячеек таблицы. True — редактирование разрешено, |
|
|
False — запрещено |
|
Options . goTab |
Разрешает (True) или запрещает (False) |
|
|
использование клавиши <Таb> для перемещения |
|
|
курсора в следующую ячейку таблицы |
|
Options . GoAlways- |
Признак нахождения компонента в режиме |
|
ShowEditor |
редактирования. Если значение свойства False, то для |
|
|
того, чтобы в ячейке появился курсор, надо начать |
|
|
набирать текст, нажать клавишу <F2> или сделать |
|
|
щелчок мышью |
|
DefaultColWidth |
Ширина колонок таблицы |
|
DefaultRowHeight |
Высота строк таблицы |
|
GridLineWi-dth |
Ширина линий, ограничивающих ячейки таблицы |
|
Left |
Расстояние от левой границы поля таблицы до левой |
|
|
границы формы |
|
Top |
Расстояние от верхней границы поля таблицы до |
|
|
верхней границы формы |
|
Height |
Высота поля таблицы |
|
Width |
Ширина поля таблицы |
|
Font |
Шрифт, используемый для отображения |
|
|
содержимого ячеек таблицы |
|
ParentFont |
Признак наследования характеристик шрифта формы |
|

Обратите внимание на логическое свойство Options.goEditing. По умолчанию его значение равно false, следовательно, вся таблица не является доступной для редактирования. Иными словами, нельзя изменять значения её элементов. Чтобы позволить делать изменения значений с пульта, надо установить это свойство в true.
В качестве примера использования компонента StringGrid для ввода массива рассмотрим программу, которая вычисляет среднее арифметическое значение элементов массива. Для простоты предполагаем, что массив является одномерным и содержит 5 строк, то есть его длина не изменяется при выполнении программы. Над массивом производятся следующие простейшие операции:
•ввод значений:
•оперделение суммы элементов массива:
•оперделение среднего значения.
Диалоговое окно программы приведено на рис. 31. Компонент StingGrid1 используется для ввода массива, компонент Label1 — для вывода пояснительного текста, bRaschet и bExit (типа TBitButton) – для вычислений и выхода из программы.
Рис. 31. Диалоговое окно программы Ввод и обработка массива. Слева – ввод данных, справа – вывод результатов
Обратите внимание на заголовок окна сообщений, выводимого командой ShowMessage (рис. 31., справа): вместо стандартного безликого текста, там выводится наименование программы “Использование StringGrid”. Чтобы это сделать, надо в среде Builder выполнить команду
Project\Options\Application\Title.
Добавляется компонент StringGrid в форму точно так же, как и другие компоненты. После добавления компонента к форме нужно выполнить его настройку в соответствии с табл.26.
Таблица 26. Значения свойств компонента StringGrid1
Свойство |
Значение |
ColCount |
1 |
FixedCols |
0 |
FixedRows |
0 |
RowCount |
5 |
Options . goEditing |
True |
Options . AlwaysShowEditor |
True |
Options .goTabs |
True |
Обратите внимание на опцию “Options.goEditing”, значение которой установлено в true. В этом случае строки StringGrid станут доступными для редактирования, в том числе и для начального ввода данных. По умолчанию это значение устанавливается в false, а значит, клетки StringGrid недоступны для ввода данных.
Текст программы приведен на рис. 32.
#include <vcl.h> #pragma hdrstop #include "uStr.h"
#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::bExitClick(TObject *Sender) {Close();} //---------------------------------------------------------------------------
void __fastcall TForm1::bRaschetClick(TObject *Sender) {int i,A[5];
float summ,sred;//summ - сумма элементов массива; sred - их среднее значение //Пересылка значений элементов StringGrid в массив A
//for (i= 0;i<=4;i++)
if (StringGrid1->Cells[0][i]= =””) //Считаем, что если ячейка пустая, то
//соответствующий ей элемент массива равен нулю
A[i]= 0;
else A[i]= StrToInt(StringGrid1->Cells[0][i]);
// обработка массива summ = 0;
for (i =0;i<=4; i++) summ = summ + A[i];

//следующий оператор находится уже вне цикла sred=summ / 5.0;
// вывод результата
ShowMessage(“Сумма элементов: “
• |
+FloatToStr(summ) |
• |
+”\nСреднее арифметическое: “ |
• |
+ FloatToStrF(sred,ffFixed,7,2)); |
|
//символы «\n» являются управляющей escape-поледовательностью, |
|
//обеспечевающей переход на следующую строку |
}
Рис. 32. Листинг программы для ввода и обработки одномерного массива целых чисел
Подробно компонент StringGrid рассматривается в рамках лабораторной работы №5.
Компонент Memo
В некоторых случаях для ввода массива можно использовать компонент Memo. Компонент Memo позволяет вводить текст, состоящий из достаточно большого количества строк, поэтому его удобно использовать для ввода символьного массива. Компонент Memo добавляется в форму обычным образом. Значок компонента находится на вкладке Standard (табл. 27).
|
Таблица 27. Свойства компонента Memo |
Свойство |
Значение |
Name |
Имя компонента. Используется в программе для |
|
доступа к свойствам компонента |
Text |
Текст, находящийся в поле Memo. |
|
Рассматривается как единое целое |
Lines |
Текст, находящийся в поле Memo. |
|
Рассматривается как совокупность строк. Доступ |
|
к строке осуществляется по номеру |
Lines .Count |
Количество строк текста в поле Memo |
Left |
Расстояние от левой границы поля до левой |
|
границы формы |
Top |
Расстояние от верхней границы поля до верхней |
|
границы формы |
Height |
Высота поля |
Width |
Ширина поля |
Font |
Шрифт, используемый для отображения |
|
вводимого текста |
ParentFont |
Признак наследования свойств шрифта |
|
родительской формы |
При использовании компонента Memo для ввода массива значение каждого элемента массива следует вводить в отдельной строке и после ввода каждого элемента массива нажимать клавишу <Enter>. Получить доступ к находящейся в поле Memo строке текста можно при помощи свойства Lines, указав в квадратных скобках номер нужной строки (строки нумеруются с нуля так же, как и элементы массива ).
Следующая программа, текст которой приведен в листинге 4 , демонстрирует использование компонента Memo для ввода символьного массива.
Основной цикл процедуры ввода символьного массива из компонента Memo может выглядеть так:
{ AnsiString A[100]; for (i=0; i<=Kol-1;i++)
A [ i ]= StrToInt(Memo1->Lines->Strings[i]);
Листинг 4. Программа ввода символьного массива
где:
Kol — именованная константа, определяющая количество элементов массива (не более 100 в данном прмере) ;
A — массив из 100 строк символов; Memo1 — имя Memo-компонента;
Lines — свойство компонента Memo, представляющее собой список строк, каждый элемент которого содержит одну строку находящегося в визуальном поле Memo.
Stringsотдельная строка множества Lines, к которой можно обращаться по индексу.
Компонент ListBox
Этот компонент очень широко используется в визуальном программировании. В целом он весьма близок к MEMO, основной отличие состоит в том, что окно компонента предназначено только для вывода строк, ввод не допускается. Изучению многострочных компонентов посвящена лабораторная работа №5.
Вопросы для самопроверки
1.Основное свойство компонентов Memo и ListBox – это набор строк типа TStringList. Охарактеризуйте его: почему в его названии используется слово List (список), а не Array (массив)? Как обращаться к элементам этой совокупности? Каков тип этих элементов ?
2.Что общего и чем различаются компоненты Memo и ListBox?
3.Что общего и чем различаются родственные компоненты Memo и ListBox от StringGrid?
4.Какова структура хранения, используемая в компоненте StringGrid? Каков тип данных, хранимых в StringGrid?
5.Каким образом дополнительный глобальный массив чисел помогает сократить затраты труда на программирование обработки числовых массивов, записанных в Memo, ListBox или StringGrid? Почему этот массив должен быть обязательно глобальным?
Тема 3.2. Строковые массивы
Элементами массивов могут быть не только числа, но и строки. Тогда объявление такого массива может выглядеть так:
AnsiString Mas1[10], Mas2[20][15];
С точки зрения общей организации программ обработка строковых массивов не приводит к каким-либо особым случаям: в основном, это циклы с известным количеством повторений. Каждый элемент массива (строка символов) обрабатывается с помощью строковых функций, рассмотренных выше (см. «Встроенные функции обработки строк»).
Наиболее часто строковые массивы используются для отображения элементарных списков - наименований объектов, фамилий студентов, закупленных товаров и т.п. Списки надо вводить, сохранять в памяти и осуществлять в них поиск элементов по заданным критериям. Несмотря на близкие аналогии с обработкой числовых массивов, для строковых массивов используют некие особые приемы. Подробно эти способы программирования обсуждаются в курсе «Прикладное программирование», который изучается позднее. Здесь только отметим эти особенности:
•на экране строковые массивы удобно представлять компонентами ListBox, Memo и StringList (см. 3.1);
•для обработки строковых массивов предназначены структуры типа TStringList, представляющие собой массив строк переменной длины. Подробно эта структура рассматривается позднее в курсе «Прикладное программирование»;
•для сохранения строковых массивов во внешней памяти используются файлы или базы данных. Объект типа TStringList снабжен методами, специально предназначенными для обмена данными с файлом;
•для ввода символьных строк в массивы в программе обязательно следует предусматривать методы контроля правильности и защиты от несанкционированных действий.
Вкачестве примера обработки строковых массивов рассмотрим типичную задачу поиска заданной фамилии в списке студентов. Итак, дан массив Fam строк из 10 элементов, предположим для простоты, что все элементы в массив уже введены, причём все фамилии различны. Для

организации поиска надо предусмотреть окно ввода. Возможный интерфейс представлен на рис. 34.
Рис. 34. Интерфейс программы «Поиск в строковом массиве»
На рисунке указаны программные имена компонентов, участвующих в программировании (рис. 37).
Представление об алгоритме программы дают следующие два рисунка. Если для поиска указан студент, который действительно присутствует в списке, то программа выведет такое сообщение (рис. 35).
Рис. 35. Поиск увенчался успехом

Если студент не найден, то сообщение может быть таким (рис. 36):
Рис. 36. Результат неудачного поиска
Значит, алгоритм может быть следующим:
•установить начальные значения элементов массива;
•вести запрос на поиск (фамилию для поиска);
•построить цикл, обеспечивающий последовательный просмотр всех элементов массива. Поскольку количество элементов (строк) фиксировано и равно 10, то цикл должен повторяться 10 раз;
•в каждом цикле сравнивать значение запроса со значением текущей строки на предмет равенства;
•если строки равны, то прервать цикл, вывести на экран сообщение об удачном завершении поиска (рис. 35) и закончить программу;
•если равенства строк ни разу не наступило, а весь массив просмотрен до конца, то вывести на экран сообщение о неудачном завершении поиска (рис. 36) и закончить программу.
На рис. 37 представлен полный листинг программы непосредственного поиска . Обратите внимание, что в подобных задачах обрабатываемый массив как правило объявляется как глобальная переменная, поскольку к этому массиву должны иметь доступ различные блоки программы.
#include <vcl.h> #pragma hdrstop
#include "uPoisk.h" //---------------------------------------------------------------------------
#pragma package(smart_init) #pragma resource "*.dfm" TfrmPoisk *frmPoisk;
//Элементам глобального массива Fam присваиваются начальные //значения
AnsiString Fam[10]={ "Иванов","Иванова","Петров","Петровский","Сидоров", "Андреев","Антонова","Баранов","Брянцев","Васильев"};
//---------------------------------------------------------------------------
__fastcall TfrmPoisk::TfrmPoisk(TComponent* Owner): TForm(Owner) {// это «конструктор формы». Builder создал его автоматически
}
//---------------------------------------------------------------------------
void __fastcall TfrmPoisk::bExitClick(TObject *Sender)
{
Close();// завершение программы по кнопке «Выход» //Её программное имя : bExit
}
//---------------------------------------------------------------------------
//алгоритм поиска. Программное имя кнопки «Поиск» : bPoisk void __fastcall TfrmPoisk::bPoiskClick(TObject *Sender)
{int i; AnsiString sPoisk; sPoisk=Edit1->Text; //запрос на поиск. for (i=0;i<=9;i++)
{if (sPoisk==Fam[i])
goto M1;//безусловный выход из цикла при выполнении условия поиска }//Конец тела цикла
ShowMessage("Студент <"+sPoisk+"> в списке отсутствует"); return;//безусловный выход из блока
M1:ShowMessage("Студент <"+sPoisk+"> найден в списке под номером " +IntToStr(i+1));
}
//---------------------------------------------------------------------------
Рис. 37. Листинг программы непосредственного поиска
Более детально работа со строковыми массивами изучается позднее в курсе «Прикладное программирование»
Вопросы для самопроверки
1.В чем состоит существо операции «сложение» строк?
2.Каков смысл операций отношения символьных строк?
3.Имеет ли смысл запись
{AnsiString a,b; if (a>b),
если a=”Петров”, а b=”Иванов”?
…
}
4.Можно ли определить факт, что одна строка является подмножеством другой? Если да, то как ?
5.Как определить, что введенный с пульта символ относится к русским (английским) буквам?
6.На каком месте в списке русских фамилий окажется запись Ёлкин после сортировки по алфавиту ?
7.На каком месте в списке русских фамилий окажется запись Сидоров после сортировки по алфавиту, если первая буква этой фамилии напечатана на английском регистре?
8.Почему функции UpperCase и LowerCase не применимы к неанглийскому алфавиту ?
Тема 3.3. Методы сортировки и поиска в массиве
Под сортировкой массива подразумевается процесс перестановки элементов массива, целью которого является размещение элементов массива в определенном порядке. Например, если имеется массив целых чисел а, то после выполнения сортировки по возрастанию должно выполняться условие:
а[0] < а[1] < а[2] < .. .< a[N-1]
где N — число элементов в массиве.
Задача сортировки распространена в информационных системах и используется как предварительный этап задачи поиска, так как поиск в упорядоченном (отсортированном) массиве проводится намного быстрее, чем в неупорядоченном (см. метод бинарного поиска, рассматриваемый ниже, в 3.4).
Существует множество методов (алгоритмов) сортировки массивов.
1.метод всплывающего пузырька выбора.
2.метод локального минимума.
3.метод обмена.
4.обменная сортировка со слиянием (параллельная сортировка Бэтчера).
5.обменная сортировка с разделением (быстрая сортировка Хоара).
6.поразрядная обменная сортировка и т.п.
Все методы приводят к одинаковому результату, но с различными
показателями качества. Основным показателям качества алгоритма сортировки является его скорость; потребляемая процессом память в
настоящее время не является дефицитным ресурсом. Скорость алгоритма зависит от числа операций сравнения и перестановок элементов массива, причем более существенны именно перестановки, поскольку они выполняются в оперативной памяти, тогда как сравнения производятся в процессоре, что на порядок быстрее.
Методы 1 и 2 рассматриваются в рамках практических занятий (см. 3.4.1 и 3.4.2), с остальными методами студент ознакамливается самостоятельно в рамках работы над курсовым проектом.
Задача поиска формулируется в общем виде так: дана переменная, значение которой рассматривается как запрос на поиск. Определить, принадлежит ли этот запрос множеству значений, составляющих массив данных.
Как и сортировка, поиск может быть организован множеством различных способов, отметим некоторые из них:
1.прямой перебор в неупорядоченном массиве
2.прямой перебор в упорядоченном массиве
3.бинарный поиск
4.поиск по двоичному дереву
Первый вариант поиска рассматривался выше (см. 3.1). Варианты 2 и 3 будут рассмотрены в рамках практических занятий (см. 3.4.3, 3.4.4 и 3.4.5), с остальными методами студент ознакамливается самостоятельно в рамках работы над курсовым проектом.
Вопросы для самопроверки
1.Почему задача сортировки столь часто используется в программировании?
2.На чем основываются методы быстрого поиска?
3.Как ускорить сортировку данных в файле, находящемся в медленном внешнем запоминающем устройстве?
4.Почему задача поиска считается одной из самых распространенных как в прикладном, так и в системном программировании?
5.Какой массив быстрее будет отсортирован – числовой или строковый?
6.Быстрый поиск возможен только в отсортированных массивах, однако задача сортировки сама по себе очень медленная по сравнению с поиском. Нет ли тут противоречия, состоящего в том, что какой бы быстрой ни была сортировка, выигрыша не будет получено из-за медленной сортировки?

Тема 3.4. Развитые структуры и алгоритмы
Списки и деревья
Как уже отмечалось, выбор хорошей структуры данных является залогом успешного программирования, поэтому программист должен иметь представление о более развитых структурах данных, чем простые переменные или массивы. В прикладном программировании реже, а в системном очень часто используются такие структуры хранения данных, как
списки и деревья.
Главными особенностями этих структур являются:
•способ доступа к элементам структуры
•способ их хранения в памяти
Как списки, так и деревья представляют собой совокупности элементов, но в отличие от массивов они предлагают как иной способ доступа, так и другие оригинальные операции над элементами.
Списки
Списком называется структура, в которой связи между элементами устанавливаются непосредственно в самом элементе. На рис. 38 представлена логическая структура однонаправленного списка
Рис. 38. Структура однонаправленного списка
Главная особенность списка как структуры хранения состоит в том, что ячейки памяти выделяются не одним сплошным экстентом, как для массива, а произвольным образом. Супервизор памяти (программа операционной системы) динамически выделяет под каждый элемент первую попавшуюся свободную ячейку. Чтобы список «знал», где располагается следующий элемент, необходимо в теле элемента предусмотреть ссылку на связанный с ним следующий элемент. На рисунке видно, что элементы списка «разбросаны» по запоминающему пространству.
Такая организация позволяет наилучшим образом использовать память машины, поскольку можно помещать элементы в любые незанятые области памяти. Позднее вы узнаете, что именно по такому принципу построена

таблица размещения файлов (FAT) практически в любой современной операционной системе.
Другим достоинством списковых структур является легкость выполнения таких операций, как «включение элемента в список» или «удаление элемента из списка». Действительно, предположим, необходимо удалить из списка (рис. 38) элемент 3. Для этого достаточно просто переделать ссылку элемента 2, указав в качестве следующего адреса не «адрес 3», а «адрес 4». Как видно, операции по изменению ссылок не приводят к перемещению элементов по адресному пространству, а следовательно, выполняются очень быстро. Методы сортировки, основанные на списочных структурах, работают значительно быстрее, чем основанные на массивах, поскольку они исключают физическое перемещение элементов по ячейкам памяти.
Структура хранения типа «дерево» в общих чертах напоминает список, с той лишь разницей, что в каждом элементе вместо одной, существуют две адресных ссылки, а в целом у структуры не один, а много конечных элементов, называемых «листьями».
Рис. 39. Структура бинарного «дерева»
На таких структурах превосходно работают методы быстрой сортировки и поиска. Однако программирование этих методов довольно сложное и требует знания работы с указателями (pointer), что выходит за рамки курса «Программирование и основы алгоритмизации» и будет рассматриваться позднее.