Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Отладка программных решений. Учебно-методическое пособие для студентов направлений подготовки бакалавриата 09.03.03 «Прикладная информатика», 09.03.04
.pdf
так как для определения адреса конкретного элемента нужно
посчитать насколько он удален от первого элемента, то
нумерация (индексация) элементов начинается с 0;
так как массив в памяти должен быть расположен единым
«куском», то при создании массива необходимо указать, сколько
элементов в нем будет хранится, чтобы найти в памяти
место, куда он поместится полностью;
так как массив в памяти должен быть расположен единым
«куском» и, если возникает потребность увеличить количество
элементов в массиве, то приходится создавать новый массив,
большей длины и переносить туда все элементы из исходного
массива;
Важно. Коллекция и массив – это немного разные вещи. С
стороны, и то и другое используется для хранения набора данных.
С другой стороны, коллекция – это динамический массив с большой
надстройкой над ним. В частности, во внутренний механизм работы
такое
одной
коллекции встроена возможность создания нового массива, большей
длины (динамическое расширение), при добавлении нового элемента в
коллекцию. При этом этот механизм именно
коллекции и вызывается только по необходимости самой коллекцией
(если в уже имеющийся массив коллекции нельзя добавить новый
элемент). Если же работа выполняется с обычным массивом, то
необходимо самостоятельно прописывать в коде вызовы отдельных
методов, в случае необходимости расширения массива.
Чтобы лучше понимать, как работать с массивом
его, например, как цепочку соединенных между собой платформ для
перевозки грузов (ж/д платформа или автомобильная). На каждую платформу
что скрыт внутри работы
можно представлять
11

можно поместить контейнер, при этом все контейнеры имею одинаковый
размер, но разное содержимое или, например, разный вес (если будем
рассматривать простой целочисленный массив).
Рассмотрим на примере. Сразу оговоримся, что для примера будем
рассматривать массив целочисленных значений.
Изначально будет, например, 5 пустых платформ (рисунок 1.1), что
будет идентично созданию массиву на 5 элементов (листинг
Рисунок 1.1 – 5 пустых платформ
int[]mas=newint[5];
Листинг 1.1 – Создание массива на 5 элементов
Далее на первую платформу помещаем груз, весом 10 единиц (рисунок
1.2).
10
Рисунок 1.2 – Добавление груза на первую платформу
1.1).
Это будет идентично присвоению в первую ячейку массива
константного значения 10 (листинг 1.2).
mas[0]=10;
Листинг 1.2 – В первую ячейку массива поместили значение 10
Далее поместим на остальные платформы поместим грузы, а также
пронумеруем сами платформы (рисунок 1.3).
10
7 1
10 2
Рисунок 1.3 – Платформы с грузами
12
4 10
3
4

Важно! Не путать порядковый номер (индекс массива) со значением,
которое там лежит. Например, задача: найти и вывести минимальное
значение в массиве. Часто можно встретить такой код (листинг 1.3).
intmin=mas[0];
for(inti=0;i<mas.Length;i++)
{
if(mas[i]<mas[min])
{
min=mas[i];
}
}
Console.WriteLine("Min={0}",min);
Листинг 1.3 – Поиск минимального элемента в массиве
И в данном коде есть логическая ошибка, когда в операторе if идет
обращение к элементу массива по порядковому номеру, но в качестве номера
подставляется значение из самого массива, что в корне неверно. Если
обратимся к примеру с платформами, получается, что на первой же итерации
значение в min будет равно 10 и будет попытка обратиться
к элементу
массива с порядковым номером 10, которого нет в массиве. В лучшем случае,
если среда разработки отслеживает такие действия, произойдет выброс
исключения, в худшем произойдет обращение к области памяти вне массива.
И хорошо, если это будет операция чтения, просто считается произвольный
набор байт. А вот, если будет запись (например, mas[min] = 15), то
запросто
могут быть повреждены значения, хранящиеся в других переменных и далее
это может серьезно повлиять на корректность работы программы.
Перейдем к методам обработки массивов. Первое, что рассмотрим –
поиск. Задача поиска/выборки из набора данных – одна из самых
распространенных. Задача поиска, как правило, выполняется над всем
набором данных, подразумевая использование операторов
цикла (for или
foreach) для прохода по набору данных. В процессе прохода для каждого
элемента из набора данных выполняется проверка, удовлетворяет ли этот
элемент условию отбора или нет. Если элемент удовлетворяет условию, то
13

далее, в зависимости от требований, он или куда-то передается/выводится,
или помещается в отдельный набор данных.
В качестве результата работы задачи поиска может быть порядковый
номер элемента, удовлетворяющего условию или его значение (если
результатом должно выступать единичное значение) или набор элементов,
удовлетворяющих условию (обычно, такой набор передается далее для
дальнейшей обработки).
В случае, если задача поиска подразумевает в качестве результата
только одно значение (например, максимальное значение в массиве), важно
учитывать, что в зависимости от того, как будет выставлено условие в
условном операторе, строгое (например, >) или нестрогое (например, >=) и,
если в массиве будет несколько элементов, удовлетворяющих условию, то
будет выбран
условие нестрогое (при стандартной реализации задачи поиска с проходом по
массиву с начала в конец).
Еще одна задача, которая часто встречается – это задача перестановки
элементов в массиве. Как правило, это перестановка связана с
упорядочиванием элементов по определенным критериям (сортировкой).
или первый из них, если условие строгое или последний, если
Возвращайся к
имеется кран-манипулятор, с помощью которого можно поднять один груз и
переместить его в другое место. Однако тут возникает проблема, что на всех
имеющихся платформах уже также стоят грузы и перемещаемый груз на них
поставить уже нельзя. Выходом будет создание отдельной платформы,
несвязанной
связанной с массивом). Получается, груз с одной из платформ перемещается
на эту независимую платформу (запоминаем значения из ячейки массива в
отдельной переменной), далее на освободившееся место перемещается груз с
другой платформы (в ячейку массива запоминается значение из другой
ячейки), далее на новое
независимой платформы (в другую ячейку помещается значение из
нашим платформам, представим, что помимо самих платформ
с другими (в коде – это объявление отдельной переменной, не
освободившееся место перемещается груз с
14

отдельной переменной). В коде это будет выглядеть следующим образом
(листинг 1.4).
inttemp=mas[3];
mas[3]=mas[1];
mas[1]=temp;
Листинг 1.4 – Перестановка четвертого и второго элементов в массиве
Если в рамках решения задачи необходимо поменять серию элементов
в массиве (несколько подряд идущих элементов), то подобную операцию
следует делать в цикле.
Также в рамках практической работы будут задачи, которые на
практике уже не встречаются, так как их реализация «зашита» в работу
коллекций. Это задачи вставки в массив и удаления из
массива. Данные
задачи введены для закрепления студентами навыков обработки массивов.
Для задач вставки вводится искусственное ограничение – нельзя
создавать новые массивы, т.е. вся работа должна вестись с одним массивом.
И тут возникает сложность, так как массив невозможно «расширить» без
создания нового. Выход из этой ситуации – изначально задать массив больше
длины,
заполнить его частично изначальными значениями и далее уже,
посредством манипуляций над массивом, заносить в свободные ячейки новые
значения. Вопрос только, насколько большей длины задавать массив. И тут
надо исходить из задачи. Если задача подразумевает, что в ходе выполнения
в массив должен добавиться только один элемент, то изначально массив
задается на 1 элемент
больше от исходного (т.е., например, если в задании
указано, что исходный массив должен быть на 10 элементов, то задается
массив на 11 и заполняются первые 10, оставляя последний не заполненным).
Если же, исходя из условия задачи неизвестно, сколько потребуется вставить
новых элементов (например, вставить 0 после каждого отрицательного
элемента и при этом неизвестно,
сколько отрицательных значений будет в
массиве), то исходят из самого худшего сценария. Как правило – это
удвоение исходного размера массива (в случае предыдущего примера,
15

считается самый худший сценарий, когда все элементы массива –
отрицательные числа и после каждого потребуется вставить 0).
Важно! При создании массива все его элементы инициализируются, т.е.
им присваивается значение по умолчанию. Например, для целочисленного
типа значение по умолчанию, как правило, будет 0. Получается, когда
объявляется целочисленный массив, все его элементы имеют
Далее, в процессе работы программы в элементы массива вносятся уже
конкретные значения. А под свободными или пустыми элементами
понимаются элементы массива, в которые не заносились значения в ходе
работы программы. При этом важно понимать, что в качестве конкретного
значения, заносимого в элемент массива может быть значение 0, поэтому
считать, свободным элемент
не является корректным. Тут нужно именно понимать, с какими элементами
массива в процессе работы программы уже выполнялись манипуляции, а
какие были только проинициализированы.
Логика реализации задач вставки следующая:
1. Задаем массив нужной длины
массива, у которого в качестве значения лежит 0
значение 0.
2. Заполняем часть массива значениями
3. Начинаем проходить по заполненной
3.1. Если элемент массива удовлетворяет условию вставки
3.1.1. «Сдвигаем» все элементы после текущего на единицу вправо
3.1.2. Вставляем требуемое значение после текущего элемента (это при
условии задачи, если требуется вставлять «после», если требуется
вставлять «до», то текущий элемент также сдвигается вправо)
3.1.3. Фиксируем, что заполненная часть массива увеличилась
4. Выводим результат (только заполненную часть массива)
части
16
на 1

Самое сложное в реализации данного решения – операция сдвига. Она
подразумевает, что часть элементов массива (цепочка) переставляется влево
или вправо относительно текущей позиции.
Рассмотрим на примере сдвига вправо. Сперва необходимо убедиться,
что правее от цепочки сдвигаемых элементов есть пустые (если, конечно, это
не циклически сдвиг). Если есть пустые, то начинаем с
расположенного справа (так как сдвигать необходимо вправо) от крайнего
правого элемента цепочки. Этому элементу присваивается значение, которое
хранится в крайнем правом элементе цепочки. Далее крайнему правому
элементу цепочки присваивается значение элемента, расположенного слева
от него. Далее этому элементу (расположенному слева от крайнего)
присваивается значение из элемента, расположенного левее. И
пока не дойдем до первого элемента цепочки, ему уже ничего присваивать не
надо.
Рассмотрим схематично, как это выглядит. Допустим, есть массив на 10
элементов и требуется после максимального вставить 0 (рисунок 1.4).
5 7 0 3 9 6 7 8 0 2 1
элемента,
так далее,
Рисунок 1.4 – Схематичное представление массива
Так как потребуется вставлять только 1 элемент, массив задается на 11
элементов и заполняются первые 10. Последний элемент
остается условно незаполненным. Максимальный элемент в массиве – 9. Он
расположен на 2 позиции (отсчет идет с 0). Получается, потребуется
«сдвинуть» все элементы, расположенные правее 2 позиции. Начинаем все с
элемента, распложенного правее от крайнего элемента цепочки, это элемент
на 10 позиции. Ему присваивается значение с элемента 9 позиции (рисунок
1.5).
5 7 7 3 9 6 7 8 0 2 1
Рисунок 1.5 – «Сдвиг» крайнего правого
(помечен красным)
элемента
17

Далее крайнему правому элементу присваивается значение из
элемента, расположенного левее от него (рисунок 1.6).
5 7 7 3 9 6 8 8 0 2 1
Рисунок 1.6 – «Сдвиг» второго элемента
И так далее, пока не дойдем до первого элемента цепочки
(рисунок 1.7).
5 7 7 3 9 2 8 1 6 3 0
Рисунок 1.7 – «Сдвиг» цепочки
Далее первому элементу присваивается значение, которое следует
вставить по условию (рисунок 1.8).
5 7 7 3 9 2 8 1 6 0 0
Рисунок 1.8 – Вставка в массив
Так как операция «сдвига» повторяется для каждого элемента цепочки,
то используется оператор цикла для выполнения этой операции. Также,
всегда есть нюансы по задаче, например, вставить нужно «до» какого-то
элемента, или вставить несколько элементов и т.п. Эти нюансы влияют, с
какого элемента начинается сдвиг и до какого элемента он выполняется
Также важно, что, если требуется сдвиг вправо, то операция начинается
с крайнего правого элемента, и идет влево. Если же требуется сдвиг влево, то
операция должна начинаться с крайнего левого элемента и идти вправо. В
противном случае, будет потеря данных. Например, если бы при решении
предыдущей задачи сдвиг начинался бы с
то получилось бы следующая картина (рисунок 1.9).
5 7 3 3 9 3 3 3 3 3 3
Рисунок 1.9 – Некорректный сдвиг в массиве
18
левой позиции и двигался в право,
.

Остается рассмотреть операцию удаления. Она проще операции
вставки тем, что тут массив не будет увеличиваться, следовательно, при его
создании нет необходимости закладывать в длину «лишние» элементы.
Вся задача сводится к следующим этапам:
1. Задаем массив нужной длины
2. Заполняем массив значениями
3. Начинаем проходить по массиву
3.1. Если элемент
3.1.1. «Сдвигаем» все элементы, начиная с текущего на единицу влево
3.1.2. Фиксируем, что условная длина массива уменьшилась на 1
4. Выводим результат (с учетом, что были «удалены» часть элементов)
Рассмотрим на примере задачи. Требуется удалить из массива все
нечетные элементы. Массив на 10 элементов. Схематично будет выглядеть
следующим
(рисунок 1.10).
Рисунок 1.10 – Схематичное представление исходного массива на 10
образом. Изначально заполняем массив на 10 элементов
массива удовлетворяет условию удаления
5 7 3 9 6 7 8 0 2 1
элементов
Далее для каждого элемента, удовлетворяющего условию, выполняем
сдвиг влево, «затирая» значение в этом элементе (рисунок 1.11).
7 9 2 3 0 7 7 1 6 8
Рисунок 1.11 – Удаление первого элемента
В результате получается такой массив (рисунок 1.12).
2 6 8 0 7 7 7 7 7 7
Рисунок 1.12 – Массив после операции удаления
По результату операции было
таким образом массив условно «уменьшился» на 6 элементов, следовательно,
выполнено 6 операции сдвига влево,
19

при выводе такого массива следует выводить только первые 4 (исходный
размер массива – удаленные элементы) элемента.
Общее задание
1. Требуется сделать desktop-приложение по обработке массивов.
Необходимо реализовать следующее:
а. На форме в левой части разместить панель, в которую
поместить 6 кнопок (по количеству заданий, одна кнопка
инициирует запуск обработки одного задания).
б. На форме в правой части сверху разместить панель, в
которую поместить текстовое поле для ввода массива и 2
кнопки, для генерации одномерного и двумерного массивов
(по нажатию кнопки текстовое поле должно заполняться
либо одномерным массивом, либо двумерным, в
зависимости от нажатой кнопки).
в. Для генерации массивов на панели предусмотреть
возможность ввода размерности массива и диапазона
генерируемых под него значений.
г. На форме в правой части ниже разместить панель, в
которой по нажатию кнопки из левой панели будет
выводится задание по варианту.
д. На форме в правой части в нижней панели разместить
кнопку при нажатии на которую будет выводится
результат
е. Обязательно! Программа должна корректно
отрабатывать случаи недостаточности данных для
обработки массива, согласно заданию.
выполнения задания.
ж. Запрещено использовать дополнительные массивы, если
это явно не указано в задании.
20
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
