- •Содержание
- •1. Основные понятия и определения
- •1.1. Структура персональной ЭВМ
- •1.2. Размещение данных и программ в памяти ПЭВМ
- •1.3. Программные модули
- •1.4. Ошибки
- •1.5. Функциональная и модульная декомпозиции
- •1.6. Файловая система хранения информации
- •1.7. Операционная система
- •2. Понятие алгоритмов и способы их описания
- •2.1. Свойства алгоритмов
- •2.2. Способы описания алгоритмов
- •3. Базовые элементы языка Cи
- •3.1. Алфавит языка
- •3.2. Лексемы
- •3.3. Идентификаторы и ключевые слова
- •3.4. Знаки операций
- •3.5. Литералы (константы)
- •3.6. Комментарии
- •4. Базовые типы объектов
- •4.1. Простейшая программа
- •4.2. Основные типы данных
- •4.3. Декларация объектов
- •4.4. Данные целого типа (int)
- •4.5. Данные символьного типа (char)
- •4.6. Данные вещественного типа (float, double)
- •5. Константы в программах
- •5.1. Целочисленные константы
- •5.2. Константы вещественного типа
- •5.3. Символьные константы
- •5.4. Строковые константы
- •6. Обзор операций
- •6.1. Операции, выражения
- •6.2. Арифметические операции
- •6.3. Операции присваивания
- •6.4. Сокращенная запись операции присваивания
- •6.5. Преобразование типов операндов арифметических операций
- •6.6. Операция приведения типа
- •6.7. Операции сравнения
- •6.8. Логические операции
- •6.9. Побитовые логические операции, операции над битами
- •6.10. Операция «,» (запятая)
- •7. Обзор базовых инструкций языка Си
- •7.1. Стандартная библиотека языка Си
- •7.2. Стандартные математические функции
- •7.3. Функции вывода данных
- •7.4. Функции ввода информации
- •7.5. Ввод - вывод потоками
- •8. Синтаксис операторов языка Cи
- •8.1. Условные операторы
- •8.2. Условная операция «? :»
- •8.3. Оператор выбора альтернатив (переключатель)
- •9. Составление циклических алгоритмов
- •9.1. Понятие цикла
- •9.2. Оператор с предусловием while
- •9.3. Оператор цикла с постусловием do – while
- •9.4. Оператор цикла с предусловием и коррекцией for
- •10. Операторы передачи управления
- •10.1. Оператор безусловного перехода goto
- •10.2. Оператор continue
- •10.3. Оператор break
- •10.4. Оператор return
- •11.1. Операции над указателями (косвенная адресация)
- •11.2. Ссылка
- •12. Массивы
- •12.1. Одномерные массивы
- •12.2. Многомерные массивы
- •12.3. Операция sizeof
- •12.4. Применение указателей
- •12.5. Указатели на указатели
- •13. Работа с динамической памятью
- •13.1. Пример создания одномерного динамического массива
- •13.2. Пример создания двухмерного динамического массива
- •14. Строки в языке Си
- •14.1. Русификация под Visual
- •15. Функции пользователя
- •15.1. Декларация функции
- •15.2. Вызов функции
- •15.3. Операция typedef
- •15.4. Указатели на функции
- •16. Классы памяти и области действия объектов
- •16.1. Автоматические переменные
- •16.2. Внешние переменные
- •16.3. Область действия переменных
- •17. Структуры, объединения, перечисления
- •17.1. Структуры
- •17.2. Декларация структурного типа данных
- •17.3. Создание структурных переменных
- •17.4. Вложенные структуры
- •17.5. Массивы структур
- •17.6. Размещение структурных переменных в памяти
- •17.7. Объединения
- •17.8. Перечисления
- •18. Файлы в языке Си
- •18.1. Открытие файла
- •18.2. Закрытие файла
- •18.3. Запись – чтение информации
- •18.4. Текстовые файлы
- •18.5. Бинарные файлы
- •Литература
- •Приложение 1. Таблицы символов ASCII
- •Приложение 2. Операции языка Си
- •Приложение 3. Возможности препроцессора
- •1. Вид рабочего стола консольного приложения Visual C++
- •2. Создание нового проекта
- •3. Добавление к проекту файлов с исходным кодом
- •4. Компиляция, компоновка и выполнение проекта
- •5. Конфигурация проекта
- •6. Открытие существующего проекта
- •Приложение 5. Некоторые возможности отладчика Visual C++
- •1. Установка точки прерывания
- •2. Пошаговое выполнение программы
- •3. Проверка значений переменных во время выполнения программы
- •4. Окна Auto и Watch 1
- •5. Программные средства отладки
- •ЧАСТЬ 2
- •1. Системы счисления
- •1.1. Общие определения
- •1.2. Алгоритмы перевода из одной системы счисления в другую
- •2. Организация памяти и структуры данных
- •3. Линейные списки и рекурсия
- •4. Динамическая структура данных – СТЕК
- •5. Динамическая структура данных – ОЧЕРЕДЬ
- •6. Двунаправленный линейный список
- •7. Построение обратной польской записи
- •8. Нелинейные структуры данных
- •Пояснение к программе
- •9. Понятие хеширования
- •9.1. Хеш-функция и хеш-таблица
- •9.2. Схемы хеширования
- •10. Элементы теории погрешностей
- •10.1. Методы реализации математических моделей
- •10.2. Источники погрешностей
- •10.3. Приближенные числа и оценка их погрешностей
- •10.4. Прямая задача теории погрешностей
- •10.5. Обратная задача теории погрешностей
- •10.6. Понятия устойчивости, корректности и сходимости
- •11. Вычисление интегралов
- •11.1. Формулы численного интегрирования
- •11.2. Формула средних
- •11.3. Формула трапеций
- •11.4. Формула Симпсона
- •11.5. Схема с автоматическим выбором шага по заданной точности
- •12. Методы решения нелинейных уравнений
- •12.1. Итерационные методы уточнения корней
- •12.2. Метод Ньютона
- •12.3. Метод секущих
- •12.4. Метод Вегстейна
- •12.5. Метод парабол
- •12.6. Метод деления отрезка пополам
- •13. Решение систем линейных алгебраических уравнений
- •13.1. Прямые методы решения СЛАУ
- •13.2. Метод Гаусса
- •13.3. Метод прогонки
- •13.4. Метод квадратного корня
- •13.5. Итерационные методы решения СЛАУ
- •13.6. Метод простой итерации
- •14. Поиск и сортировка
- •14.1. Последовательный поиск в массиве
- •14.2. Барьерный последовательный поиск
- •14.3. Сортировка вставками (включениями)
- •14.4. Двоичный поиск
- •14.5. Сортировка выбором
- •14.6. Алгоритмы сортировки выбором
- •14.7. Сортировка обменом
- •14.8. Быстрая сортировка
- •15. Обработка статистических данных
14.8. Быстрая сортировка
Все рассмотренные ранее методы обмена не столь эффективны при реализации на ЭВМ из-за сравнений и возможных обменов только соседних элементов. Лучшие результаты дают методы, в которых пересылки выполняются на большие расстояния. Рассмотрим два наиболее быстрых алгоритмов.
Метод Хоара
Метод Хоара (Charles Antony Richard Hoare, 1962 г.), называемый также методом быстрой сортировки (Quicksort) основывается на следующем: находится такой элемент, который разбивает множество на два подмножества так, что в одном все элементы больше, а в другом – меньше делящего. Каждое из подмножеств также разделяется на два, по такому же признаку. Конечным итогом такого разделения станет рассортированное множество. Рассмотрим один из вариантов реализации сортировки Хоора.
В самой процедуре сортировки сначала выберем средний элемент. Потом, используя переменные i (цикл i=0, i++) и j (цикл j=n-1, j--), пройдемся по массиву, отыскивая в левой части элементы больше среднего, а в правой – меньше среднего. Два найденных элемента переставим местами. Будем действовать так, пока i не станет больше j. Тогда мы получим два подмножества, ограниченные с краев индексами l и r, а в середине – j и i. Если эти подмножества существуют (т.е. i<r и j>l), то выполняем их сортировку.
Например, необходимо рассортировать массив: 13, 3, 23, 19, 7, 53, 29, 17 Переставляемые элементы будем подчеркивать, средний – выделим жирным шрифтом (19), а элемент, попавший на свое место и не участвующий в последующих сравнениях – наклонным шрифтом. Индекс i будет задавать номер элемента слева от среднего, а j справа от среднего.
1)13 3 23 19 7 53 29 17
i → . . . ←j
ищем в левой части элемент больший среднего, а в правой – меньший среднего,
это 23 и |
17, переставляем их; |
|
2) |
13 3 17 19 7 53 29 23 |
– переставили (19 и 7); |
3)13 3 17 7 | 19 53 29 23
справа все большие среднего (19), слева – меньшие, теперь делим совокупность на два подмножества:
------- |
|
А ------- |
|
|
|
---------- В ----------- |
|
||
13 |
3 |
17 |
7 |
|
|
19 |
53 |
29 |
23 |
---А1--- |
|
-----А2----- |
|
|
19 |
23 |
29 |
53 – здесь |
|
Выделяем подмножество |
3 |
|
13 17 |
7 |
|||||
|
13 |
17 |
7 |
|
|
|
7 |
17 |
|
Выделяем подмножество |
13 |
|
|||||||
Результат: |
|
3 |
|
7 13 |
17 |
19 23 29 53 |
|||
Как искать точку деления: |
|
|
|
||||||
|
|
|
19 |
53 |
24 |
|
23 |
|
|
|
|
|
i=left |
|
|
|
j=right |
|
210
19 < 23 |
– обмен не требуется: j = j-1 |
|||
|
19 |
53 |
24 |
23 |
19 < 24 |
– обмен не требуется: j = j-1 |
|||
|
19 |
53 |
24 |
23 |
Метод Шелла
Сортировка Шелла (Donald Lewis Shell), предложенная в 1959 г., называется также «слиянием с обменом» и является расширением челночной сортировки.
Основная идея алгоритма состоит в том, что на начальном этапе реализуется сравнивание и перемещение далеко отстоящих друг от друга элементов. Интервал между сравниваемыми элементами (h) постепенно уменьшается до единицы, что приводит к перестановке соседних элементов на последних стадиях сортировки (если это необходимо).
Реализуем метод Шелла следующим образом. Начальный шаг сортировки примем равным h=n/2, т.е. 0,5 от общей длины массива, и после каждого прохода будем уменьшать его в два раза. Каждый этап сортировки включает в себя проход всего массива и сравнение отстоящих на h элементов (i=0; j=n/2; i++; j++; до тех пор, пока j<n). Проход с тем же шагом повторяется, если элементы переставлялись. Заметим, что после каждого этапа отстоящие на h элементы отсортированы.
Таким образом, вначале сравниваются (и, если нужно, переставляются) далеко стоящие элементы, а на последнем проходе – соседние элементы
Рассмотрим пример. Рассортировать массив: 41, 53, 11, 37, 79, 19, 7, 61.
В строке после массива в круглых скобках указаны индексы сравниваемых элементов и указан номер внешнего цикла.
Цикл |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
– индексы элементов |
|
41 |
53 |
11 |
37 |
79 |
19 |
7 |
61 |
– исходный массив |
1-ый |
41 |
19 |
11 |
37 |
79 |
53 |
7 |
61 |
– (0,4),(1,5) |
|
41 |
19 |
7 |
37 |
79 |
53 |
11 |
61 |
– (2,6),(3,7) |
2-ой |
7 |
19 |
41 |
37 |
11 |
53 |
79 |
61 |
– (0,2),(1,3),(2,4),(3,5),(4,6),(5,7) |
|
7 |
19 |
11 |
37 |
41 |
53 |
79 |
61 |
– (0,2),(1,3),(2,4),(3,5),(4,6),(5,7) |
3-ий |
7 |
11 |
19 |
37 |
41 |
53 |
61 |
79 |
– сравнивались соседние |
Алгоритм метода Шелла
Внешний цикл (1): от h=n/2 до h>0; h=h/2
Вложенный внутренний цикл (2): do (выполнять пока end_sort =1):
1)end_sort = 0
2)цикл (3): для i от 0 до h; j от h; до тех пор, пока j<n; i++, j++ выполнить сравнение:
если x[i] > x[j] то переставить местами, т.е. buf = x[j], x[j] = x[i], x[i] = buf;
211
изменить признак: |
end_sort = 1; |
3) конец цикла (3) |
|
Конец циклов (2 и 1): выполнять пока end_sort =1, каждый выход будет уменьшать h в два раза.
Выигрыш получается за счет того, что на каждом этапе сортировки либо участвует сравнительно мало элементов, либо эти элементы уже довольно хорошо упорядочены, и требуется небольшое количество перестановок. Последний просмотр сортировки Шелла выполняется по тому же алгоритму, что и в челночной сортировке. Предыдущие просмотры подобны просмотрам челночной обработки, но в них сравниваются не соседние элементы, а элементы, отстоящие на заданное расстояние h. Большой шаг на начальных этапах сортировки позволяет уменьшить число вторичных сравнений на более поздних этапах.
При анализе данного алгоритма возникают достаточно сложные математические задачи, многие из которых еще не решены. Например, неизвестно, какая последовательность расстояний дает лучшие результаты, хотя выяснено, что расстояния hi не должны быть множителями один другого.
Сортировка методом Шелла может быть реализована, например, в следующем виде:
#include <iostream.h> #include <conio.h>
void sort_Sh ( int *x, int n)
{
int i, j, buf, h, end_sort; for( h = n/2; h>0; h/=2) do
{
end_sort = 0;
for( i=0, j=h; j<n; i++, j++)
if( *(x+i)> *(x+j) ) |
// Сравниваем отстоящие на h элементы |
{ |
|
buf = *(x+j); |
// Переставляем элементы |
*(x+j) = *(x+i); |
|
*(x+i) = buf; |
|
end_sort = 1; |
// Есть еще не рассортированные данные |
} |
|
} while (end_sort); |
// Окончание этапа сортировки |
} |
|
void main() |
|
{
int x[ ] = { 41, 53, 11, 37, 79, 19, 7, 61}; // задали явно sort_Sh(x,8);
cout<<”Array: “; for (int i=0; i<8; i++)
cout << x[i] << “ “; cout<<endl;
212