- •Тема 1. Основные этапы решения задач на эвм 5
- •Тема 2. Жизненный цикл программы. Критерии качества программы. 15
- •Тема 3. Схемы алгоритмов, данных, программ 29
- •Тема 1. Основные этапы решения задач на эвм Постановка задачи разработки программного обеспечения
- •Анализ формальной постановки задачи
- •Выбор или разработка математической модели и метода решения
- •Разработка алгоритма
- •Базовые структуры алгоритма
- •3.2. Цикл с постусловием.
- •Тема 2. Жизненный цикл программы. Критерии качества программы.
- •Техническое задание и спецификация программы
- •Разработка проекта программной системы
- •Программирование (кодирование) или программная реализация алгоритмов
- •Тестирование и отладка
- •Эксплуатация и сопровождение
- •Критерии качества программного обеспечения
- •Тема 3. Схемы алгоритмов, данных, программ
- •Символы данных
- •Отображает данные, вводимые в ручную, во время обработки с устройств любого типа (клавиатура, переключатели, кнопки, световое перо, полоски со штрих кодом и т.Д.).
- •Символы процесса
- •Символы линий
- •Специальные символы
- •Правила применения символов в схемах
- •Правила выполнения соединений
- •Специальные условные обозначения
- •Тема 4. Язык программирования высокого уровня Си Общие сведения о языке Си
- •Алфавит языка Си
- •Грамматика для описания языка, синтаксические диаграммы
- •Структура программы на языке Си
- •Void main() //функция main
- •Имена объектов в программе
- •Выражения, операции и приоритеты
- •Тема 5. Стандартные типы данных
- •Тема 6. Составные типы данных Данные регулярного типа (массивы)
- •Int b [n]; // вектор из 10 целых элементов
- •9 Strcpy(s1,&s2[k]); //копирует правую подстроку из s2 в s1
- •9 Strncpy(s1,&s[2],n); //копирует среднюю подстроку из s2 в s1
- •Void main() /*пример функции*/
- •If(strcmp(s, "пароль"))
- •If(!strсmp("quit", s)) break;
- •Данные комбинированного типа (структуры)
- •Int month;
- •Int year;
- •Перечисления
- •Объединения
- •Указатели
- •Void *addres;
- •Int arrey[25];
- •Тема 7. Представление основных управляющих структур программирования Оператор присваивания
- •Составной оператор
- •Оператор перехода Goto
- •Условный оператор If
- •Оператор выбора switch
- •Операторы цикла while, do – while, for
- •Int I,j,imax,jmax,imin,jmin;
- •Операторы прерывания циклов
- •If (!flag) printf("Отрицательных чисел нет"); Форматированный ввод данных
- •Форматированный вывод данных
- •Преобразование типов
- •Инициализация данных
- •Тема 8. Функции
- •Определение функций в языке Си
- •Int rus (unsigned char r)
- •Void change (int X, int y)
- •Void change (int *X, int *y)
- •Вызов функций в языке Си
- •Int *fun (intx,int *y);
- •Int main()
- •Рекурсивные функции
- •Int nodWhile (int m, int n)
- •Int nodWhile (int m, int n)
- •Int main()
- •Int fCalculated[nFib];
- •Int FibDinam (int n)
- •Int main()
- •Int Summa(int n, int a[100])
- •Int main()
- •Тема 9. Файлы
- •Int fseek(file *fp, long count, int access);
- •Int ferror(file *fp);
- •Int remove(char *file_name);
- •Void rewind(file *fp);
- •Int main()
- •Тема 10. Приемы программирования. Примеры алгоритмов Алгоритмы сортировки
- •Исходный массив
- •Void SortBubble (int count, int* pArr)
- •Исходный массив
- •Void SortSelect(int count, int* pArr)
- •Int i1,temp;
- •Int jmax;
- •Void SortInsert (int count, int* pArr)
- •Int temp, j;
- •Алгоритмы поиска
- •Int bfSearch(char *s, char *p)
- •Int bmtarr[255];
- •Int bmSearch(int startpos, char *s, char *p)
- •Int BinarySearch (int lb, int ub, int key, int* pArr)
- •Динамические структуры данных
- •Линейные списки
- •Int value; // значение элемента
- •Void PrintSearchList (list head, int val)
- •If (lfound) printf("Элемент в списке найден!");
- •Стек, очередь, дек
- •Int prior(char);
- •Void main(void)
- •Int k, point;
- •Int prior(char a)
- •Деревья
- •Int info; //информационное поле
- •Приложение 1. Стандартные библиотеки языка Си
- •Приложение 2. Примеры реализации алгоритмов
- •Int main()
- •Int arr[10]; // Массив arr из 10 целочисленных элементов
- •Int I; // Счетчик для циклов
- •Int main()
- •Int main()
- •Int main()
- •Int Temp;
- •Int CurrentYear, Diff, Day1, Day2, Month1, Month2, I, Visokos;
- •Int main()
- •InsertSort(d, max); // Сортируем массив b методом вставок
- •Int number;
- •Int main()
- •Не рекурсивный алгоритм решения задачи Ханойская башня.
- •Int main()
- •Рекурсивный алгоритм решения задачи Ханойская башня.
- •Void move(int I, int j, int d)
- •Void hanoy(int I, int j, int k, int d)
- •Int main()
- •Int Cubic(double *X,double a,double b,double c);
- •Int Cubic (double *X, double a, double b, double c)
- •Void lu_backsub (double **a, int n, int *indx, double *b)
- •Void lu_invert (double **a, int n, int *indx, double **inv, double *col)
- •Int BracketRoot (double x0, double *a, double *b, double d0, double di, double dmax, double (*fun)(double));
- •Int BracketRoot (double x0, double *a, double *b, double d0,
- •Int main()
- •Int expo, I;
- •If (expo & 1)
- •Int main()
- •Приложение 3. Лабораторные работы Лабораторная работа №1
- •Лабораторная работа №2
- •Лабораторная работа №3
- •Лабораторная работа №4
- •Лабораторная работа №5
- •Лабораторная работа №6
- •Лабораторная работа №7
- •Лабораторная работа №8
- •Лабораторная работа №9
- •Лабораторная работа №10
- •Лабораторная работа №11
- •Лабораторная работа №12
- •Список литературы
Int fCalculated[nFib];
Int FibDinam (int n)
{
if (FCalculated[n] != 0) return(FCalculated[n]);
else
{
if ((n == 1) || (n == 2)) return(1);
else
{
FCalculated[n]= FibDinam(n-1)+FibDinam(n-2);
return(FCalculated[n]);
}
}
}
Int main()
{
int i,n;
// очищаем массив результатов рекурсии
for(i=1;i<NFib;i++)
{
FCalculated[i] = 0;
}
FCalculated[1] = 1;
FCalculated[2] = 1;
printf("введите N:\n");
scanf("%d", &n);
printf("FibD[%d] = %d\n", n, FibDinam(n));
}
Отметим, что если оценивать сложность рекурсивного алгоритма с запоминанием результатов, то он все равно уступает по скорости обычному алгоритму с итерациями, который был рассмотрен ранее, так как сложность алгоритма с итерациями – линейна, т.е. при использовании этого алгоритма для вычисления n-го числа Фибоначчи потребуется n шагов. Это можно проверить на практике. Например, если на одном и том же компьютере выполнить при N=85 три алгоритма нахождения чисел Фибоначчи:
а) алгоритм с рекурсией (Fib);
б) алгоритм с рекурсией с запоминанием результатов (FibDinam);
с) алгоритм без рекурсии, с итерацией (FibCircle);
то получим следующие временные результаты вычислений (примерно):
а) несколько минут;
б) около секунды;
с) практически мгновенно, т.е. не более секунды.
Эти результаты демонстрируют особенности использования рекурсивных алгоритмов.
Примечание. При выполнении программ и вычислении времени их выполнения использовался компьютер: Intel® Core™ 2 Duo CPU 3 Ghz, 4ГБ ОЗУ.
Пример 32. Необходимо с помощью рекурсивной функции вычислить сумму элементов одномерного массива, который предварительно заполняется случайным образом с помощью стандартных функций генерации случайных чисел.
Int Summa(int n, int a[100])
{
if (n = 0) return(0);
else return(A[n] + Summa(n-1,A));
}
Int main()
{
int i,n;
int a[100];
printf("Количество элементов в массиве?\n");
scanf("%i", &n); //N<100
for(i=1;i<n;i++)
{
a[i] = -10 + rand();
printf("%d\n",a[i]);
}
printf("Сумма: %d\n", Summa(n,a));
}
Тема 9. Файлы
Файлом называют способ хранения информации на физическом устройстве. Файл это понятие, которое применимо ко всему от файла на диске до терминала.
В языке Си отсутствуют операторы для работы с файлами. Все необходимые действия выполняются с помощью функций, включенных в стандартную библиотеку. Они позволяют работать с различными устройствами, такими, как диски, принтер, коммуникационные каналы и т.д. Эти устройства сильно отличаются друг от друга. Однако файловая система преобразует их в единое абстрактное логическое устройство, называемое потоком.
В Си существует два типа потоков: текстовые (text) и двоичные (binary).
Текстовый поток - это последовательность символов. При передаче символов из потока на экран, часть из них не выводится (например, символ возврата каретки, перевода строки).
Двоичный поток - это последовательность байтов, которые однозначно соответствуют тому, что находится на внешнем устройстве.
Прежде чем читать или записывать информацию в файл, он должен быть открыт и тем самым связан с потоком. Это можно сделать с помощью библиотечной функции fopen(). Она берет внешнее представление файла (например, c:\my_file.txt) и связывает его с внутренним логическим именем, которое используется далее в программе. Логическое имя это указатель на требуемый файл. Его необходимо определить; делается это, например, так:
file *fp;
Здесь file имя типа, описанное в стандартном заголовочном файле stdio.h, fp указатель на файл. Обращение к функции fopen() в программе осуществляется выражением:
fp = fopen(<спецификация файла>, <способ использования файла>);
Спецификация файла (т.е. имя файла и путь к нему) может, например, иметь вид: «c:\\my_file.txt» для файла my_file.txt на диске C.
Способ использования файла задается символами, представленными в таблю13.
Таблица 13.
Способы использования файлов
Символ |
Описание способа использования |
r |
открыть существующий файл для чтения; |
w |
создать новый файл для записи (если файл с указанным именем существует, то он будет переписан); |
а |
дополнить файл (открыть существующий файл для записи информации, начиная с конца файла, или создать файл, если он не существует); |
r+ |
открыть существующий файл для чтения и записи; |
w+ |
создать новый файл для чтения и записи; |
a+ |
дополнить или создать файл с возможностью чтения и записи; |
rb |
открыть двоичный файл для чтения; |
wb |
создать двоичный файл для записи; |
аb |
дополнить двоичный файл; |
r+b |
открыть двоичный файл для чтения и записи; |
w+b |
создать двоичный файл для чтения и записи; |
а+b |
дополнить двоичный файл с предоставлением возможности чтения и записи; |
rt |
открыть текстовой файл для чтения; |
wt |
создать текстовый файл для записи; |
at |
дополнить текстовый файл; |
r+t |
открыть текстовой файл для чтения и записи; |
w+t |
создать текстовый файл для чтения и записи; |
a+t |
дополнить текстовый файл с предоставлением возможности записи и чтения. |
Если режим t или b не задан (например, r, w или а), то он определяется значением глобальной переменной _fmode. Если fmode=0_BINARY, то файлы открываются в двоичном режиме, а если _fmode=0_TEXT - в текстовом режиме. Константы 0_BINARY и 0_ТЕXТ определены в файле fcntl.h.
Строки вида r+b можно записывать и в другой форме: rb+.
Если в результате обращения к функции fopen() возникает ошибка, то она возвращает константу NULL.
Рекомендуется использовать следующий способ открытия файла:
if ((fp = fopen("c:\\my_file.txt", "rt")) == NULL)
{
puts("Открыть файл не удалось\n");
exit(1);
}
После окончания работы с файлом он должен быть закрыт. Это делается с помощью библиотечной функции fclose(). Она имеет следующий прототип:
int fclose(FILE *fp);
При успешном завершении операции функция fclose() возвращает значение нуль. Любое другое значение свидетельствует об ошибке.
Рассмотрим другие библиотечные функции, используемые для работы с файлами (все они описаны в файле stdio.h):
1. Функция putc() записывает символ в файл и имеет следующий прототип:
int putc(int с, FILE *fp);
Здесь fp указатель на файл, возвращенный функцией fopen(), с символ для записи (переменная с имеет тип int, но используется только младший байт). При успешном завершении putc() возвращает записанный символ, в противном случае возвращается константа EOF. Она определена в файле stdio.h и имеет значение -1.
2. Функция getc() читает символ из файла и имеет следующий прототип:
int getc(FILE *fp);
Здесь fp указатель на файл, возвращенный функцией fopen(). Эта функция возвращает прочитанный символ. Соответствующее значение имеет тип int, но старший байт равен нулю. Если достигнут конец файла, то getc() возвращает значение ЕОF.
3. Функция feof() определяет конец файла при чтении двоичных данных и имеет следующий прототип:
int feof(FILE *fp);
Здесь fp указатель на файл, возвращенный функцией fopen(). При достижении конца файла возвращается ненулевое значение, в противном случае возвращается 0.
4. Функция fputs() записывает строку символов в файл. Она отличается от функции puts() только тем, что в качестве второго параметра должен быть записан указатель на переменную файлового типа.
fputs("Ехаmple", fp);
При возникновении ошибки возвращается значение EOF.
5. Функция fgets() читает строку символов из файла. Она отличается от функции gets() тем, что в качестве второго параметра должно быть указано максимальное число вводимых символов плюс единица, а в качестве третьего указатель на переменную файлового типа. Строка считывается целиком, если ее длина не превышает указанного числа символов, в противном случае функция возвращает только заданное число символов.
fgets(string, n, fp);
Функция возвращает указатель на строку string при успешном завершении и константу NULL в случае ошибки либо достижения конца файла.
6. Функция fprintf() выполняет те же действия, что и функция printf(), но работает с файлом. Ее отличием является то, что в качестве первого параметра задается указатель на переменную файлового типа.
fprintf(fp, "%х",а);
7. Функция fscanf() выполняет те же действия, что и функция scanf(), но работает с файлом. Ее отличием является то, что в качестве первого параметра задается указатель на переменную файлового типа.
fscanf(fp, "%х", &a);
При достижении конца файла возвращается значение EOF.
8. Функция fseek() позволяет выполнять чтение и запись с произвольным доступом и имеет следующий прототип: