- •Базовые понятия информатики. Понятие «Информатика» и «Информация»
- •Информация
- •Информационные технологии
- •Понятие алгоритма. Свойства и классы алгоритмов. Формы представления алгоритмов
- •Понятие алгоритма. Базовые алгоритмические структуры
- •Представление данных в памяти персонального компьютера.
- •Принципы обработки программных кодов
- •Компиляторы
- •Интерпретатор
- •Язык с. История развития. Основные свойства языка
- •Отличительные особенности языкаC
- •Элементы языка c
- •Константы
- •Базовые типы данных
- •Директива #include
- •Использование void
- •Инструкция return
- •Описание переменных
- •Обработка данных. Операторы
- •Арифметические операторы
- •Приоритет операторов и порядок вычислений
- •Используемые алгоритмы обработки данных
- •Аккумуляторы
- •Преобразования типов данных
- •Декларации и дефиниции функций
- •Формальные и фактические параметры. Вызов функций
- •Возврат функцией значений
- •Переменные в функциях
- •Автоматические (локальные) переменные
- •Внешние (глобальные) переменные
- •Статические переменные
- •Передача параметров по значению
- •Передача параметров по ссылке
- •Значения параметров по умолчанию
- •Перегрузка функций
- •Рекурсия
- •Встроенные функции
- •Обработка символьных данных
- •Функция puts()
- •Функция putchar()
- •Функция printf()
- •Выбор правильных средств вывода информации
- •Функция gets()
- •Функция getchar()
- •Функция scanf()
- •Выбор соответствующих средств ввода данных
- •Управляющие структуры Структуры выбора (if / else)
- •Структуры выбора (switch/case/default)
- •Структуры повторения (циклы)
- •Использование цикла for
- •Использование цикла do...While (постусловие)
- •Использование цикла while (предусловие)
- •Операторы передачи управления Оператор безусловного перехода goto
- •Оператор break
- •Оператор continue
- •Препроцессор языка Си
- •Массивы Объявление переменной массива
- •Использование индексной переменной
- •Инициализация массива при объявлении
- •Передача массивов в функции
- •Использование констант при объявлении массивов
- •Символьные строки
- •Массивы строк
- •Алгоритмы сортировки массива
- •Поиск заданного элемента в массиве
- •Указатели
- •Объявление указателя
- •Указатели на массивы
- •Операции над указателями
- •Указатели на строку
- •Указатели на функцию
- •Функции, возвращающие указатель
- •Указатели на многомерные массивы
- •Массивы указателей
- •Динамическое распределение памяти
- •Структуры данных
- •Реализация одних структур на базе других
- •Очередь
- •Операции над очередями
- •Операции над стеками
- •Ссылочные реализации структур данных
- •Операции над списками
Массивы строк
Можно организовать массив строк точно так же, как массив данных любого другого типа. Но массив строк, по сути, будет являться уже массивом массивов символов. Массив, элементы которого сами являются массивами, называется двухмерным массивом.
Двухмерный массив можно представить себе как таблицу, имеющую ряды и колонки. Такой массив следует определять с двумя индексами, один из которых определяет количество рядов таблицы, а второй устанавливает количество колонок. Ниже приведены инструкции, определяющие массив, имеющий 10 рядов и 20 колонок, то есть содержащий 200 целочисленных переменных:
int table[10][20];
Представим себе каждый элемент как целое число, занимающее собственную клеточку в таблице 10х20. Элемент table[0][0] находится в левом верхнем углу таблицы, а элемент table[0][1] занимает соседнюю клетку справа в том же ряду.
Определяя массив строк, также необходимо использовать два индекса. Первый определяет максимальное количество строк в массиве, а второй указывает максимальную длину каждой строки. Таким образом, определение
char names[10][20];
задает десять строковых переменных names длиной не больше 19 символов в каждой.
Если вы хотите задавать строки путем ввода значений отдельных символов, следует использовать вложенные циклы. Внешний цикл будет повторяться 10 раз, по одному на каждую строку, а внутренний должен иметь 19 повторов для ввода значений одной строки.
Для того чтобы ввести символ в строку, необходимо использовать оба индекса:
name[index][index2] = letter;
Первый индекс указывает номер нужной строки внутри массива, а второй определяет позицию символа внутри строки.
Расположение матриц в памяти
Двумерный массив можно инициировать так:
static int matr[2][5] = {{3,4,0,1,2},{6,5,1,4,9}};
Матрица хранится в памяти построчно, т.е. самый правый индекс в наборе индексов массива меняется наиболее быстро.
Например, для массива char aCh[2][4] будет выделено восемь байтов памяти, в которых в следующем порядке будут размещены элементы массива:
элемент |
aCh[0][0] |
aCh[0][1] |
aCh[0][2] |
aCh[0][3] |
aCh[1][0] |
aCh[1][1] |
aCh[1][2] |
aCh[1][3] |
N байта |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Трехмерный массив
При размещении трехмерного массива char aс[3][2][3] память под элементы этого массива будет выделяться последовательно в соответствии со следующими значениями индексов:
A000 |
A001 |
A002 |
|
A010 |
A011 |
A012 |
|
A100 |
A101 |
A102 |
A110 |
A111 |
A112 |
|
A200 |
A201 |
A202 |
|
A210 |
A211 |
A212 |
Общий объем выделяемой под массив памяти определяется как произведение всех размерностей массива (общее число элементов), умноженное на длину типа данных массива.
Алгоритмы сортировки массива
Пузырьковая сортировка
Расположим массив сверху вниз, от нулевого элемента - к последнему.
Идея метода: шаг сортировки состоит в проходе снизу вверх по массиву. По пути просматриваются пары соседних элементов. Если элементы некоторой пары находятся в неправильном порядке, то меняем их местами.
После нулевого прохода по массиву "вверху" оказывается самый "легкий" элемент - отсюда аналогия с пузырьком. Следующий проход делается до второго сверху элемента, таким образом, второй по величине элемент поднимается на правильную позицию...
Делаем проходы по все уменьшающейся нижней части массива до тех пор, пока в ней не останется только один элемент. На этом сортировка заканчивается, так как последовательность упорядочена по возрастанию.
#include <iostream.h>
#include <conio.h>
int main()
{int array[100],size,x,y,temp,i;
cin>>size;
for (x=0;x<size;x++)
cin>>array[x];
for (i=size;i>0;i--)
for (int j=0;j<i;j++)
if (array[j]>array[j+1])
{
int b=array[j];
array[j]=array[j+1];
array[j+1]= b;
}
for (i=0;i<size;i++)
cout<<array[i]<<" ";
getch();
return 0;
}
Главным недостатком пузырьковой сортировки является количество перестановок элементов массива.
Выборочная сортировка
Идея метода состоит в том, чтобы создавать отсортированную последовательность путем присоединения к ней одного элемента за другим в правильном порядке. Будем строить готовую последовательность, начиная с левого конца массива. Алгоритм состоит из n последовательных шагов, начиная от нулевого и заканчивая (n-1)-м.
На i-м шаге выбираем наименьший из элементов a[i] ... a[n] и меняем его местами с a[i]. Последовательность шагов при n=5 изображена на рисунке ниже.
Вне зависимости от номера текущего шага i, последовательность a[0]...a[i] (выделена курсивом) является упорядоченной. Таким образом, на (n-1)-м шаге вся последовательность, кроме a[n] оказывается отсортированной, а a[n] стоит на последнем месте по праву: все меньшие элементы уже ушли влево.
Далее приведен код выборочной сортировки по возрастанию элементов.
Как и при пузырьковой сортировке, данный алгоритм будет просматривать подмассивы и отыскивать наименьший элемент в каждом из них. Подмассивы будут ограничиваться с двух сторон индексами start и size-1. Правый индекс равен size-1, т.к., если все прочие элементы заняли свои места, наибольший элемент автоматически оказывается в правильном расположении.
#include <iostream.h>
#include <conio.h>
main() {
int array[100], size, min_pos, i, start, min, temp;
cin>>size;
for (i=0; i<size; i++)
cin>>array[i];
start=0;
while (start!=size-1) {
min=array[start];
min_pos=start;
for (i=start; i<size; i++)
if (array [i]<min)
{
min=array[i];
min_pos=i; }
if (min_pos!=start)
temp=array[start];
array[start]=array[min_pos];
array[min_pos]=temp; }
start++;
} for (i=0; i<size; i++)
cout<<array[i]<< " ";
getch();
return 0;
}
Пузырьковая сортировка и выборочная сортировка сравнительно неэффективны, их среднее время работы пропорционально n2, где n – количество элементов массива.
Быстрая сортировка
"Быстрая сортировка", хоть и была разработана более 40 лет назад, является наиболее широко применяемым и одним их самых эффективных алгоритмов. Метод основан на подходе "разделяй-и-властвуй". Общая схема такова:
из массива выбирается некоторый опорный элемент a[i],
запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные a[i], влево от него, а все ключи, большие, либо равные a[i] - вправо,
теперь массив состоит из двух подмножеств, причем левое меньше, либо равно правого,
для обоих подмассивов: если в подмассиве более двух элементов, рекурсивно запускаем для него ту же процедуру.
В конце получится полностью отсортированная последовательность.
Рассмотрим алгоритм подробнее.
1. Введем два указателя: i и j. В начале алгоритма они указывают, соответственно, на левый и правый конец последовательности.
2. Будем двигать указатель i с шагом в один элемент по направлению к концу массива, пока не будет найден элемент array [i] >=p. Затем аналогичным образом начнем двигать указатель j от конца массива к началу, пока не будет найден array[j]<=р.
3. Далее, если i<=j, меняем array [i] и array [j] местами и продолжаем двигать i и j по тем же правилам.
4. Повторяем шаг 2, пока i<=j.
Теперь массив разделен на две части: все элементы левой меньше либо равны опорному элементу, все элементы правой — больше либо равны опорному элементу. Разделение завершено.
Проиллюстрируем работу алгоритма на примере. Исходный массив:
5 2 7 2 13 3 8 15 19
Выберем опорный элемент р. Например, пусть это будет элемент 13. 1.
Шаг 1. Меняем местами элементы в позициях 4 и 6:
5 2 7 2 8 3 13 15 19
Выбираем опорный элемент 7.
Шаг 2. Меняем местами элементы в позициях 2 и 5:
5 2 3 2 8 7 13 15 19
Выбираем опорный элемент 2.
Шаг 3. Меняем местами элементы в позициях 0 и 3:
2 2 3 5 8 7 13 15 19
Выбираем опорный элемент 8
Шаг 4. Меняем местами элементы в позициях 4 и 5:
2 2 3 5 7 8 13 15 19
Сортировка закончена, т. к. все элементы встали на свои позиции.
Далее приведен код быстрой сортировки. Быструю сортировку выполняет функция quicksort. В качестве параметров функции выступают верхняя и нижняя границы обрабатываемого на данном шаге подмассива.
#include <iostream.h>
#include <conio.h>
int array[100000];
void quicksort(long High, long Low)
{
long i,j;
int p, temp;
i=Low;
j=High;
p=array[(Low+High)/2];
while(array[i]<p)
i++;
while(array[j]>p) j--;
if (i<=j)
{
temp=array[i];
array[i]=array[j];
array[j]=temp;
while (i<=j);
if (j>Low) quicksort(j, Low);
if (High>i) quicksort(High, i);
}
main()
{
int size;
int i ;
cin>>size;
for (i=0; i<size; i++)
cin>>array[i];
quicksort(size-1, 0);
for (i=0; i<size; i++)
cout<<array[i]<<” “;
getch();
return 0;
}
Сортировка массива при известном интервале значений элементов
Данная сортировка применима к массиву только в том случае, если задано некоторое число К, и все элементы массива меньше либо равны ему, т. е. для выполнения данной сортировки необходимо знать один общий интервал, в котором лежит каждый элемент массива. Алгоритм такой сортировки достаточно прост в реализации.
Пусть дан массив натуральных чисел, значение каждого элемента которого не превышает девяти (табл. 1).
Таблица 1. Массив натуральных чисел
Для сортировки такого массива будет использоваться вспомогательный массив, число ячеек в котором совпадает с числом К. В нашем случае необходимо выделить память для массива из девяти ячеек, которые будут заполнены нулями (табл. 2).
Таблица 2. Вспомогательный массив, заполненный нулями
Теперь будем поочередно просматривать каждый элемент массива, который необходимо отсортировать, и, если на /-ом шаге выделен элемент М, то во вспомогательном массиве значение элемента, находящегося в позиции М, увеличиваем на единицу.
Совершим вышеописанные действия с заданным массивом чисел. После завершения работы алгоритма вспомогательный массив примет вид, как указано в табл. 3.
Таблица 3.
Теперь вспомогательный массив обработан, можно выводить результат следующим образом: если элемент вспомогательного массива не равен нулю, то выводим номер его позиции Р раз, где Р равно значению данного элемента.
Итак, в нашем случае вывод будет следующим: 2, 4, 5, 5, 8, 9.
Теперь рассмотрим программу, которая сортирует массив натуральных чисел вышеуказанным методом. Чтобы не вводить все элементы массива, сгенерируем их случайным образом при помощи функции random(int). Ниже приведен код данной программы:
#include <iostream.h>
#include <conio.h>
tinclude <stdlib.h>
int i, j, N, K, array[1000], Help_array[1000];
main()
{
cin>>N>>K;
randomize();
for (i=0; i<N; i++)
array[i]=random(K);
for (i=0; i<N; i++)
Help_array[array[i]]+=1;
for (i=1; i<K; i++)
if (Help_array!=0)
for (j=0; j<Help_array[i]; j++)
cout<<i<<” “;
getch();
return0;
}