- •Часть 2
- •18 Сентября 2012 г., протокол № 1
- •Предисловие
- •Глава 6 простые типы данных § 1. Целый тип
- •1.1. Битовые операции
- •Использование битовых операций
- •1.3. Упаковка и распаковка информации
- •§ 2. Логический тип
- •§ 3. Символьный тип
- •§ 4. Вещественный тип
- •§ 5. Преобразование типов
- •Преобразование типов в выражениях
- •Преобразование типов при присваивании
- •Г л а в а 7 введение в указатели
- •§ 1. Понятие указателя. Операции разыменования и разадресации
- •§ 2. Инициализация и присваивание указателей
- •§ 3. Распределение динамической памяти
- •Операция new
- •Операция delete
- •§ 4. Параметры-указатели. Функция ввода scanf
- •Упражнения, тесты
- •Г л а в а 8 одномерные массивы, указатели и функции
- •§ 1. Связь указателей и одномерных массивов. Передача массива в качестве параметра функции
- •§ 2. Сортировка одномерных массивов
- •§ 3. Сортировка массива по параметру числа
- •§ 4. Сортировка массива выбором.
- •§ 5. Сортировка массива вставками
- •§ 6. Динамические одномерные массивы
- •6.1. Порядок работы с динамическим массивом
- •6.2. Работа с динамическим массивом в классе. Деструктор
- •§ 7. Введение в строки
- •Глава 9 мАтрицы
- •§ 1. Объявление, способы определения матриц
- •§ 2. Вывод матриц
- •§ 3. Типы алгоритмов
- •3.1. Построчная обработка
- •Обработка матрицы по столбцам
- •3.3. Обработка всей матрицы
- •3.4. Обработка части матрицы
- •Преобразование матрицы
- •Построение матриц
- •§ 4. Матрицы, указатели и функции
- •Упражнения и тесты
- •Обработка матрицы по столбцам.
- •Список реКоМендуемой литературы
- •Сборники задач по программированию
- •Оглавление
- •Методы программирования:
- •Лекции, примеры, тесты
- •Пособие для студентов механико-математического факультета
- •В двух частях
- •Часть 2
§ 5. Сортировка массива вставками
Есть различные модификации алгоритмов сортировки вставками. Рассмотрим сортировку простыми вставками по возрастанию, которая сложнее рассмотренных раньше.
На первом шаге берём второй элемент массива, то есть x[1], и его оставляем на своём месте, если x[1] > x[0], или переставляем с x[0] в противном случае. Для массива 54, 43. 50. 77, 33, 49, 56 получим 43. 54, 50. 77, 33, 49, 56.
Берём число x[2]=50 и определяем его место. Для этого проверяем: 50<43? Нет. Проверяем дальше: 50<54? Да. Запоминаем число 50, например, t=x[2]; Число 43 оставляем на месте, 54 сдвигаем вправо: x[2]=x[1]; а на его место помещаем число 50: x[1]=t; После этого шага три числа будут рассортированы: 43. 50. 54, 77, 33, 49, 56
Определяем место числа x[3]=77. Для этого его сравниваем со всеми предыдущими. Так как результаты всех сравнений x[3]< x[0]; x[3]< x[1]; x[3]< x[2]; ложны, то x[3]=77 остаётся на своём месте. Так как x[4]< x[0] (33<43), то запоминаем число 33 (t=x[4]), четыре рассортированных числа сдвигаем в обратном порядке вправо x[4]= x[3]; x[3]= x[2]; x[2]= x[1]; x[1]=x[0];
а x[0]=t. Получим 33, 43. 50. 54, 77, 49, 56.
Аналогично определяем место числа x[5]=49. 49<33? Нет. 49<43? Нет. 49<50? Да. Поэтому t=49, числа 50, 54 и 77 сдвигаем вправо, x[2]=t и получим:
33, 43. 49, 50. 54, 77, 56.
Аналогично определяем место последнего числа x[6]=56. 56<33? Нет. 56<43? Нет. 56<49? Нет. 56<50? Нет. 56<54? Нет. 56<77? Да. Поэтому t=56, число 77 сдвигаем вправо и x[5]=t. Окончательно получим 33, 43. 49, 50. 54, 56, 77.
Предлагается самостоятельно запрограммировать описанный алгоритм.
§ 6. Динамические одномерные массивы
Массивы с фиксированной размерностью, заданной в виде константы, названные статическими, обладают рядом недостатков. Во-первых, в качестве размерности можно использовать только константу. А как быть, если количество элементов массива необходимо, например, ввести или вычислить? Во-вторых, память для таких массивов выделяется на этапе компиляции и остаётся занятой за функцией (или блоком) на всё время их выполнения до выхода из функции (блока). Эти и некоторые другие проблемы статических массивов можно преодолеть, используя так называемый динамический массив.
6.1. Порядок работы с динамическим массивом
1. В качестве его размерности можно, как и для статического массива, объявить и использовать константу. Но эффективнее для этого взять переменную, например, unsigned n . Определяем её одним из известных способов: вводим, вычисляем, задаём случайным образом и т. п.
2.Объявляем указатель на такой одномерный массив: тип_элементов_массива *указатель; например, float *ard; Из такого объявления массива ещё не видно, будем ли мы создавать массив ard или в переменной ard будет адрес одной ячейки для вещественного числа. Это зависит от того, как будем использовать операцию new.
3. При создании динамичского массива эта операция имеет следующий синтаксис: имя_массива = new тип_элементов_массива[размерность]; Для нашего примера ard=new float[n]; Эта операция, во-первых, в динамической памяти выделяет непрерывный участок для размещения массива указанной в квадратных (а не в круглых) скобках размерности, элементы которого будут иметь указанный тип (в примере вещественный). Кроме этого, операция возвращает адрес начала массива, то есть адрес его первого элемента. После выполнения операции присваивания этот адрес будет значением переменной ard.
Третий пункт можно объединить со вторым: float *ard= new float[n]; Но в отличие от статического инициализацию динамического массива одновременно с объявлением выполнять нельзя. float *ard= new float[n]={1.1,2.2, -30.3,-44}; приведёт к ошибке!
Ячейки для элементов динамического одномерного массива располагаются в оперативной памяти подряд. Поэтому работа с ним выполняется, как и для статического одномерного массива, двумя способами. Доступ к элементам динамического массива можно осуществлять с помощью явного указания индексов. Например, for (int i=0; i<n; i++) cin>>ard[i]; выполняет ввод массива. Кроме этого, динамические одномерные массивы, как и статические, можно обрабатывать, используя операции над указателями.
Если закончили работу с динамическим массивом, память, занятую для него, можно освободить во время выполнения программы, не дожидаясь её завершения, с помощью той же операции delete (гл. 6), синтаксис которой для динамического массива другой: delete [] имя_массива; Например, delete [] ard; освобождает всю память, выделенную для массива ard. В квадратных скобках ничего не записывается. Освободить память для части массива, указав в квадратных скобках выражение, невозможно.
Если delete “забыли” написать, то ошибки не будет. Но при работе с динамической памятью, особенно с массивами, память, выделенную с помощью new, рекомендуется всегда явно освобождать, используя delete. Дело в том, что при выходе из блока полученный с помощью new указатель уничтожается, но память остаётся распределённой, занятой, и к ней обратиться невозможно..
В отличие от статического массива адрес динамического можно менять. Но это нужно делать с осторожностью, чтобы не “потерять” адрес его начала. Этот адрес понадобится для освобождения занятой массивом памяти и, возможно, для других целей.
Из приведенных пяти этапов самым сложным и трудоёмким, но в то же время наиболее творческим является четвёртый, так как он связан с разработкой алгоритма. Остальные этапы являются почти стандартными. С другой стороны, если отлажен алгоритм в виде программы для статического одномерного массива, то этот же алгоритм можно использовать и для динамического одномерного массива, внеся небольшие почти одинаковые дополнения (см. этапы 1, 2, 3, 5).
