Слайд 1Программирование
на языке Си
Часть II
Массивы
Максимальный элемент массива
Обработка массивов
Сортировка массивов
Поиск в
массиве
Массивы в процедурах и функциях
© К.Ю. Поляков, 2007-2009
Практикум (моделирование)
Символьные строки
Рекурсивный
перебор
Матрицы
Файлы
Слайд 2Программирование
на языке Си
Часть II
Тема 1. Массивы
© К.Ю. Поляков, 2007-2009
Слайд 3Массивы
Массив – это группа однотипных элементов, имеющих общее имя и
расположенных в памяти рядом.
Особенности:
все элементы имеют один тип
весь массив имеет
одно имя
все элементы расположены в памяти рядом
Примеры:
список учеников в классе
квартиры в доме
школы в городе
данные о температуре воздуха за год
Слайд 4Массивы
A
массив
2
15
НОМЕР
элемента массива
(ИНДЕКС)
A[0]
A[1]
A[2]
A[3]
A[4]
ЗНАЧЕНИЕ элемента массива
A[2]
НОМЕР (ИНДЕКС)
элемента массива: 2
ЗНАЧЕНИЕ
элемента
массива: 15
Слайд 5Объявление массивов
Зачем объявлять?
определить имя массива
определить тип массива
определить число элементов
выделить
место в памяти
Пример:
Размер через константу:
имя
размер массива (количество элементов)
тип
элементов
int
A [ ];
const int N = 5;
N
int A [ 5 ];
Слайд 6Объявление массивов
Еще примеры:
int X[10], Y[10];
float zz, A[20];
char s[80];
С
присвоением начальных значений:
int A[4] = { 8, -3, 4,
6 };
float B[2] = { 1. };
char C[3] = { 'A', '1', 'Ю' };
остальные нулевые!
Слайд 7Что неправильно?
int N = 10;
float A[N];
const int
int X[4.5];
int A[10];
A[10]
= 0;
float X[5];
int n = 1;
X[n-2] = 4.5;
X[n+8] = 12.;
выход за границы массива
(стираются данные в памяти)
int X[4];
X[2] = 4.5;
дробная часть отбрасывается
(ошибки нет)
float B[2] = { 1., 3.8, 5.5 };
int A[2] = { 1, 3.8 };
float
Слайд 8Массивы
Объявление:
Ввод с клавиатуры:
Поэлементные операции:
Вывод на экран:
const int N = 5;
int A[N], i;
printf("Введите 5 элементов массива:\n");
for( i=0; i < N;
i++ ) {
printf ("A[%d] = ", i );
scanf ("%d", & A[i] );
}
A[0] =
A[1] =
A[2] =
A[3] =
A[4] =
5
12
34
56
13
for( i=0; i < N; i++ ) A[i] = A[i]*2;
printf("Результат:\n");
for( i=0; i < N; i++ )
printf("%4d", A[i]);
Результат:
10 24 68 112 26
Слайд 9Программа
#include
#include
main()
{
const int N = 5;
int A[N], i;
//
ввод элементов массива
// обработка массива
// вывод результата
getch();
}
Задача: ввести
с клавиатуры массив из 5 элементов, умножить все элементы на 2 и вывести полученный массив на экран.
на предыдущих слайдах
Слайд 10Задания
«4»: Ввести c клавиатуры массив из 5 элементов, найти среднее
арифметическое всех элементов массива.
Пример:
Введите пять чисел:
4
15 3 10 14
среднее арифметическое 9.200
«5»: Ввести c клавиатуры массив из 5 элементов, найти минимальный из них.
Пример:
Введите пять чисел:
4 15 3 10 14
минимальный элемент 3
Слайд 11Программирование
на языке Си
Часть II
Тема 2. Максимальный
элемент массива
© К.Ю.
Поляков, 2007-2009
Слайд 12Максимальный элемент
Задача: найти в массиве максимальный элемент.
Алгоритм:
Псевдокод:
// считаем, что
элемент A[0] – максимальный
for ( i=1; i < N; i++
)
if ( A[i] > максимального )
// запомнить новый максимальный элемент A[i]
Слайд 13Максимальный элемент
max = A[0]; // пока A[0]– максимальный
iMax =
0;
for ( i=1; i < N; i++ ) // проверяем
остальные
if ( A[i] > max ) { // нашли новый
max = A[i]; // запомнить A[i]
iMax = i; // запомнить i
}
Дополнение: как найти номер максимального элемента?
По номеру элемента iMax всегда можно найти его значение A[iMax]. Поэтому везде меняем max на A[iMax] и убираем переменную max.
A[iMax]
Слайд 14Заполнение случайными числами
RAND_MAX – максимальное случайное целое число
(обычно
RAND_MAX = 32767)
Случайное целое число в интервале [0,RAND_MAX]
x = rand(); // первое число
x = rand(); // уже другое число
Установить начальное значение последовательности:
srand ( 345 ); // начнем с 345
#include // случайные числа
Слайд 15Целые числа в заданном интервале
Целые числа в интервале [0,N-1]:
Примеры:
Целые числа в интервале [a,b]:
int random(int N) {
return rand()% N;
}
x = random ( 100 ); // интервал [0,99]
x = random ( z ); // интервал [0,z-1]
x = random ( z ) + a; // интервал [a,z-1+a]
x = random (b – a + 1) + a; // интервал [a,b]
Слайд 16Заполнение случайными числами
#include
#include
main()
{
const int N = 10;
int A[N],
i;
printf("Исходный массив:\n");
for (i = 0; i < N; i++ )
{
A[i] = random(100) + 50;
printf("%4d", A[i]);
}
...
}
int random(int N)
{ return rand() % N; }
функция выдает случайное число от 0 до N-1
Слайд 17Программа
#include
#include
main()
{
const int N = 5;
int A[N], i, iMax;
// заполнить случайными числами [100,150]
// найти максимальный элемент и
его номер
printf("\nМаксимальный элемент A[%d] = %d",
iMax, A[iMax]);
getch();
}
на предыдущих слайдах
Слайд 18Задания
«4»: Заполнить массив из 10 элементов случайными числами в интервале
[-10..10] и найти в нем максимальный и минимальный элементы и
их номера.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0
максимальный a[4]=10
минимальный a[8]=-10
«5»: Заполнить массив из 10 элементов случайными числами в интервале [-10..10] и найти в нем два максимальных элемента и их номера.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0
максимальные a[4]=10, a[7]=8
Слайд 19Программирование
на языке Си
Часть II
Тема 3. Обработка массивов
© К.Ю.
Поляков, 2007-2009
Слайд 20Реверс массива
Задача: переставить элементы массива в обратном порядке (выполнить инверсию).
Алгоритм:
поменять
местами A[0] и A[N-1], A[1] и A[N-2], …
Псевдокод:
for ( i
= 0; i < N; i++ )
// поменять местами A[i] и A[N-1-i]
сумма индексов N-1
Слайд 21Как переставить элементы?
2
3
1
Задача: поменять местами содержимое двух чашек.
Задача: поменять местами
содержимое двух ячеек памяти.
4
6
?
4
6
4
x
y
c
c = x;
x = y;
y = c;
x
= y;
y = x;
3
2
1
Слайд 22Программа
main()
{
const int N = 10;
int A[N], i, c;
// заполнить массив
// вывести исходный массив
for (
i = 0; i < N/2; i++ ) {
c = A[i];
A[i] = A[N-1-i];
A[N-1-i] = c;
}
// вывести полученный массив
}
Слайд 23Задания
«4»: Заполнить массив из 10 элементов случайными числами в интервале
[-10..10] и выполнить инверсию отдельно для 1-ой и 2-ой половин
массива.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0
Результат:
-4 10 3 -5 4 0 1 -10 8 -6
«5»: Заполнить массив из 12 элементов случайными числами в интервале [-12..12] и выполнить инверсию для каждой трети массива.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0 5 7
Результат:
10 3 -5 4 -10 8 -6 -4 7 5 0 1
Слайд 24Циклический сдвиг
Задача: сдвинуть элементы массива влево на 1 ячейку, первый
элемент становится на место последнего.
Алгоритм:
A[0]=A[1]; A[1]=A[2];… A[N-2]=A[N-1];
Цикл:
for ( i =
0; i < N-1; i ++)
A[i] = A[i+1];
почему не N?
Слайд 25Программа
main()
{
const int N = 10;
int A[N], i, c;
// заполнить массив
// вывести исходный массив
c = A[0];
for ( i = 0; i < N-1; i ++)
A[i] = A[i+1];
A[N-1] = c;
// вывести полученный массив
}
Слайд 26Задания
«4»: Заполнить массив из 10 элементов случайными числами в интервале
[-10..10] и выполнить циклический сдвиг ВПРАВО.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0
Результат:
0 4 -5 3 10 -4 -6 8 -10 1
«5»: Заполнить массив из 12 элементов случайными числами в интервале [-12..12] и выполнить циклический сдвиг ВПРАВО на 4 элемента.
Пример:
Исходный массив:
4 -5 3 10 -4 -6 8 -10 1 0 5 7
Результат:
1 0 5 7 4 -5 3 10 -4 -6 8 -10
Слайд 27Программирование
на языке Си
Часть II
Тема 4. Сортировка массивов
© К.Ю.
Поляков, 2007-2009
Слайд 28Сортировка
Сортировка – это расстановка элементов массива в заданном порядке (по
возрастанию, убыванию, последней цифре, сумме делителей, …).
Задача: переставить элементы
массива в порядке возрастания.
Алгоритмы:
простые и понятные, но неэффективные для больших массивов
метод пузырька
метод выбора
сложные, но эффективные
«быстрая сортировка» (Quick Sort)
сортировка «кучей» (Heap Sort)
сортировка слиянием
пирамидальная сортировка
сложность O(N2)
сложность O(N·logN)
Слайд 29Метод пузырька
Идея – пузырек воздуха в стакане воды поднимается со
дна вверх.
Для массивов – самый маленький («легкий») элемент перемещается
вверх («всплывает»).
начиная снизу, сравниваем два соседних элемента; если они стоят «неправильно», меняем их местами
за 1 проход по массиву один элемент (самый маленький) становится на свое место
1-ый проход
2-ой проход
3-ий проход
Для сортировки массива из N элементов нужен
N-1 проход (достаточно поставить на свои места N-1 элементов).
Слайд 30Программа (1-ый проход)
сравниваются пары
A[N-2] и A[N-1],
A[N-3] и
A[N-2]
…
A[0] и A[1]
A[j] и A[j+1]
for( j =
N-2; j >= 0 ; j-- )
if ( A[j] > A[j+1] ) {
c = A[j];
A[j] = A[j+1];
A[j+1] = c;
}
0
Слайд 31Программа (следующие проходы)
2-ой проход
for ( j = N-2; j >=
1 ; j-- )
if ( A[j] > A[j+1] )
{
c = A[j];
A[j] = A[j+1];
A[j+1] = c;
}
1
(i+1)-ый проход
for ( j = N-2; j >= i ; j-- )
...
i
Слайд 32Программа
main()
{
const int N = 10;
int A[N], i, j,
c;
// заполнить массив
// вывести исходный массив
for (i = 0; i < N-1; i ++){
for (j = N-2; j >= i ; j --)
if ( A[j] > A[j+1] ) {
с = A[j];
A[j] = A[j+1];
A[j+1] = с;
}
}
// вывести полученный массив
}
элементы выше A[i] уже поставлены
i
меняем A[j] и A[j+1]
Слайд 33Метод пузырька с флажком
Идея – если при выполнении метода пузырька
не было обменов, массив уже отсортирован и остальные проходы не
нужны.
Реализация: переменная-флаг, показывающая, был ли обмен; если она равна 0, то выход.
do {
flag = 0; // сбросить флаг
for (j = N-2; j >= 0; j --)
if ( A[j] > A[j+1] ) {
с = A[j];
A[j] = A[j+1];
A[j+1] = с;
flag = 1; // поднять флаг
}
}
while ( flag ); // выход при flag = 0
flag = 0;
flag = 1;
( flag );
int flag;
Слайд 34Метод пузырька с флажком
i = 0;
do {
flag = 0;
// сбросить флаг
for ( j = N-2; j >=
i ; j -- )
if ( A[j] > A[j+1] ) {
с = A[j];
A[j] = A[j+1];
A[j+1] = с;
flag = 1; // поднять флаг
}
i ++;
}
while ( flag ); // выход при flag = 0
i = 0;
i
i ++;
Слайд 35Метод выбора
Идея:
найти минимальный элемент и поставить на первое место (поменять
местами с A[0])
из оставшихся найти минимальный элемент и поставить на
второе место (поменять местами с A[1]), и т.д.
Слайд 36Метод выбора
N
for( i = 0; i < N-1 ; i
++ ) {
nMin = i ;
for ( j
= i+1; j < N; j ++)
if( A[j] < A[nMin] ) nMin = j;
if( nMin != i ) {
c = A[i];
A[i] = A[nMin];
A[nMin] = c;
}
}
N-1
нужно N-1 проходов
поиск минимального от A[i] до A[N-1]
если нужно, переставляем
i+1
i
Слайд 37Задания
«4»: Заполнить массив из 10 элементов случайными числами в интервале
[0..100] и отсортировать его по последней цифре.
Пример:
Исходный
массив:
14 25 13 30 76 58 32 11 41 97
Результат:
30 11 41 32 13 14 25 76 97 58
«5»: Заполнить массив из 10 элементов случайными числами в интервале [0..100] и отсортировать первую половину по возрастанию, а вторую – по убыванию.
Пример:
Исходный массив:
14 25 13 30 76 58 32 11 41 97
Результат:
13 14 25 30 76 97 58 41 32 11
Слайд 38Формирование массива по условию
Задача – найти в массиве элементы, удовлетворяющие
некоторому условию (например, отрицательные), и скопировать их в другой массив.
Примитивное решение:
const int N = 5;
int A[N], B[N];
// здесь заполнить массив A
for( i = 0; i < N; i ++ )
if( A[i] < 0 ) B[i] = A[i];
A
B
выбранные элементы не рядом, не в начале массива
непонятно, как с ними работать
Слайд 39Формирование массива по условию
Решение: ввести счетчик найденных элементов count, очередной
элемент ставится на место B[count].
int A[N], B[N], count = 0;
//
здесь заполнить массив A
for( i = 0; i < N; i ++ )
if( A[i] < 0 ) {
B[count] = A[i];
count ++;
}
// вывод массива B
for( i = 0; i < count; i ++ )
printf("%d\n", B[i]);
A
B
count
Слайд 40Задания
«4»: Заполнить массив случайными числами и отобрать в другой массив
все числа, у которых вторая с конца цифра (число десятков)
– ноль.
Пример:
Исходный массив:
40 105 203 1 14
Результат:
105 203 1
«5»: Заполнить массив случайными числами и выделить в другой массив все числа, которые встречаются более
одного раза.
Пример:
Исходный массив:
4 1 2 1 11 2 34
Результат:
1 2
Слайд 41Программирование
на языке Си
Часть II
Тема 5. Поиск в массиве
©
К.Ю. Поляков, 2007-2009
Слайд 42Поиск в массиве
Задача – найти в массиве элемент, равный X,
или установить, что его нет.
Решение: для произвольного массива: линейный
поиск (перебор)
недостаток: низкая скорость
Как ускорить? – заранее подготовить массив для поиска
как именно подготовить?
как использовать «подготовленный» массив?
Слайд 43Линейный поиск
nX = -1;
for ( i = 0; i
N; i ++)
if ( A[i] == X )
{
nX = i;
break; //выход из цикла
}
Улучшение: после того, как нашли X, выходим из цикла.
break;
nX = -1; // пока не нашли ...
for ( i = 0; i < N; i ++) // цикл по всем элементам
if ( A[i] == X ) // если нашли, то ...
nX = i; // ... запомнили номер
if (nX < 0) printf("Не нашли...")
else printf("A[%d]=%d", nX, X);
nX – номер нужного
элемента в массиве
Слайд 44Двоичный поиск
X = 7
X < 8
8
4
X > 4
6
X > 6
Выбрать
средний элемент A[c] и сравнить с X.
Если X = A[c],
нашли (выход).
Если X < A[c], искать дальше в первой половине.
Если X > A[c], искать дальше во второй половине.
Слайд 45Двоичный поиск
N-1
nX = -1;
L = 0; R
= N-1; // границы: ищем от A[0] до A[N-1]
while
( R >= L ){
c = (R + L) / 2;
if (X = = A[c]) {
nX = c;
break;
}
if (X < A[c]) R = c - 1;
if (X > A[c]) L = c + 1;
}
if (nX < 0) printf("Не нашли...");
else printf("A[%d]=%d", nX, X);
номер среднего элемента
если нашли …
выйти из цикла
сдвигаем границы
>
Слайд 47Задания
«4»: Написать программу, которая сортирует массив ПО УБЫВАНИЮ и ищет
в нем элемент, равный X (это число вводится с клавиатуры).
Использовать двоичный поиск.
«5»: Написать программу, которая считает среднее число шагов в двоичном поиске для массива из 32 элементов в интервале [0,100]. Для поиска использовать 1000 случайных чисел в этом же интервале.
Слайд 48Программирование
на языке Си
Часть II
Тема 6. Массивы в процедурах
и
функциях
© К.Ю. Поляков, 2007-2009
Слайд 49Массивы в процедурах
Задача: составить процедуру, которая переставляет элементы массива в
обратном порядке.
void Reverse ( int A[] , int N
)
{
int i, c;
for ( i = 0; i < N/2; i ++ ) {
c = A[i];
A[i] = A[N-1-i];
A[N-1-i] = c;
}
}
int A[]
параметр-массив
размер массива
Слайд 50Массивы как параметры процедур
Особенности:
при описании параметра-массива в заголовке функции его
размер не указывается (функция работает с массивами любого размера)
размер массива
надо передавать как отдельный параметр
в процедура передается адрес исходного массива: все изменения, сделанные в процедуре влияют на массив в основной программе
Слайд 51Массивы в процедурах
void Reverse ( int A[], int N )
{
...
}
main()
{
int A[10];
// здесь надо заполнить массив
Reverse
( A, 10 ); // весь массив
// Reverse ( A, 5 ); // первая половина
// Reverse ( A+5, 5 ); // вторая половина
}
A или &A[0]
это адрес начала массива в памяти
A+5 или &A[5]
Слайд 52Задания
«4»: Написать процедуру, которая сортирует массив по возрастанию, и показать
пример ее использования.
«5»: Написать процедуру, которая ставит в начало массива
все четные элементы, а конец – все нечетные.
Слайд 53Массивы в функциях
Задача: составить функцию, которая находит сумму элементов массива.
int Sum ( int A[], int N )
{
int i, sum
= 0;
for ( i = 0; i < N; i ++ )
sum += A[i];
return sum;
}
результат – целое число
int A[]
параметр-массив
размер массива
Слайд 54Массивы в процедурах и функциях
int Sum ( int A[], int
N )
{
...
}
main()
{
int A[10], sum, sum1, sum2;
// заполнить
массив
sum = Sum ( A, 10 ); // весь массив
sum1 = Sum ( A, 5 ); // первая половина
sum2 = Sum ( A+5, 5 ); // вторая половина
...
}
Слайд 55Задания
«4»: Написать функцию, которая находит максимальный элемент в массиве.
«5»: Написать
логическую функцию, которая определяет, верно ли, что среди элементов массива
есть два одинаковых. Если ответ «да», функция возвращает 1; если ответ «нет», то 0.
Подсказка: для отладки удобно использовать массив из 5 элементов, задаваемых вручную:
const int N = 5;
int A[N] = { 1, 2, 3, 3, 4 };