ОГЛАВЛЕНИЕ ПРЕДИСЛОВИЕ …………………………………………………………... 5 ГЛАВА 1. ВЫЧИСЛЕНИЕ ЗНАЧЕНИЙ ФУНКЦИЙ ………………... 7 1.1. Операторы циклов …………………………………………………. 7 1.2. Операторы ветвления ……………………………………………… 8 1.3. Алгоритмы, необходимые для написания программ ……………. 10 ГЛАВА 2. СУММИРОВАНИЕ РЯДОВ ……………………………….. 18 ГЛАВА 3. ПОЗИЦИОННАЯ ЗАПИСЬ ЧИСЛА …………………….. 24 ГЛАВА 4. ДЕЛИТЕЛИ ЦЕЛОГО ЧИСЛА …………………………… 30 ГЛАВА 5. СОРТИРОВКА ДАННЫХ …………………………………… 35 5.1. Сортировка вставкой ……………………………………………….. 35 5.2. Метод пузырька …………………………………………………… 36 5.3. Сортировка выбором ……………………………………………….. 38 5.4. Быстрая сортировка ………………………………………………. 41 ГЛАВА 6. РАБОТА С ФАЙЛАМИ. ПОСТРОЕНИЕ МАССИВОВ БЕЗ ПОВТОРЕНИЙ ……………………….. 46 6.1. Работа с файлами ………………………………………………….. 46 6.2. Построение массивов без повторений …………………………….. 48 ГЛАВА 7. ОБРАБОТКА ПОСЛЕДОВАТЕЛЬНОСТИ СИМВОЛОВ 55 7.1. Алгоритм выделения слова из строки ……………………………. 55 7.2. Выбор слов, подходящих под шаблон …………………….............. 56 7.3. Перевод прописных символов в строчные ………………………. 57 3 ГЛАВА 8. ПОБИТОВЫЕ ОПЕРАЦИИ ………………………………. 60 ГЛАВА 9. ПРЕОБРАЗОВАНИЕ И ПОСТРОЕНИЕ МАТРИЦ ……. 70 ГЛАВА 10. СТРУКТУРЫ ……………………………………………….. 86 ГЛАВА 11. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ ………….. 101 11.1. Односвязные списки …………………………………………….. 101 11.2. Очереди ……………………………………………………………. 107 11.3. Стеки ………………………………………………………………. 111 Список литературы ……………………………………………………….. 122 4 ПРЕДИСЛОВИЕ В настоящее время резко возрос интерес к программированию. Это связано с развитием и внедрением в повседневную жизнь информационных и коммуникационных технологий [2, 3, 5 – 12, 15, 37]. Все программы, например, компьютерная игра, служебная программа для архивации данных, обозреватель для работы в Интернете или операционная система Windows, написаны на одном или нескольких языках программирования. Сегодня в мире насчитывается около 400 таких языков, которые используются для создания программ, а также еще несколько тысяч языков, давно забытых, или не получивших широкой известности, иногда незаслуженно. К настоящему времени ситуация с использованием различных языков продолжает меняться. Однако для разработки наиболее сложных и высокоэффективных программ используют язык программирования С++ [13, 21 – 23, 27 – 36]. Язык программирования С++ был разработан Бьярном Страуструпом (Bjarne Stroustrup) [29] на основе языка Си [9]. Язык С++ является расширением языка Си, поэтому программы, созданные на языке Си, могут обрабатываться компилятором языка С++. Язык С++ является универсальным языком программирования, так как с его помощью можно решать широкий круг задач, выполняемых на ЭВМ. Язык С++ реализует объектно-ориентированный подход к программированию [14, 16 – 20, 23 – 25]. Он может быть и процедурноориентированным, и поддерживать параметрическое программирование. Программы, написанные на языке С++, по быстродействию сравнимы с программами, написанными на Ассемблере. С++ – это язык программирования высокого уровня. Поэтому программы, подготовленные на нем, более наглядны, и они легко переносимы с одного типа компьютера на другой. Материал учебного пособия может быть использован при изучении курсов: «Программирование», «Объектно-ориентированный анализ и программирование (С++)», «Языки и методы программирования», «Технология программирования и работа на ЭВМ», а также при написании курсовых и дипломных работ. Наряду с теоретическим материалом в пособии приведены примеры программ, иллюстрирующих наиболее интересные стороны рассматриваемых вопросов: вычисление значений функций, суммирование рядов, позиционная запись числа и делители целого числа, сортировка данных, построение массивов, работа с файлами, обработка последовательности символов, побитовые операции, преобразование и построение матриц, структуры, динамические структуры данных. В каждой главе учебного пособия приведены упражнения для самостоятельной работы студентов. Учебное пособие предназначено для студентов механикоматематического факультета ННГУ, обучающихся по направлению подготовки 080500 «Бизнес-информатика», 010100 «Математика», 010200 «Математика и компьютерные науки», 010400 «Прикладная математика и информатика», 010800 «Механика и математическое моделирование». Оно может быть использовано при изучении 5 языка С++ и студентами других факультетов ННГУ, изучающими объектноориентированные технологии. Авторы выражают искреннюю благодарность заведующему кафедрой «Электроника и сети ЭВМ» НГТУ, профессору В.Р. Милову, доценту кафедры численного и функционального анализа ННГУ, доценту Н.В. Кротову за ценные советы при рецензировании рукописи. Авторы выражают искреннюю благодарность за поддержку заместителю по очной форме обучения проректора по учебной работе, заведующей кафедрой прикладной статистики ННГУ, доценту Н.Р. Стронгиной, заведующему кафедрой математического моделирования экономических систем ННГУ, профессору Ю.А. Кузнецову, директору НИИ механики, заведующему кафедрой численного моделирования физико-механических процессов ННГУ, профессору Л.А. Игумнову и директору Института радиоэлектроники и информационных технологий НГТУ, действительному члену Международной академии информатизации, профессору В.Г. Баранову. 6 ГЛАВА 1. ВЫЧИСЛЕНИЕ ЗНАЧЕНИЙ ФУНКЦИЙ В отличие от таких языков программирования, как Алгол, Паскаль, Фортран и других, в которых делается различие между программами и подпрограммами, процедурами и функциями, в языке С++ и его предшественнике языке Си используются только функции. При программировании на языке С++ функция является основным понятием, без которого нельзя обойтись. Каждая программа на языке С++ – это совокупность функций. Каждая функция глобальная, т.е. при определенных условиях доступна в модуле либо во всех модулях программы. Каждую из этих функций нужно определить либо описать до еѐ использования в конкретном модуле программы. Программа должна обязательно включать единственную функцию main(), которая является главной функцией [24]. Функция main() обеспечивает создание точки входа в откомпилированную программу. Кроме этой функции в программе может быть любое количество пользовательских функций. Пользовательские функции прямо или опосредованно вызываются из функции main(). При написании функций часто используются операторы циклов. 1.1. Операторы циклов Операторы циклов применяются для организации многократно автоматически повторяющихся вычислений [1, 17, 32]. Любой цикл содержит тело цикла, то есть операторы, которые повторяются несколько раз, начальные установки, модификацию параметров цикла и проверку условия продолжения выполнения цикла. Один проход цикла называется итерацией. На каждой итерации выполняется проверка условия. Проверка условия может выполняться либо до тела цикла (цикл с предусловием), либо после тела цикла (цикл с постусловием). Цикл с предусловием имеет вид: while (выражение) {операторы тела цикла}; где выражение определяет условие повторения тела цикла. Выражение вычисляется перед каждой итерацией цикла и его тип должен быть арифметическим или приводимым к нему. Выполнение операторов тела цикла начинается с вычисления выражения. Если выражение истинно (true), то операторы тела цикл будут выполняться. Если же при первой проверке выражения оно будет равно false, то цикл не будет выполняться ни разу. Цикл с постусловием записывается в виде: do {операторы тела цикла} while (выражение); 7 В данном цикле сначала выполняются операторы тела цикла, то есть простой либо составной операторы, а затем вычисляется выражение. Тип выражения, как и в операторе цикла с предусловием, должен быть арифметическим. Если выражение истинно (true), то операторы тела цикла выполняются ещѐ раз. Цикл будет завершен, когда выражение будет равным false, либо в теле цикла будет выполнен какой-либо оператор передачи управления. В отличие от цикла с предусловием, в цикле с постусловием операторы тела цикла могут быть выполнены хотя бы один раз. Кроме указанных выше операторов циклов часто применяется цикл с параметрами. Он имеет следующий вид: for (инициализация; выражение; шаг) { операторы тела цикла } где инициализация – используется для объявления присвоения начального значения переменной цикла и присвоения начальных значений другим величинам, которые применяются в цикле. В этой части может быть использована операция «запятая» для задания нескольких операторов, выполняющихся последовательно один за другим. Инициализация осуществляется один раз в начале исполнения цикла. Выражение – определяет условие выполнения цикла. Цикл будет выполняться, если результат выражения, приведенный к типу bool, равен true. Цикл с параметром реализуется как цикл с предусловием. Шаг – предназначен для изменения переменной цикла. В этой части также может быть использована операция «запятая» для задания нескольких операторов. Следует отметить, что любую часть, находящуюся внутри круглых скобок оператора с параметрами for, можно опустить. Однако точки с запятой «;» необходимо оставить на своих местах. 1.2. Операторы ветвления Операторы ветвления используются в разветвленных алгоритмах и служат для выбора маршрута выполнения программы в зависимости от истинности или ложности некоторых условий [1, 17, 32]. Операторы ветвления называют ещѐ конструкциями принятия решений [1]. К операторам ветвления относятся следующие операторы: условные операторы if, if … else и операторпереключатель switch. Синтаксис условных операторов имеет вид [1]: if (выражение) оператор; 8 либо, если операторов, выполняемых при истинности выражения несколько, то if (выражение) { оператор 1; оператор 2; ………… оператор N; } В случае, когда необходимо сравнить выражение с некоторым значением, нужно использовать операции отношений. Например, if (выражение == значение) оператор; if (выражение != значение) оператор; if (выражение <= значение) оператор; Оператор if … else может иметь две ветви: if (выражение) { оператор 1; оператор 2; } else { оператор 3; оператор 4; } Здесь вторая ветвь является альтернативой. Оператор if … else допускает применение вложенных конструкций вида: if (выражение 1) оператор 1; else if (выражение 2) оператор 2; else if (выражение 3) оператор 3; else if (выражение 4) { оператор 4; ………… else if (выражение N) оператор N; else оператор по умолчанию; где последняя ветвь else оператор по умолчанию; является необязательной. Количество уровней вложенности операторов if может быть любым. Однако при количестве таких вложенных конструкций, больших четырѐх-пяти, программу становится трудно отлаживать [1]. 9 Когда в программе нужно выбрать один из многочисленных вариантов, бывает целесообразным применять оператор-переключатель switch. Этот оператор называется ещѐ оператором множественного выбора [1]. Синтаксис оператора-переключателя switch имеет вид: switch (выражение) { case метка 1: оператор 1; break; { case метка 2: оператор 2; break; ………… case метка N: оператор N; break; default: оператор; } //Выход из оператора switch В данном операторе выражение и метки должны иметь значения целого либо символьного типа. Выбирается тот вариант, метка которого совпадает со значением выражения. В случае, когда нет ни одного совпадения меток со значением выражения, выбирается метка default: . Эта метка является необязательной. 1.3. Алгоритмы, необходимые для написания программ Обратим внимание на то, что при написании программ необходимо иметь в виду следующие алгоритмы, которые встречаются и при вычислении значений функций. 1) Ограничение на входные данные приводит к необходимости проверки при их введении. Для этого можно использовать следующие циклы. а) цикл с предусловием while (условие) . . . . Условие должно принимать значение «истина» при неправильном вводе данных. Например, необходимо ввести натуральное число n. Это осуществляется следующим циклом с предусловием: cin >> n; while (n <= 0) { cout << ”Введите натуральное число “; cin >> n; } 10 б) цикл с постусловием do . . . while (условие). Условие должно принимать значение «истина» при неправильном вводе данных. Например, необходимо ввести натуральное число n. Это осуществляется следующим циклом с постусловием: do { cout << ”Введите натуральное число “; cin >> n; }while (n <= 0); 2) Следует помнить о необходимости проверки аргументов функций, если область определения функции отлична от всего пространства. 3) Еще один часто встречающийся алгоритм при вводе данных – необходимо ввести n элементов массива x[i], значения которого уникальны. Это можно осуществить с помощью следующего цикла с параметрами: for(i=0; i<n; i++) { cout << "Введите x("<<i+1<<") = "; cin >> x[i]; for(j=0 ; j<i; j++) if(x[i] == x[j]) //Если встретился такой же элемент, { //необходимо его ввести вновь, i--; //причем его индекс будет повторяться break; //до тех пор, пока значение не будет } //уникальным. } Листинг 1.1. Задана прямая линия ax+by+c=0, причем коэффициенты a и b не равны нулю (необходимо проверить при вводе). Определить, лежит ли точка с координатами (x0,y0) выше или ниже прямой. Вычислить y=ln(5+3 x) при x=d+hk, k=0, 1, 2, …, 10, если точка лежит выше прямой, и y=0, если точка лежит на прямой линии или ниже ее. Вывести на экран дисплея информацию, если функцию вычислить нельзя. //stdafx.h #pragma once #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <math.h> //Библиотека математических функций #include <tchar.h> 11 #include <iostream> using namespace std; //Использовать пространство имен std //L1_1.cpp #include “stdafx.h” int main( ) { setlocale(LC_CTYPE, “russian”); // Функции обработки символов double x,y,a,b,c; do //Контроль того, что a и b не равны нулю { cout << «Введите коэффициенты прямой a b c «; cin >> a >> b >> c; }while(a == 0 || b == 0); cout << «Введите начальную точку и шаг «; cin >> d >> h; cout << ‟\n‟; cout << « x y Результат\n\n»; cout.precision(5); //Вывод 5 значащих цифр for(i=0; i<=10; i++) { x=d+i*h; if(5+3*x <= 0) { cout.width(32); //Выводить в 32 позициях cout << «Функцию вычислить нельзя\n»; } else { y=log(5+3*x); if(a*x+b*y+c<0) { cout.width(4); //Выводить в 4 позициях cout << x; cout.width(8); //Выводить в 8 позициях cout << y; cout << « Точка лежит под прямой \n»; } else { cout.width(4); //Выводить в 4 позициях cout << x; cout.width(8); //Выводить в 8 позициях cout << 0; 12 cout << « Точка лежит над прямой \n»; } } } return 0; } Результат работы программы листинга 1.1 приведен на рис. 1.1: Рис. 1.1. Результат работы программы листинга 1.1 УПРАЖНЕНИЯ 1. Задана парабола y = ax2+bx+c. Определить, лежит ли точка с координатами (x0,y0) выше или ниже параболы. Вычислить y=logfx(3+x)3 при x= d+kh, k=0, 1, 2, …, 10; f, d, h – некоторые числа, если точка лежит выше параболы, и y=0, если точка ниже параболы или на ней. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 2. Задана окружность x2+y2=R2. Определить, лежит ли точка с координатами (x0,y0) внутри или вне окружности. Вычислить y= m sin( fx 1) при x= d+kh, k=0, 1, 2,…, 10; m, f, d, h – некоторые числа, если точка лежит вне окружности, и y=x, если точка лежит внутри окружности или на ней. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 3. Задана прямая линия ax+by+c=0, причем коэффициенты a и b не равны нулю. Определить, лежит ли точка с координатами (x0,y0) выше или ниже прямой. Вычислить y=|log3(1+fx)| при x=d+hk, k=0, 1, 2, …, 10; f, d, h – не13 которые числа, если точка лежит выше прямой, и y=0, если точка лежит на прямой линии или ниже прямой. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 4. Задана парабола y = ax2+bx+c. Определить, лежит ли точка с координатами (x0,y0) выше или ниже параболы. Вычислить y=|(f+mx2)S/2| при x= d+kh, k=0, 1, 2, …, 10; f, S, m, d, h – некоторые числа, если точка лежит выше параболы, и y=x, если точка ниже параболы или на ней. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 5. Определить, лежит ли точка с координатами (x0,y0) в первом квадранте. Вычислить y=lnm/2(1+x)3 при x= d+kh, k=0, 1, 2, …, 10; m, d, h – некоторые числа, если точка лежит в первом квадранте, и y=x2, если точка находится вне первого квадранта. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 6. Определить, лежит ли точка с координатами (x0,y0) между параболами y=x2+1 и y=x2-1. Вычислить y= x ax при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 7. Определить, лежит ли точка с координатами (x0,y0) между окружностями радиуса R и r, R >r, с центром в начале координат. Вычислить b 2 y= b sin( x a ) при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +x, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 8. Определить, лежит ли точка с координатами (x0,y0) внутри верхнего полукруга радиуса R с центром в начале координат, где R – константа. Вычис5 лить y b ax 3 3x при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 9. Определить, лежит ли точка с координатами (x0,y0) внутри квадрата с координатами вершин (a; a), (a; -a), (-a; -a), (-a; a), a – некоторая константа. Вычислить y= ln b x ax при x=d+kh, k=0, 1, 2, …, 10; a, b, d, h – неко- торые числа, если точка лежит в этой области, и y=x2 +x, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 10. Определить, лежит ли точка с координатами (x0,y0) внутри нижнего полукруга радиуса R с центром в начале координат, где R – константа. Вычис- 2 лить y b ax b 2 при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые 14 числа, если точка лежит в этой области, и y=0, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 11. Определить, лежит ли точка с координатами (x0,y0) внутри квадрата с координатами вершин (a; 0), (0; -a), (-a; 0), (0; a), где a – константа. Вычис- лить y= сx 2 3 при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 12. Определить, лежит ли точка с координатами (x0,y0) внутри квадрата с координатами вершин (a; a), (a; -a), (-a; -a), (-a; a), где a – константа. Вы2 b b 4 числить y= ln cx b при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=сx2 +bx, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 13. Определить, лежит ли точка с координатами (x0,y0) в третьем квадранте. b 2 Вычислить y= x sin ax при x= d+kh, k=0, 1, 2, …, 10; a,b, d, h – некоторые числа, если точка лежит в третьем квадранте, и y=x2, если точка вне третьего квадранта. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 14. Определить, лежит ли точка с координатами (x0,y0) вне квадрата с координатами вершин (a; a), (a; -a), (-a; -a), (-a; a), где a – константа. Вычис- b 2 3 лить y= log cx 1 при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=сx2 +bx, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 15. Определить, лежит ли точка с координатами (x0,y0) вне квадрата с координатами вершин (a; 0), (0; -a), (-a; 0), (0; a), где a – константа. Вычислить y= b sin(b cx 2 ) при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 16. Определить, лежит ли точка с координатами (x0,y0) вне верхнего полукруга радиуса R с центром в начале координат, где R – константа. Вычис3 лить y log ax (3 bx) при x=d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2+ax, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 15 17. Определить, лежит ли точка с координатами (x0,y0) внутри полосы |y|<с, 3 где c – константа. Вычислить y lg b (1 ax) при x=d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=xa, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 18. Определить, лежит ли точка с координатами (x0,y0) внутри полосы |x|<с, где c – константа. Вычислить y x 3 sin ax 4 при x=d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=xb+1, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 19. Определить, лежит ли точка с координатами (x0,y0) между окружностями радиусов R и r, где R >r, с центрами в начале координат. Вычислить b a b y= (ax) 4 3 при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +x, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 20. Задана парабола y = ax2+bx+c. Определить, лежит ли точка с координаf 2 f тами (x0,y0) выше или ниже параболы. Вычислить y= ln mx 2 при x= d+kh, k=0, 1, 2,…,10; f, m, d, h – некоторые числа, если точка лежит выше параболы, и y=x, если точка находится ниже параболы или на ней. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 21. Задана парабола y = ax2+bx+c. Определить, лежит ли точка с координа- cos fx 2 m тами (x0,y0) выше или ниже параболы. Вычислить y= при x= d+kh, k=0, 1, 2, …, 10; f, m, d, h – некоторые числа, если точка лежит выше параболы, и y=0, если точка находится ниже параболы или на ней. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 22. Определить, лежит ли точка с координатами (x0,y0) внутри квадрата с координатами вершин (a; 0), (0; -a), (-a; 0), (0; a), где a – константа. Вычисb лить y= log 5 5 cx при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 23. Определить, лежит ли точка с координатами (x0,y0) внутри верхнего полукруга радиуса R с центром в начале координат, где R – константа. Вы- b 2 числить y x sin( ax) при x= d+kh, k=0, 1, 2, …, 10; a, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2, если точка находится 2 16 вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 24. Определить, лежит ли точка с координатами (x0,y0) во втором квадранте. 3 Вычислить y= log ax (3 bx) при x= d+kh, k=0, 1, 2, …, 10; a,b, d, h – некоторые числа, если точка лежит в первом квадранте, и y=x2, если точка находится вне второго квадранта. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 25. Определить, лежит ли точка с координатами (x0,y0) внутри квадрата с координатами вершин (a; 0), (0; -a), (-a; 0), (0; a), где a – константа. Вычислить y= log c b cx при x=d+kh, k=0, 1, 2, …, 10; с, b, d, h – некоторые числа, если точка лежит в этой области, и y=x2 +2, если точка находится вне области. Вывести на экран дисплея информацию, если функцию вычислить нельзя. 17 ГЛАВА 2. СУММИРОВАНИЕ РЯДОВ Основной алгоритм при вычислении суммы ряда a i i – это к значению объекта, содержащего текущее значения суммы, добавляется значение текущего члена суммы, причем начальное значение суммы полагается равным нулю. Например, s=0; Цикл, где s+=a; // Начальное значение суммы ряда // a значение текущего члена ряда Следует отметить, что значение текущего члена ряда может вычисляться на каждом шаге цикла независимо от значения предыдущего члена суммы или x 2n нужно выявить зависимость ai =f(ai-1). Например, если a n , n=0, 1, …, то 2n! an =an-1x2/(2n-1)/2n. Для этого примера следует отметить ещѐ одну особенность: при n = 0 значение a0=1, так как 0!=1, то есть слагаемое a0 необходимо присвоить значению объекта s до выполнения цикла. При вычислении сумм могут быть сформулированы следующие задачи [26]. Задано явное выражение функции, представленной данным рядом. Например, ряд x 2n s= . n 0 2n! (2.1) f(x) = cos(x). (2.2) представляет функцию Задана точность приближения этой функции рядом s - это , то есть |f(x) – s| < . Необходимо выяснить, сколько членов ряда нужно просуммировать, чтобы была достигнута заданная точность. Проводя этот эксперимент необходимо помнить, что при малых значениях точности значение текущего слагаемого должно быть больше минимального допустимого значения данного типа. Провести исследование, как число суммируемых членов зависит от значения точности приближения функции. Второй вариант постановки задачи – это задать значение числа суммируемых членов ряда и оценить погрешность представления функции f(x) конечной суммой этого ряда. Листинг 2.1. Вычислить сумму ряда, заданного формулой (2.1), двумя способами и сравнить результат с функцией (2.2). 18 //L2_1.cpp #include <stdio.h> #include <math.h> //Библиотека математических функций #include <float.h> //Библиотека предельных значений вещественных значений #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int i,n,m,v; double s,a,delta,f,x; do { cout << "Введите число вычислений "; cin >> m; }while(m <= 0); cout << "Введите x "; cin >> x; f = cos(x); delta = 0.1; cout << " delta n \n"; for(i=0; i<m; i++) { n = 1; s = 1; a = 1; v = 1; while(fabs(s-f) >= delta && fabs(a) > DBL_MIN) { a = a*x*x/(2*n-1)/(2*n); v = -v; s+ = v*a; n++; } cout.width(7); cout << delta; cout.width(6); cout << n << '\n'; delta/ = 10; } do { 19 cout << "Введите предельное значение n "; cin >> m; }while(m < 0); cout << " delta n \n"; if(n = 0) { delta = fabs(f-s); cout.width(7); cout << delta; cout.width(6); cout << n << '\n'; } else { cout.precision(3); for(n=0; n <= m; n++) { s = 1; a = 1; v = 1; for(i=1; i<=n; i++) { a = a*x*x/(2*i-1)/(2*i); v = -v; s+ = v*a; } delta = fabs(f-s); cout.width(11); cout << delta; cout.width(6); cout << n << '\n'; } } return 0; } Результат выполнения программы листинга 2.1 представлен на рис. 2.1: 20 Рис. 2.1. Результат работы программы листинга 2.1 УПРАЖНЕНИЯ Выполнить упражнения двумя способами [26]: 1. Задана точность приближения этой функции рядом s это , то есть |f(x) – s| < . Необходимо выяснить, сколько членов ряда нужно просуммировать, чтобы была достигнута эта точность. Проводя этот эксперимент, необходимо помнить, что при малых значениях точности значение текущего слагаемого должно быть больше минимального допустимого значения данного типа или число суммируемых членов достигнет предельно допустимого значения. Провести исследование, как число суммируемых членов зависит от значения точности приближения функции. 2. Задать значение числа суммируемых членов и оценить погрешность представления функции f(x) конечной суммой этого ряда. 1. 1 n(n 1) , f ( x) 1. n 1 21 1 2. (2n 1)(2n 1) , 3. 2 n 1 n 0 4. n f ( x) 2. , (1) n 0 5. 1 n 1 , 2n 1 f ( x) e. n 0 (1) n 0 n 1 , n! 1 , (2n 1) n 1 n 1 1 , 8. (1) 2 n n 1 n 1 1 , 9. (1) 4 n n 1 2n n x , 10. (1) (2n)! n 0 x 2 n 1 n , 11. (1) (2n 1)! n 0 x 2 n 1 , 12. n 0 ( 2n 1)! x 2n , 13. n 0 ( 2n)! 7. f ( x) 2 3. n! , 6. f ( x) 1 2 . (1) x 2 n 1 , (2n 1) ( x 1) n , 15. n nx n 1 xn 16. , n 1 n f ( x) 4 . n 1 n 14. (1) n 0 f ( x) 1 e . f ( x) 2 12 . f ( x) 7 2 720 . f ( x) cos( x). f ( x) sin( x). f ( x) sh( x). f ( x) ch( x). f ( x) arctg( x); x 1. f ( x) ln( x). f ( x) ln(1 x); xn , f ( x) ln( x 1); 17. (1) n n 1 ( x 1) 2 n 1 , f ( x) lg ( x) 2 . 18. 2 n 1 n 0 ( 2n 1)( x 1) n 1 22 x 1. x 1. xn 19. , n 0 n! ( x ln a) n , 20. n ! n 0 n n 21. (1) x , f ( x) e x . f ( x) a x . f ( x) 1 (1 x) , x 1. n n 22. (1) (n 1) x , f ( x) 1 (1 x) 2 , x 1. n 23. x , f ( x) 1 (1 x) , x 2 n 1 , 24. 2 n 1 n 1 f ( x) n 0 n 0 x 1. n 0 n 25. (n 1) x , 1 (1 x) ln ; 2 (1 x) f ( x) 1 (1 x) 2 , n 0 23 x 1. x 1. ГЛАВА 3. ПОЗИЦИОННАЯ ЗАПИСЬ ЧИСЛА Натуральное число можно записать так: n n 1 21 0 , где i – цифра в i – ой позиции. При работе с натуральными числами основными являются два алгоритма [26]: выделение последней цифры; удаление этой цифры из числа. Используя операции получения остатка и частного от деления на 10, можно последовательно получить все цифры числа. Кроме того, при разработке алгоритмов используется представление числа через его цифры в виде суммы: n n 1 21 0 = n·10 + n-1·10 +…+2·10 + 1·10 + 0·10 . n n-1 2 1 0 (3.1) Листинг 3.1. Дано натуральное n. Заменить в этом числе порядок цифр на обратный. Новое число обозначить через nn. Выделяя последовательно цифры i числа n, как остаток от деления на 10, перенести их в новое число nn= nn·10+i. //L3_1.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n, nn; do { cout << "Введите натуральное число "; cin >> n; }while (n <= 0); nn = 0; while (n > 0) { nn = nn*10+n%10; n/ = 10; } cout << "Полученное число "<<nn<<'\n'; return 0; } Результат работы программы листинга 3.1 приведен на рис. 3.1: 24 Рис. 3.1. Результат работы программы листинга 3.1 Листинг 3.2. Дано натуральное число n. Удалить из записи этого числа цифры 5 и 0, оставив остальные в том же порядке, что и в исходном числе. Для этого воспользоваться записью числа в виде разложения с использованием цифр и степеней числа 10, представленного формулой (3.1). //L3_2.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n,nn,k = 1,c; do { cout << "Введите натуральное число "; cin >> n; }while (n <= 0); nn = 0; while (n > 0) { c = n%10; if(c!= 5 && c!= 0) { nn = nn+c*k; k* = 10; } n/ = 10; } cout << "Полученное число "<<nn<<'\n'; return 0; } На рис. 3.2 представлен результат выполнения программы листинга 3.2. 25 Рис. 3.2. Результат работы программы листинга 3.2 Листинг 3.3. Найти трехзначное натуральное число, сумма цифр которого равна заданному числу. Прежде всего, следует отметить, что сумма цифр не может превышать 27, так как 9+9+9=27. Кроме того, если предположить, что k, j и i –цифры, то заданное число равно k + j + i. //L3_3.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n,i,j,k; do { cout << "Введите натуральное число <= 27 "; cin >> n; }while (n <=0 && n > 27); for(i=0; i<=9; i++) for(j=0; j<9; j++) { k = n-i-j; if(k >= 1&& k <= 9) cout << k+j*10+i*100 << '\n'; } return 0; } Результат работы программы листинга 3.3 приведен на рис. 3.3: Рис. 3.3. Результат работы программы листинга 3.3 26 Листинг 3.4. Определить цифру в последовательности чисел. Например, определить n –ю цифру в последовательности Фибоначчи [4]: 1123581321… . Алгоритм заключается в определении диапазона числа, в котором находится эта позиция. Для этого определяется число позиций текущего числа и наращивается до тех пор, пока это значение меньше исходной позиции. Затем определяется число младших цифр, которые следует убрать из текущего числа, и определяется искомая цифра. //L3_4.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int tmp, n, l, dl, m, i1, i2, i3; do { cout << "Введите число n "; cin >> n; }while (n <= 0); i1 = 0; i2 = 1; l = 0; while (n > l) { dl = 0; m = i2; while (m > 0) //Определяет число { //позиций в i2 dl++; //текущем числе m / = 10; //Фибоначчи. } l+ = dl; i3 = i1 + i2; i1 = i2; i2 = i3; } tmp = l-k; while (tmp > 0) { i2 / = 10; tmp--; } 27 tmp = i1%10; cout << n<< "-ая цифра = " << tmp << endl; return 0; } На рис. 3.4 представлен результат выполнения программы листинга 3.4. Рис. 3.4. Результат работы программы листинга 3.4 УПРАЖНЕНИЯ 1. Среди всех четырехзначных цифр определить число тех, у которых все цифры различны. 2. Найти количество чѐтных цифр натурального числа N. 3. Найти все натуральные числа, не превосходящие заданного числа N, и делящиеся на каждую из своих цифр. 4. Найти все натуральные числа, не превосходящие заданного числа N, десятичная запись которых есть строго возрастающая или строго убывающая последовательность цифр. 5. Найти все пары двухзначных натуральных чисел M и N, таких, что значение произведения MN не изменится, если в числах изменить порядок цифр. Например, M =38 и N =83. 6. Найти все натуральные числа, не превосходящие заданного числа N, сумма квадратов цифр которых кратна 13. 7. Найти все четырехзначные числа KLMN , для которых справедливо KL MN K L M N . 8. Сложить все цифры какого-либо натурального числа, затем все цифры полученной суммы и так далее до тех пор, пока не получится цифра, которая называется корнем данного числа (например, число 34697, тогда 3+4+6+9+7=29, 2+9=11, 1+1=2). Найти корень заданного натурального числа. 9. Среди трехзначных натуральных чисел найти такие числа, у которых сумма цифр, сложенная с квадратом этой суммы, равна исходному числу. 10. Определить пятизначное число N такое, что шестизначные числа 1N и N1 связаны соотношением N1 =3 1N . 28 11. Определить трехзначное число, удовлетворяющее условию: удалив старшую цифру и умножив полученное число на 7, получаем исходное число. 12. Натуральное число N называется числом Армстронга, если сумма цифр, каждая из которых возведена в степень, равную числу цифр в N, равна исходному числу. Найти все числа Армстронга, заключенные между числами N1 и N2. 13. Найти все автоморфные числа в промежутке от N1 до N2. Автоморфным называется число, квадрат которого заканчивается этим же числом. Например, число 25 и его квадрат 625. 14. Найти натуральные числа-палиндромы в диапазоне от N1 до N2. Например, число 1246421 является палиндромом. 15. Определить k-ю цифру последовательности 123456789101112131415… , в которой подряд записаны все натуральные числа. 16. Определить k-ю цифру последовательности 1101001000010000… , в которой подряд записаны степени числа 10. 17. Определить k-ю цифру последовательности 1392781243729… , в которой подряд записаны степени числа 3. 18. Определить k-ю цифру последовательности 1491625364964… , в которой подряд записаны все квадраты натуральных чисел. 19. Определить k-ю цифру последовательности 182764125216343… , в которой подряд записаны все кубы натуральных чисел. 20. Проверить, является ли заданное число палиндромом. Если это не палиндром, то заменить порядок цифр на обратный и сложить с исходным числом. Если полученное число не является палиндромом, то операцию повторять до тех пор, пока не получится число-палиндром. Для натуральных числе в диапазоне от N1 до N2 определить максимальное число действий преобразования числа в палиндром. 21. Найти все трехзначные числа, которые при увеличении на 1 делятся на 2, при увеличении на 2 делятся на 3, при увеличении на 3 делятся на 4, а при увеличении на 4 делятся на 5. 22. Найти все трехзначные числа, квадраты которых оканчиваются исходным числом. 23. Найти все трехзначные числа, сумма цифр которого и само число кратны 7. 24. Из натурального числа удалить все цифры от 0 до 3, оставив прежним порядок остальных цифр. 25. Среди всех трехзначных чисел найти такие, что исходное число равно среднему арифметическому всех чисел (включаяя и исходное число). Число состоит из тех же цифр,т.е. 6 2 1 0 2 1 0 2 0 1 0 1 2 0 2 1 1 0 2 2 1 0 . 29 ГЛАВА 4. ДЕЛИТЕЛИ ЦЕЛОГО ЧИСЛА Для нахождения всех делителей некоторого натурального числа N, исключая 1 и само число, следует перебрать все натуральные значения от 2 до [N/2], так как в интервале от [N/2]+1 до N множителей нет [26]. Здесь [x] – целая часть числа x. Листинг 4.1. Определить все делителели некоторого натурального числа N, за исключением 1 и самого числа. //L4_1.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n,d; do { cout<<"Введите n "; cin>>n; }while (n<=0); for(d=2;d<=n/2;d++) { if(n%d==0) cout<<d<<" "; } cout<<endl; return 0; } //Цикл гарантирует //введение натурального //числа. //Нахождение делителей Результат работы программы листинга 4.1 приведен на рис. 4.1: Рис. 4.1. Результат работы программы листинга 4.1 Следует отметить, что можно искать делители среди натуральных чисел, не превышающих квадратный корень из исходного числа, а остальные делители получаются в результате деления этого числа на найденные делители, то есть цикл «Нахождение делителей» будет иметь следующий заголовок: 30 for(d=2; d*d<=n; d++) . В этом случае результат работы программы представлен на рис. 4.2. Рис. 4.2. Результат работы программы листинга 4.2 Листинг 4.2. Найти наибольший общий делитель (НОД) двух неотрицательных целых чисел m и n, используя алгоритм Евклида [4, 26]. Алгоритм Евклида основывается на том, что для двух чисел m и n, причем m n, НОД(m, n) = НОД(n,r), где r – остаток от деления m на n. Если n = 0, то НОД(m,0)= m. //L4_2.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n,m,r; do { // Цикл гарантирует // введение натуральных // чисел. cout<<"Введите натуральные числа m и n "; cin>>m>>n; }while (m <= 0 || n <= 0); if (m < n) { r=m; m=n; n=r; } while (n > 0) { r=m % n; m=n; n=r; } cout<<"Наибольший общий делитель "<<m<<endl; return 0; 31 } На рис. 4.3 представлен результат выполнения программы листинга 4.2. Рис. 4.3. Результат работы программы листинга 4.2 Листинг 4.3. Найти простые числа, не превышающие заданного натурального числа N [26]. Первые простые числа – это 2 и 3. Если введенное число совпадает с ними, то их следует напечатать. В остальных случаях следует проверить, имеет ли текущее число делители меньше кадратного корня из числа. Четные числа проверять нет необходимости, так как они всегда имеют делитель 2. //L4_3.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int N,d,k; do { //Цикл гарантирует //введение натурального //числа. cout<<"Введите натуральное число n "; cin>>N; }while (N<=0); if(N>=2) cout<<2<<" "; if(N>=3) cout<<3<<" "; k=5; while (k<=N) { for(d=2; d*d<k && k%d !=0; d++) ; if(d*d>k) //Число простое cout<<k<<" "; 32 k+=2; } cout<<endl; return 0; } Результат работы программы листинга 4.3 приведен на рис. 4.4: Рис. 4.4. Результат работы программы листинга 4.3 УПРАЖНЕНИЯ 1. Для натурального числа N найти сумму всех делителей, включая 1 и само число. 2. Для натурального числа N найти число четных делителей. 3. Для натурального числа N найти число всех делителей, исключая 1 и само число. 4. Для натурального числа N найти сумму всех нечетных делителей, включая 1 и само число (если оно нечетное). 5. Для натурального числа N найти сумму всех четных делителей, включая и само число (если оно четное). 6. Найти все натуральные числа из интервала от 1 до 200, у которых сумма делителей равна N. 7. Найти все натуральные числа из интервала от 1 до 200, у которых число делителей равно N. 8. Найти все натуральные числа из интервала от N 1 до N 2, у которых сумма делителей больше K. 9. Найти все натуральные числа из интервала от N 1 до N 2, у которых сумма делителей меньше или равна K. 10. Найти натуральное число в диапазоне от 1 до10 000 с максимальной суммой делителей. 11. Найти натуральное число в диапазоне от 1 до 10 000 с минимальной суммой делителей. 12. Найти натуральное число в диапазоне от 1 до 10 000 с максимальным числом делителей. 13. Найти количество делителей натурального числа N, больших K. 33 14. Даны целые числа p и q. Получить все делители числа q, взаимно простые с p. Числа называются взаимно простыми, если у них нет ощих делителей, кроме 1. Например, 15 и 8. 15. Получить все простые делители числа N. 16. Среди всех четырехзначных чисел найти все простые числа, у которых сумма двух старших цифр равна сумме двух младших цифр. 17. Найти наибольший обший делитель трех чисел НОД(N,M,K), используя соотношение НОД(N,M,K) = НОД(НОД(N,M),K). 18. Даны натуральные числа M и N. Получить все кратные им числа, меньшие MN. 19. Для натуральных чисел N и M найти наименьшее общее кратное, используя соотношение НОК(N,M)= NM / НОД(N,M). 20. Найти наибольший обший делитель n чисел НОД(N1,N2,…,Nk), используя соотношение: НОД(N1,N2,…,Nk) = НОД(НОД(N1,N2,…),Nk) = НОД(НОД(НОД(N1,N2,…,Nk-2), Nk-1) ,Nk) и так далее. 21. Найти все совершенные натуральные числа не превосходящие N. Совершенным называется число, равное сумме своих делителей, включая 1 и исключая само число. Например, 28=1+2+4+7+14. 22. Найти все совершенные натуральные числа из интервала от N 1 до N 2 . 23. Найти все простые множители числа N, причем каждый из них должен быть выведен столько раз, сколько он встречается в исходном числе. Например, N = 28 = 227. 24. Найти все простые множители числа N, причем каждый из них должен быть выведен один раз. Например, N = 28 2 7. 25. Найти все пары дружественных натуральных чисел из интервала от N 1 до N 2. Два числа называются дружественными, если каждое из них равно сумме делителей другого (само число в качестве делителя не рассматривается). 34 ГЛАВА 5. СОРТИРОВКА ДАННЫХ Сортировку данных можно осуществлять различными алгоритмами. Среди них наиболее часто применяются следующие методы [10]: сортировка вставкой, метод пузырька, сортировка выбором и быстрая сортировка. Рассмотрим эти методы подробнее. 5.1. Сортировка вставкой На каждом шаге алгоритма сортировки вставкой выбирается один из элементов входных данных и вставляется в нужную позицию в уже отсортированном списке до тех пор, пока набор входных данных не будет исчерпан. Метод выбора очередного элемента из исходного массива произволен. Можно использовать практически любой алгоритм выбора. Обычно с целью получения устойчивого алгоритма сортировки элементы вставляются по порядку их появления во входном массиве. Листинг 5.1. Программа демонстрирует метод сортировки вставкой массива из 10 целых элементов. //L5_1.cpp #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int A[10], n=10, i, j, key; for(i=0; i<n; i++) { cout<<"Введите А("<<i+1<<")="; cin>>A[i]; } cout<<"Исходный массив\n"; for(i=0; i<n; i++) cout<<A[i]<<" "; cout<<endl; for(i = 1; i<n; i++) { key = A[i]; j = i - 1; while (j >= 0 && A[j] > key) { A[j + 1] = A[j]; j = j - 1; 35 A[j + 1] = key; } } cout<<"Полученный массив\n"; for(i=0; i<n; i++) cout<<A[i]<<" "; cout<<endl; return 0; } Результат работы программы листинга 5.1 приведен на рис. 5.1: Рис. 5.1. Результат работы программы листинга 5.1 5.2. Метод пузырька Алгоритм сортировки методом пузырька состоит из повторяющихся проходов по сортируемому массиву. За каждый проход элементы последовательно сравниваются попарно и, если порядок в паре неверный, выполняется обмен элементов. Проходы по массиву повторяются N-1 раз или до тех пор, пока на очередном проходе не окажется, что обмены больше не нужны. Это означает, что массив отсортирован. При каждом проходе алгоритма по внутреннему циклу, очередной наибольший элемент массива ставится на своѐ место в конце массива рядом с предыдущим наибольшим элементом, а наименьший элемент перемещается на одну позицию к началу массива («всплывает» до нужной позиции как пузырѐк в воде, отсюда и название данного алгоритма). Листинг 5.2. Задан список студентов с указанием фамилии и номера группы. Упорядочить этот список по возрастанию номера группы, а внутри группы построить его в алфавитном порядке. 36 //L5_2.cpp #include <string.h> #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n, i,*grup, f, k=0, gtmp; char **name, *ntmp, fam[30]; do { cout<<"Введите число студентов "; cin>>n; }while(n<=0); name=new char*[n]; // Выделение памяти для указателей, // связанных с фамилией студентов. grup=new int[n]; // Выделение памяти под номера групп. for(i=0; i<n; i++) { cout<<"Введите фамилию "<<i+1<<"-го студента и его группу "; cin>>fam>>grup[i]; name[i]=strdup(fam); // Заполняется фамилия i-го студента } do { f=0; for(i=0; i<n-1-k; i++) //Сравнение по группам, а если они равны, сравнение фамилий: if(grup[i]>grup[i+1] || (grup[i]==grup[i+1] && strcmp(name[i],name[i+1])>0)) { ntmp=name[i]; name[i]=name[i+1]; name[i+1]=ntmp; gtmp=grup[i]; grup[i]=grup[i+1]; grup[i+1]=gtmp; f=1; } }while (f); cout<<"Полученный список\n"; setlocale(LC_CTYPE,".866"); //Установка страницы для правильного //вывода символов кириллицы. for(i=0; i<n; i++) { 37 cout.width(6); cout<<grup[i]<<" "; cout<<name[i]<<'\n'; //Выделение поля для вывода группы } return 0; } На рис. 5.2 представлен результат выполнения программы листинга 5.2. Рис. 5.2. Результат работы программы листинга 5.2 5.3. Сортировка выбором Алгоритм сортировки выбором состоит из трех шагов: 1. Находится номер минимального значения в текущем списке. 2. Производится обмен этого значения со значением первой, не отсортированной позиции (обмен не нужен, если минимальный элемент уже находится на данной позиции). 3. Сортируется «хвост» списка, исключив из рассмотрения уже отсортированные элементы. Для реализации устойчивости алгоритма необходимо на шаге 2 минимальный элемент непосредственно вставлять в первую, не отсортированную позицию, не меняя порядок остальных элементов. Листинг 5.3. Задан список студентов с указанием фамилии и номера группы (рис. 5.3). Упорядочить этот список по возрастанию номера группы, а внутри группы построить его в алфавитном порядке. 38 //L5_3.cpp #include <string.h> #include <iostream> using namespace std; int main() { setlocale(LC_CTYPE,"russian"); int n, i, j, *grup, jmax, gm; char **name, fam[30], *fm; fstream ff("input.txt"); ff>>n; name=new char*[n]; //Выделение памяти для указателей, связанных //с фамилией студентов. grup=new int[n]; //Выделение памяти под номера групп for(i=0;i<n;i++) { ff>>fam>>grup[i]; name[i]=strdup(fam); //Заполняется фамилия i-го студента } ff.close(); for(i=0;i<n-1;i++) { fm=name[i]; gm=grup[i]; jmax=i; for(j=i+1;j<n;j++) if(grup[j]<gm ||(grup[j]==gm && strcmp(name[j],fm)<0)) { fm=name[j]; gm=grup[j]; jmax=j; } name[jmax]=name[i]; name[i]=fm; grup[jmax]=grup[i]; grup[i]=gm; } cout<<"Полученный список\n"; for(i=0;i<n;i++) { cout.width(6); //Выделение поля для вывода группы cout<<grup[i]<<" "; cout<<name[i]<<'\n'; 39 } ff.open("input.txt", ios::app); ff<<"\nПолученный список\n"; for(i=0;i<n;i++) { ff.width(6); ff<<grup[i]<<" "; ff<<name[i]<<'\n'; } ff.close(); cin.get(); return 0; } Содержимое файла “input.txt” Рис. 5.3. Информация, находящаяся в файле «input.txt» Результат работы программы листинга 5.3 приведен на рис. 5.4: Рис. 5.4. Результат работы программы листинга 5.3 40 5.4. Быстрая сортировка Быстрая сортировка, хоть и была разработана более 40 лет назад, является наиболее широко применяемым и одним их самых эффективных алгоритмов сортировки. Метод основан на принципе «разделяй-и-властвуй». Общая схема быстрой сортировки такова: из массива выбирается некоторый опорный элемент a[i], запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные a[i], влево от него, а все ключи, большие, либо равные a[i] – вправо (рис. 5.5). Теперь массив состоит из двух подмножеств, причем левое подмножество меньше, либо равно правого: Рис. 5.5. Разделение массива на два подмассива Для каждого подмассива будем иметь: если в подмассиве более двух элементов, рекурсивно запускается для него та же процедура. В конце получится полностью отсортированная последовательность. Рассмотрим алгоритм быстрой сортировки подробнее. 1. На входе задаем массив a[0] ... a[N] и опорный элемент p, по которому будет производиться разделение. 2. Введем два указателя: i и j (рис. 5.6). В начале алгоритма они указывают, соответственно, на левый и правый концы последовательности. 3. Будем двигать указатель i с шагом в 1 элемент по направлению к концу массива, пока не будет найден элемент a[i] >= p. 4. Аналогичным образом начнем двигать указатель j от конца массива к началу, пока не будет найден a[j] <= p. 5. Если i <= j, меняем a[i] и a[j] местами и продолжаем двигать i, j по тем же правилам. 6. Повторяем шаг 3, пока i <= j. Рассмотрим работу процедуры быстрой сортировки для массива a[0]...a[6] и опорного элемента p = a[3] (рис. 5.6). 41 Рис. 5.6. Иллюстрация алгоритма быстрой сортировки Теперь массив разделен на две части: все элементы левой меньше либо равны p, все элементы правой – больше, либо равны p. Разделение завершено. Листинг 5.4. Задать исходный массив х[N]. Количество элементов массива N и значения элементов массива ввести с клавиатуры. Применяя алгоритм быстрой сортировки, отсортировать исходный массив в порядке возрастания его элементов. Вывести на экран дисплея исходный и отсортированный массивы. //L5_4.cpp #include <iostream> using namespace std; void qs(int* s_arr, int first, int last); // Прототип функции qs() int main() { setlocale(LC_CTYPE,"russian"); int i, n, *x; do { cout<<"Введите число элементов массива "; cin>>n; }while (n<=1); x=new int[n]; for(i=0; i<n; i++) { cout<<"Введите x("<<i+1<<")="; 42 cin>>x[i]; } cout<<"Исходный массив\n"; for(i=0; i<n; i++) cout<<x[i]<<" "; cout<<endl; qs(x,0,n-1); cout<<"Полученный массив\n"; for(i=0;i<n;i++) cout<<x[i]<<" "; cout<<endl; return 0; } void qs(int* s_arr, int first, int last) { int i = first, j = last, x = s_arr[(first + last) / 2]; do { while (s_arr[i] < x) i++; while (s_arr[j] > x) j--; if(i <= j) { if (i < j) swap(s_arr[i], s_arr[j]); i++; j--; } } while (i <= j); if (i < last) qs(s_arr, i, last); if (first < j) qs(s_arr, first, j); } На рис. 5.7 приведен результат выполнения программы листинга 5.4. 43 Рис. 5.7. Результат работы программы листинга 5.4 УПРАЖНЕНИЯ 1. Упорядочить массив из n числовых элементов методом пузырька по возрастанию. 2. Упорядочить массив из n числовых элементов методом пузырька по убыванию. 3. Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по убыванию. 4. Используя алгоритм сортировки вставкой, упорядочить массив из n числовых элементов по убыванию. 5. Используя алгоритм сортировки выбором, упорядочить массив из n числовых элементов по убыванию. 6. Используя алгоритм сортировки выбором, упорядочить массив из n числовых элементов по возрастанию. 7. Упорядочить четные элементы массива из n числовых элементов методом пузырька по возрастанию. 8. Упорядочить нечетные элементы массива из n числовых элементов методом пузырька по убыванию. 9. Упорядочить массив из n символов методом пузырька в алфавитном порядке. 10. Упорядочить массив из n символов методом быстрой сортировки в алфавитном порядке. 11. Упорядочить массив из n символов методом сортировки вставкой в алфавитном порядке. 12. Упорядочить массив из n числовых элементов методом пузырька по возрастанию числа их делителей. 44 13. Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по убыванию числа их делителей. 14. Используя алгоритм быстрой сортировки, упорядочить массив из n числовых элементов по возрастанию числа их делителей. 15. Задан список студентов с указанием их среднего балла за текущую сессию. Упорядочить список студентов по убыванию балла, а в случае равенства баллов, упорядочить список студентов в алфавитном порядке. 16. Задан список студентов с указанием числа их прогулов за текущий семестр. Упорядочить список студентов по убыванию числа прогулов, а в случае равенства прогулов, упорядочить его в алфавитном порядке. 17. Задан список сотрудников с указанием отдела, в котором они работают. Упорядочить список сотрудников по убыванию номера отдела, а в случае равенства номеров отделов, упорядочить его в алфавитном порядке. 18. Упорядочить массив из n элементов следующим образом: положительные элементы по возрастанию, а отрицательные – по убыванию. 19. Заданы два упорядоченных массива из n и m элементов. Построить массив размерностью n+m с той же упорядоченностью. 20. Заданы два упорядоченных массива из n и m элементов. Построить массив размерностью n+m с противоположной упорядоченностью. 21. Упорядочить массив из n элементов следующим образом: сначала положительные элементы по убыванию, а затем отрицательные элементы по возрастанию. 22. Задан список финалистов лыжного соревнования с указанием фамилии и результата в минутах. Упорядочить список по возрастанию результатов, а в случае равенства результатов, указать фамилии спортсменов в алфавитном порядке. 23. В налоговой инспекции составлен список налогоплательщиков с указанием фамилии и суммы уплаченного налога. Упорядочить список налогоплательщиков по убыванию заплаченной суммы, а в случае равенства сумм указать фамилии налогоплательщиков в алфавитном порядке. 24. В налоговой инспекции составлен список налогоплательщиков с указанием фамилии и суммы задолженности по налогам. Упорядочить список налогоплательщиков по возрастанию суммы, а в случае равенства сумм указать фамилии налогоплательщиков в алфавитном порядке. 25. Задан список сотрудников некоторой фирмы с указанием фамилии и суммы, заработанной за месяц. Упорядочить список сотрудников по убыванию заработанной суммы, а в случае равенства сумм упорядочить фамилии сотрудников в алфавитном порядке. 45 ГЛАВА 6. РАБОТА С ФАЙЛАМИ. ПОСТРОЕНИЕ МАССИВОВ БЕЗ ПОВТОРЕНИЙ 6.1. Работа с файлами Файл – это поименованная часть памяти диска, которая содержит некоторый набор записей [32]. В С++ средства для доступа к файлам объявлены в заголовочном файле fstream, который необходимо включить в программный код при работе с файлами. Для обозначения источника либо приемника данных применяется термин «поток». Потоки для работы с файлами создаются как объекты следующих классов: ofstream – для вывода (записи) данных в файл; ifstream – для ввода (чтения) данных из файла; fstream – для чтения и записи данных (двунаправленный обмен). Имя файла задается либо при создании объекта, либо при использовании метода open(). В качестве примера рассмотрим пример с двойной сортировкой (см. листинг 5.2), но информацию нужно получать из файла. Листинг 6.1. В текстовом файле «input.txt» записана следующая информация: число студентов, а затем идут парой фамилия и номер группы (рис. 6.1). Необходимо преобразовать этот список так, чтобы он оказался отсортированным по группам и внутри каждой группы в алфавитном порядке. Полученный список вывести на экран дисплея и записать в файл. //L6_1.cpp #include <string.h> #include <fstream> #include <iostream> using namespace std; int main( ) { setlocale(LC_CTYPE,"russian"); int n,i,*grup,f,k=0,gtmp; char**name,*ntmp,fam[30]; fstream ff("input.txt"); //Соэдание объекта ff и открытие файла ff>>n; name=new char*[n]; //Выделение памяти для указателей, //связанных с фамилией студентов . grup=new int[n]; //Выделение памяти под номера групп for(i=0;i<n;i++) { ff>>fam>>grup[i]; 46 name[i]=strdup(fam); //Заполняется фамилия i-го студента } ff.close(); //Закрытие файла . . . //См. листинг 5.2 ff.open("input.txt",ios::app); //Открытие файла для пополнения ff<<"\nПолученный список\n"; for(i=0;i<n;i++) { ff.width(6); ff<<grup[i]<<" "; ff<<name[i]<<'\n'; } ff.close(); //Закрытие файла return 0; } Содержимое файла “input.txt” Рис. 6.1. Информация, находящаяся в файле «input.txt» На рис. 6.2 приведен результат выполнения программы листинга 6.1. Рис. 6.2. Результат работы программы листинга 6.1 47 6.2. Построение массивов без повторений Предположим, что в файле «input.txt» записана информация, содержащая количество студентов в списке, фамилию студента, название предмета и оценку по этому предмету. Фамилии студентов и названия предметов могут повторяться (рис. 6.3). Необходимо сформировать список студентов и вычислить общее количество пропусков занятий для каждого из них, а также общее число пропусков занятий по каждому предмету. Таким образом, для каждого студента и каждого предмета нужно суммировать число пропусков занятий. Содержимое файла “input.txt” Рис. 6.3. Информация, находящаяся в файле «input.txt» Листинг 6.2. Сформировать список из неповторяющихся фамилий и список из неповторяющихся предметов. При вводе проверять, если среди раннее введенных фамилий (рис. 6.3) вводимые фамилии и предметы. Если их нет, то вводится новая запись, а если они уже есть, то добавляется число прогулов в уже существующую запись. //L6_2.cpp #include <string.h> #include <fstream> #include <iostream> using namespace std; int main( ) { setlocale(LC_CTYPE,"russian"); int n,i,j,*nname,*nsubject,mn=0,ms=0,f,aut; 48 char**name,**subject,fam[30],sb[30]; fstream ff("input.txt"); ff>>n; //Читаем число записей name=new char*[n]; //Выделяем память под указатели //на фамилии. subject=new char*[n]; //Выделяем память под указатели //на названия предметов. nname=new int[n]; //Выделяем память под количество //пропусков длякаждого студента. nsubject=new int[n]; //Выделяем память под количество //под каждый предмет. for(i=0;i<n;i++) { ff>>fam; //Ввод фамилии студента ff>>sb; //Ввод предмета ff>>aut; //Ввод числа прогулов студента по этому //предмету. for(j=0;j<mn;j++) if(strcmp(name[j],fam)==0) break; if(j>=mn) { name[mn]=strdup(fam); nname[mn++]=aut; } else nname[j]+=aut; for(j=0;j<ms;j++) if(strcmp(subject[j],sb)==0) break; if(j>=ms) { subject[ms]=strdup(sb); nsubject[ms++]=aut; } else nsubject[j]+=aut; } ff.close(); cout<<"\nПолученные списки\nСТУДЕНТЫ\n\n"; for(i=0;i<mn;i++) { cout.width(10); cout<<name[i]; 49 cout.width(5); cout<<nname[i]<<'\n'; } cout<<"\nПРЕДМЕТЫ\n\n"; for(i=0;i<ms;i++) { cout.width(10); cout<<subject[i]; cout.width(5); cout<<nsubject[i]<<'\n'; } cout<<'\n'; ff.open("input.txt",ios::app); ff<<"\nПолученные списки\nСТУДЕНТЫ\n\n"; for(i=0;i<mn;i++) { ff.width(10); ff<<name[i]; ff.width(5); ff<<nname[i]<<'\n'; } ff<<"\nПРЕДМЕТЫ\n\n"; for(i=0;i<ms;i++) { ff.width(10); ff<<subject[i]; ff.width(5); ff<<nsubject[i]<<'\n'; } ff<<'\n'; ff.close(); return 0; } Результат работы программы листинга 6.2 приведен на рис. 6.4. 50 Рис. 6.4. Результат работы программы листинга 6.2 Листинг 6.3. В файле с именем «input.txt» содержится информация о количестве чисел и сами числа (рис. 6.5). Необходимо сформировать массив, не содержащий повторяющихся значений. Этот алгоритм был рассмотрен в главе 1. При работе с файлом он выглядит следующим образом. //L6_3.cpp #include <string.h> #include <fstream> #include <iostream> using namespace std; int main( ) { setlocale(LC_CTYPE,"russian"); int n,i,m=0,*x,tmp; fstream ff("input.txt"),f1; //Открытие файла "input.txt" ff>>n; //Чтение n x=new int[n]; //Запрос памяти под массив ff>>tmp; while(!ff.eof()) { for(i=0;i<m;i++) if(x[i]==tmp) break; if(i==m) //Если такого элемента еще не было, //дополняем его и увеличиваем индекс 51 //элемента массива. x[m++]=tmp; ff>>tmp; } ff.close(); //Закрытие файла //Открываем файл "input.txt" для пополнения f1.open("input.txt", ios::app); f1<<"\nПолученный вектор размерностью "<<m<<'\n'; for(i=0;i<m;i++) { f1.width(5); //Под выводимый объект выделяем 5 позиций f1.setf(ios::left); //В поле вывода значение прижать к левому краю f1<<x[i]; } f1.close(); //Закрытие файла return 0; } Содержимое файла "input.txt" Рис. 6.5. Информация, находящаяся в файле «input.txt» На рис. 6.6 представлен результат выполнения программы листинга 6.3. Рис. 6.6. Результат работы программы листинга 6.3 УПРАЖНЕНИЯ 1. Даны два массива целых чисел a и b, каждый их которых не повторяющихся элементов. Исходная информация записана Построить пересечение массивов a и b. 2. Даны два массива целых чисел a и b, каждый их которых не повторяющихся элементов. Исходная информация записана Построить объединение массивов a и b. 52 содержит в файле. содержит в файле. 3. Даны два массива целых чисел a и b, каждый их которых не содержит повторяющихся элементов. Исходная информация записана в файле. Построить симметричную разность массивов a и b. 4. Даны два массива целых чисел a и b, каждый их которых не содержит повторяющихся элементов. Исходная информация записана в файле. Построить дополнение массива a до массива b. 5. Задан произвольный массив. Исходная информация записана в файле. Построить массив только из значений, входящих в него один раз. 6. Задан произвольный массив. Исходная информация записана в файле. Построить массив только из значений, входящих в него более одного раза. 7. В файле задан список сотрудников с указанием фамилии, отдела, названия месяца и заработанной сотрудником за этот месяц заработнойя платы. Создать список отделов и вычислить общую сумму заработной платы сотрудников каждого отдела. 8. В файле задан список сотрудников с указанием фамилии, отдела, названия месяца и заработанной сотрудником за этот месяц заработной платы. Создать список сотрудников и вычислить общую сумму их заработной платы. 9. В файле задан список сотрудников с указанием фамилии, отдела, названия месяца и заработанной сотрудником за этот месяц заработной платы. Создать список отделов и вычислить общую сумму заработной платы за каждый месяц. 10. В файле задан список студентов с указанием предмета и оценки за экзамен. Составить список студентов с указанием их среднего балла за сессию. 11. В файле задан список студентов с указанием предмета и оценки за экзамен. Составить список предметов с указанием среднего балла по этому предмету в сессию. 12. Задан произвольный массив. Исходная информация записана в файле. Построить массив только из уникальных значений, с указанием, сколько раз элемент входит в исходный массив. 13. В файле задан список слов. Составить список уникальных слов с указанием, сколько раз они встречаются в исходном списке. 14. В файле задан список слов. Составить список слов, встречающихся в списке только один раз. 15. В файле задан список слов. Составить список слов, встречающихся в списке более одного раза. 16. В файле задан произвольный набор чисел. Создать массив неповторяющихся чисел с указанием о том, сколько раз число встречается в исходном массиве, и упорядочить числа по возрастанию частоты повторяемости. 17. В файле задан произвольный набор чисел. Создать массив неповторяющихся положительных чисел с указанием о том, сколько раз 53 число встречается в исходном массиве, и упорядочить числа по убыванию частоты повторяемости. 18. Даны два массива целых чисел a и b, каждый их которых не содержит повторяющихся элементов. Исходная информация записана в файле. Построить симметричную разность массивов a и b и упорядочить ее по убыванию. 19. Даны два массива целых чисел a и b, каждый их которых не содержит повторяющихся элементов. Исходная информация записана в файле. Построить пересечение массивов a и b, исключая отрицательные элементы. 20. В файле содержится список налоговой инспекции с указанием фамилии, года и суммы задолженностей за указанный год. Построить список должников с указанием их суммарной задолженности. 21. В файле содержится список налоговой инспекции с указанием фамилии, года и суммы задолженностей за указанный год. Построить список годов с указанием суммарной задолженности и определить год с максимальной задолженностью. 22. В файле задан список студентов с указанием предмета и оценки за экзамен. Составить список оценок с указанием их повторяемости за сессию. Определить наиболее часто встречающиея оценки. 23. В файле задан список сотрудников с указанием фамилии, отдела, названия месяца и заработанной сотрудником за этот месяц заработной платы. Создать список отделов и общего количества сотрудников в отделе. Определить отдел с максимальным числом сотрудников. 24. В файле задан текст. Определить частоту повторяемости входящих в текст латинских букв. Строчные и прописные буквы считать одинаковыми. 25. В файле задан текст. Определить частоту повторяемости входящих в текст цифр. 54 ГЛАВА 7. ОБРАБОТКА ПОСЛЕДОВАТЕЛЬНОСТИ СИМВОЛОВ При обработке последовательности символов наиболее часто используются следующие три алгоритма [26]: алгоритм выделения слова из строки; выбор слов, подходящих под шаблон; перевод прописных символов в строчные. 7.1. Алгоритм выделения слова из строки Алгоритм выделения слова из строки заключается в нахождении индекса, соответствующего началу слова (первый не пробельный символ), и индекса первого после окончания слова пробела или признака конца строки (символ „\0‟). Существование слова гарантируется отличной от нуля разностью между вторым и первым символом. Листинг 7.1. Определить число слов в тексте, записанном в файле. //L7_1.cpp #include <fstream> #include <iostream> using namespace std; int sum_word(char*st);//Прототип функции int main( ) { int sum=0; char s[81]; fstream f("input.txt"),f1; f.getline(s,80); //Читаем строку из файла while(!f.eof()) //Проверка достижения конца файла { sum+=sum_word(s); //Добавляем в сумму число //слов в текущей строке. f.getline(s,80); //Чистим следующую строку } f.close(); f1.open("input.txt",ios::app); //Открываем файл для пополнения f1<<"\n\nЧисло слов в тексте = "<<sum<<'\n'; f1.close(); return 0; } //Функция, определяющая число слов в строке: int sum_word(char *st) 55 { int s=0,b,e=0; while(st[e] != '\0') { //Пропускаем ведущие пробелы: while(st[e] != '\0' && st[e] == ' ') e++; b=e; //Пропускаем символы слова: while(st[e] != '\0' && st[e]!=' ') e++; if(e-b>0) //Слово выделено s++; } return s; } Результат работы программы листинга 7.1 приведен на рис. 7.1. В файле с именем “input.txt” содержится информация о количестве чисел и сами числа. Необходимо сформировать массив, не содержащий повторяющихся значений. Этот алгоритм был рассмотрен в главе 1. При работе с файлом он выглядит следующим образом. Число слов в тексте = 35 Рис. 7.1. Результат работы программы листинга 7.1 7.2. Выбор слов, подходящих под шаблон Выбор слов, подходящих под шаблон, является одним из наиболее применяемых алгоритмов. Например, задано слово, в котором встречаются символы „*‟ и „?‟. Такие слова будем называть шаблоном. Если в произвольном слове символы совпадают с символами шаблона, а вместо символа „*‟ можно использовать любую последовательность символов и вместо „?‟ – любой символ, то говорят, что слово подходит под шаблон. Например, пароход и паропровод подходят под шаблон паро*од. В первом случае под „*‟ скрывается последова56 тельность “х”, а во втором – “пров”. Под шаблон ?а?а подходят слова мама и папа. Листинг 7.2. Функция shablon ( ) проверяет, подходит ли слово под шаблон вида „*‟. //L7_2.cpp int shablon(char *word, char *sh) { int b, e, si=0, ls; while(sh[si] != '\0' && sh[si] != '*') si++; //Если символ ‘*’ отсутствует: if(si == strlen(sh) && strcmp(word, sh) == 0) return 1; if(si == strlen(sh) && strcmp(word, sh) != 0) return 0; //si – индекс символа ‘*’ в шаблоне. //Проверяем совпадение до ‘*’: for(b=0; b<si; b++) if(word[b] != sh[b]) break; if(b<si) //Символы не совпали return 0; else { //Проверяем совпадение после ‘*’: for(e=strlen(word)-1, ls = strlen(sh)-1; sh[ls] != '*'; e--, ls--) if(word[e] != sh[ls]) break; if(sh[ls] != '*') //Символы не совпали с символом ‘*’ return 0; else //Символы совпали до и после ‘*’ return 1; } 7.3. Перевод прописных символов в строчные При обработке последовательности символов также часто используется процедура – перевод символов верхнего регистра (прописные символы) в символы нижннего регистра (строчные символы). Листинг 7.3. Функция A_to_a ( ) переводит прописные символы в строчные. 57 //L7_3.cpp char A_to_a(char c) { if(c >='А' && c <= 'Я') c = c + 'а ' - 'А'; return c; } УПРАЖНЕНИЯ 1. В файле задан текст. Определить количество слов в тексте, которые начинаются и заканчиваются на одну и ту же букву. 2. В файле задан текст. Создать массив из уникальных слов в тексте, подходящих под заданный шаблон, включающий в себя символы “?”. 3. В файле задан текст. Определить количество слов в тексте, которые являются палиндромами. Слово называется палиндромом, если чтение слева направо и справа налево дает один и тот же результат. Строчные и прописные буквы не различать. 4. В файле задан текст. Создать массив из уникальных слов в тексте, подходящих под заданный шаблон, включающий в себя символы “*”. 5. В файле задан текст. Определить количество строк в тексте, которые являются палиндромами, если игнорировать пробелы. Строчные и прописные буквы не различать. 6. Используя функцию из раздела 7.3, которая переводит прописные буквы в строчные буквы, преобразовать текст, находящийся в файле. 7. Написать функцию, определяющую число гласных букв в слове. В тексте, записанном в файле, определить слово с максимальным числом гласных букв. 8. Написать функцию, определяющую число гласных букв в слове. В тексте, записанном в файле, определить слово с минимальным числом гласных букв. 9. В файле задан текст. Написать функцию, определяющую длину слова. С помощью этой функции определить количество слов в тексте, имеющих заданную длину. Найденные слова записать в выходной файл. 10. В файле задан текст. Написать функцию, определяющую длину слова. С помощью этой функции определить слова максимальной длины. Найденные слова записать в исходный файл. 11. В файле задан текст. Создать массив из слов этого текста, являющихся палиндромами, которые подходят под заданный шаблон, включающий в себя символы “?”. 12. В файле задан текст. Записать в новый файл четные строки исходного текста с указанием их номера в исходном тексте. 58 13. В файле задан текст. Написать функцию, определяющую длину слова. Применяя эту функцию, в выходной файл записать слова с указанием их длины. 14. В файле задан текст. Написать функцию, определяющую длину слова. С помощью этой функции определить, сколько слов в тексте имеют длину, больше заданной длины. Найденные слова записать в выходной файл. 15. В файле задан текст. Написать функцию, определяющую длину слова. С помощью этой функции определить, сколько слов в тексте имеют длину, меньше заданной длины. Найденные слова записать в выходной файл. 16. В файле задан текст. Определить строки, количество слов в которых совпадает с заданным числом. Найденные строки записать в выходной файл с указанием их номера в исходном файле. 17. В файле задан текст. Определить строки, количество слов в которых меньше заданного числа. Найденные строки записать в выходной файл с указанием их номера в исходном файле. 18. В файле задан текст. Определить строки, количество слов в которых больше заданного числа. Найденные строки записать в выходной файл с указанием их номера в исходном файле. 19. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „?‟. Определить число слов в тексте файла, которые подходят под заданный шаблон. 20. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „*‟. Определить число слов в тексте файла, которые подходят под заданный шаблон. 21. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „*‟. Найти слова в тексте файла, подходящие под заданный шаблон, и имеющие длину меньше заданной. 22. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „*‟. Найти слова в тексте файла, подходящие под заданный шаблон, и имеющие длину больше заданной. 23. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „?‟. Найти слова в тексте файла, подходящие под заданный шаблон, и имеющие длину меньше заданной. 24. В файле задан текст. Написать функцию, определяющую, подходит ли слово под заданный шаблон, содержащий символ „?‟. Найти слова в тексте файла, подходящие под заданный шаблон, и имеющие длину, больше заданной. 25. Написать функцию, определяющую длину слова. В тексте, записанном в файле, определить число слов с нечетным числом букв. Найденные слова с указанием их длины записать в выходной файл. 59 ГЛАВА 8. ПОБИТОВЫЕ ОПЕРАЦИИ Побитовые операции можно применять только к целочисленным операндам типа char, short, int, long. Они действуют на отдельные разряды двоичного представления чисел. В С++ определены следующие побитовые операции [32]: | & ^ ~ << >> – побитовое логическое ИЛИ; – побитовое логическое И; – побитовое исключающее ИЛИ; – побитовое логическое отрицание; – сдвиг влево; – сдвиг вправо. Результаты действия побитовых операций на операнды a и b представлены в табл. 8.1. Таблица 8.1 Побитовые операции a 1 0 1 0 b 1 1 0 0 a|b 1 1 1 0 a&b 1 0 0 0 a^b 0 1 1 0 ~a 0 1 0 1 Операция побитового логического отрицания (~) является унарной. В результате этой операции каждый бит, имеющий значение 1, становится равным 0 и наоборот. Данная операция называется также дополнением до единицы или инверсией. Результатом операции сдвига влево (<<) является левый операнд, сдвинутый влево на число позиций, которое указано в правом операнде. Освобождающиеся младшие разряды заполняются нулями [24, 25]. Данная операция может применяться для умножения на число, равное степени числа 2, в соответствии с правилом: x << n эквивалентно умножению х на 2 в степени n. Результатом операции сдвига вправо (>>) является левый операнд, сдвинутый вправо на число позиций, которое указано в правом операнде. Освобождающиеся старшие разряды заполняются нулями для переменных типа unsigned либо значением старшего (знакового) бита для данных другого типа [24, 25]. Данная операция может применяться для деления на число, равное степени числа 2, в соответствии с правилом: x >> n эквивалентно делению х на 2 в степени n. 60 Следует отметить, что перед выполнением побитовых операций нужно преобразовывать знаковые целые числа в беззнаковые целые. Листинг 8.1. Для печати содержимого памяти, отведенной под переменную типа unsigned int, может быть использована функция, в которой создается массив, и элементы массива заполняются следующим образом: Создается шаблон, содержащий единицу в старшем разряде. Проверяется побитовое умножение исходного числа на шаблон и в массив заносится символ „1‟, если это произведение отлично от нуля, и „0‟ – в противном случае. Затем шаблон сдвигается вправо на один бит. Для более легкого чтения информации после каждых 8 битов в массив заносится пробел. Операция повторяется до тех пор, пока шаблон отличен от нуля. //L8_1.cpp void print_bit(unsigned int x) { unsigned int sh=~0, i=0, k=0; sh=~(sh>>1); //Шаблон с 1 в старшем разряде char s[40]; while(sh>0) { s[i++]=sh&x?'1':'0'; k++; if(k==8) { s[i++]=' '; k=0; } sh>>=1; //Сдвиг шаблона в следующий разряд } s[i]='\0'; cout<<s<<'\n'; } Для успешной проверки данной функции следует вводить числа в шестнадцатеричном виде, так как каждая шестнадцатеричная цифра представляется четырьмя двоичными разрядами. Листинг 8.2. Программа печатает двоичное представление числа с использованием функции, приведенной в листинге 8.1. //L8_2.cpp #include <fstream> 61 #include <iostream> using namespace std; int main( ) { setlocale(LC_CTYPE,"russian"); unsigned int n; do { cout<<"Введите неотрицательное n "; cin>>hex>>n; //Ввол числа в шестнадцатеричной //системе счисления. }while(n<0); print_bit(n); //Печать числа в двоичной системе числения cin.get(); cin.get(); return 0; } Результат работы программы листинга 8.2 приведен на рис. 8.1. Рис. 8.1. Результат работы программы листинга 8.2 Листинг 8.3. В заданном числе инвертировать n битов с позиции k вправо. При вводе данных следует контролировать, чтобы позиция инвертируемого бита и количество инвертируемых битов не выходили за пределы числа. Для построения необходимо создать шаблон, содержащий 1 в инвертируемых позициях и 0 в остальных. //L8_3.cpp #include <stdio.h> #include <tchar.h> #include <iostream> using namespace std; void print_bit(unsigned int x); int main( ) { setlocale(LC_CTYPE,"russian"); 62 unsigned int x, n, k, m, sh, y; m=sizeof(unsigned int)*8; do { cout<<"Введите неотрицательное x "; cin>>hex>>x; }while(x<0); do { cout<<"Введите позицию k и число инвертируемых битов n "; cin>>dec>>k>>n; }while(!(k<=m&&n<=k)); print_bit(x); sh=~0; sh=((sh<<m-k)>>m-n)<<k-n; y=~(x&sh)&sh; x=x&(~sh)|y; print_bit(x); return 0; } void print_bit(unsigned int x) { unsigned int sh=~0,k=0,i=0; char s[40]; sh=~(sh>>1); cout<<'\n'; while(sh!=0) { s[i++]=(sh&x)?'1':'0'; k++; if(k%8==0) s[i++]=' '; sh=sh>>1; } s[i]='\0'; cout<<s<<'\n'; } На рис. 8.2 приведен результат выполнения программы листинга 8.3. 63 Рис. 8.2. Результат работы программы листинга 8.3 Побитовые операции можно использовать для укрупненного начертания слов. Укрупненное начертание какого-либо символа связано с заданием этого символа в виде таблицы [15]. Заполненные клетки таблицы образуют нужный контур символа. Содержимое такой таблицы можно закодировать с помощью 1 (клетка заполнена) и 0 (клетка не заполнена). Пусть такая таблица состоит из 7 × 5 элементов. Тогда для идентификации символа достаточно пяти семиразрядных двоичных чисел. Каждое из них будет кодировать один из пяти вертикальных слоев. Например, начертание символа “Н” кодируется следующими двоичными числами: 1111111 (первый и пятый вертикальные слои таблицы), 10 (второй, третий и четвертый слои таблицы). При этом переход от младших разрядов к старшим соответствует просмотру исходной таблицы сверху вниз (рис. 8.3). Младший разряд Старший разряд 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 Рис. 8.3. Кодирование начертания символа “Н” Для распечатки символа необходимо установить, какие двоичные цифры находятся в соответствующих разрядах всех пяти чисел: 0 – печатать пробел, 1 – печатать выбранный символ. Листинг 8.4. Вывести на экран дисплея укрупненное начертание слов: “ННГУ” и “МЕХМАТ”. //L8_4.cpp #include "stdafx.h" #include <stdio.h> 64 #include <locale> void _tmain() {setlocale (LC_ALL, "Russian"); int i, j, k, n; int B[6][5], D[6][5]; static char s[]="ННГУ", s2[]="МЕХМАТ"; char c, e; for (n=0; (c=s[n])!='\0'; n++) switch (c) { case 'Н': B[n][0]=B[n][4]=0177; B[n][1]=B[n][2]=B[n][3]=010; break; case 'Г': B[n][0]=0177; B[n][1]=B[n][2]=B[n][3]=01; B[n][4]=03; break; case 'У': B[n][0]=047; B[n][1]=B[n][2]=B[n][3]=0110; B[n][4]=077; break; } for (k=0; k<7; k++) { for (i=0; i<n; i++) { j=0; do {if (B[i][j] & 01) // k – разряд // i – буква // j - слой //Выделение k-го разряда каждого //из чисел, кодирующих букву. printf("%c", s[i]); else printf("%c", ' '); B[i][j]=B[i][j]>>1; j++; } while (j<5); printf("%s", " "); } printf ("\n"); } printf ("\n"); for (n=0; (e=s2[n])!='\0'; n++) 65 //Сдвиг вправо на одну позицию //всех разрядов числа. switch (e) { case 'М': D[n][0]=D[n][4]=0177; D[n][1]=D[n][3]=02; D[n][2]=04; break; case 'Е': D[n][0]=0177; D[n][1]=D[n][2]=D[n][3]=0111; D[n][4]=0101; break; case 'Х': D[n][0]=D[n][4]=0143; D[n][1]=D[n][3]=024; D[n][2]=010; break; case 'А': D[n][0]=D[n][4]=0176; D[n][1]=D[n][2]=D[n][3]=011; break; case 'Т': D[n][0]=D[n][1]=D[n][3]=D[n][4]=01; D[n][2]=0177; break; } for (k=0; k<7; k++) { for (i=0; i<n; i++) { j=0; do { if (D[i][j] & 01) //Выделение k-го разряда каждого //из чисел, кодирующих букву. printf("%c", s2[i]); else printf("%c", ' '); D[i][j] = D[i][j] >> 1; //Сдвиг вправо на одну позицию //всех разрядов числа. j++; } while (j<5); printf("%s", " "); } printf ("\n"); } printf ("\n"); 66 } Результат выполнения программы листинга 8.4 приведен на рис. 8.4. Рис. 8.4. Результат работы программы листинга 8.4 УПРАЖНЕНИЯ 1. Написать функцию, заменяющую n правых битов числа x на n правых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 2. Написать функцию, заменяющую n левых битов числа x на n правых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 3. Написать функцию, заменяющую n правых битов числа x на n правых инвертированных битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 4. Написать функцию, которая циклически перемещает n правых битов числа х в старшие биты, не меняя их порядка. Провести вычисление для заданного числа x и заданного количества правых битов n. Результат записать в файл. 5. Написать функцию, заменяющую n левых битов числа x на n правых битов этого же числа. Провести вычисление для заданного числа x и заданного количества левых битов n. Результат записать в файл. 6. Написать функцию, заменяющую n левых битов числа x на инвертированные n левых битов этого числа. Провести вычисление для заданного числа x и заданного количества левых битов n. Результат записать в файл. 67 7. Написать функцию, заменяющую n левых битов числа x на n левых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 8. Написать функцию, заменяющую n битов с позиции p числа x на n правых инвертированных битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 9. Написать функцию, заменяющую n левых битов числа x на n правых инвертированных битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 10. Написать функцию, которая циклически перемещает n левых битов числа х в младшие биты, не меняя их порядка. Провести вычисление для заданного числа x и заданного количества правых битов n. Результат записать в файл. 11. Написать функцию, заменяющую n левых битов числа x на инвертированные n правых битов этого числа. Провести вычисление для заданного числа x и заданного количества левых битов n. Результат записать в файл. 12. Написать функцию, заменяющую n правых битов числа x на инвертированные n правых битов этого числа. Провести вычисление для заданного числа x и заданного количества правых битов n. Результат записать в файл. 13. Написать функцию, определяющую количество единиц в двоичном представлении целого числа. Провести вычисление для заданного числа х. Результат записать в файл. 14. Написать функцию, определяющую разность между количеством нулей и единиц в двоичном представлении целого числа. Провести вычисление для заданного числа х. Результат записать в файл. 15. Написать функцию, заменяющую n битов с позиции p числа x на n правых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 16. Написать функцию, заменяющую n битов с позиции p числа x на n левых инвертированных битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 17. Написать функцию, заменяющую n битов с позиции p числа x на инвертированные. Провести вычисление для заданного числа x и заданного количества битов n. Результат записать в файл. 18. Написать функцию, определяющую количество нулей в двоичном представлении целого числа. Провести вычисление для заданного числа х. Результат записать в файл. 19. Написать функцию, заменяющую n битов с позиции p числа x на n левых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 20. Написать функцию, заменяющую n битов с позиции p числа x на n правых битов числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 68 21. Написать функцию, определяющую количество битов, значение которых в двоичном представлении чисел x и y совпадают. Провести вычисление для заданных чисел x и y. Результат записать в файл. 22. Написать функцию, определяющую количество битов, значение которых в двоичном представлении чисел x и y не совпадают. Провести вычисление для заданных чисел x и y. Результат записать в файл. 23. Написать функцию, определяющую разность между количеством единиц в двоичном представлении чисел x и y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 24. Написать функцию, определяющую разность между количеством нулей в двоичном представлении чисел x и y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 25. Написать функцию, заменяющую n левых битов числа x на n битов с позиции p числа y. Провести вычисление для заданных чисел x и y. Результат записать в файл. 69 ГЛАВА 9. ПРЕОБРАЗОВАНИЕ И ПОСТРОЕНИЕ МАТРИЦ Матрица – это прямоугольная таблица, образованная из элементов некоторого множества и состоящая из n строк и m столбцов [16]: a11 a21 A a n1 a12 a1m a22 a2 m an 2 anm (9.1) Такая таблица называется прямоугольной матрицей размера (n×m) или (n ×m)-матрицей с элементами aij . Элемент aij расположен в i-й строке и j-м столбце. При n = m матрица называется квадратной, а число n – ее порядком. При работе с матрицами следует обратить внимание на то, определены или нет размеры матрицы до начала выполнения программы. Рассмотрим два случая выделения памяти под элементы матрицы. Размерность матрицы определена перед выполнением программы Если размерность матрицы задана заранее, например ее размерность равна 8, то используется описание: Тип имя_матрицы[8][8]; В этом случае происходит статическое выделение памяти, то есть память выделяется до выполнения программы. При объявлении указанного объекта создается указатель с именем имя_матрицы, выделяется место под 8 указателей типа *Тип и адрес первого байта становится значением переменной имя_матрицы. Каждый из 8 указателей имя_матрицы[i] связан с выделенной памятью под 8 объектов типа Тип и адрес первого байта каждой выделенной области становится значением соответствующего объекта имя_матрицы[i] [24, 32]. Действия операционной системы может быть схематически отображено следующим образом (рис. 9.1): 70 Рис. 9.1. Иллюстрация статического выделения памяти под элементы матрицы Размерность матрицы не определена перед выполнением программы Поскольку размеры матрицы не определены до начала выполнения программы, следует использовать динамическое выделение памяти под элементы матрицы, то есть выделение памяти во время выполнения программы. Если размерность матрицы заранее неизвестна, то для ее описания используется указатель типа указатель на *Тип. Тип ** имя_матрицы; В этом случае создается только переменная имя_матрицы типа Тип**. Когда определено число строк (n) и число столбцов (m) матрицы, с помощью операции new выделяется место под n переменных типа Тип*: имя_матрицы = new Тип*[n]; то есть создается массив имя_матрицы[i]. Затем, для каждого элемента имя_матрицы[i] с помощью той же операции new выделяется место под n элементов типа Тип. Окончательно это может быть оформлено в виде следующего фрагмента: Тип** имя_матрицы; имя_матрицы = new Тип*[n]; for(i=0; i<m; i++) имя_матрицы[i] = new Тип[m]; Иными словами, проводятся те операции, которые в первом случае выполняет операционная система. 71 При преобразовании и построении матриц целесообразно выполнять следующие действия: а) Размерность матрицы и значение ее элементов необходимо читать из файла, так как для ввода с клавиатуры это слишком большой объем информации. б) Печать матрицы следует оформить в виде отдельной функции, причем оформить шаблонную функцию для того, чтобы можно было печатать матрицы любого типа. В определении шаблона функций применяется служебное слово template. Для параметризации используется список формальных параметров, который заключается в угловые скобки < >. Каждый формальный параметр шаблона обозначается служебным словом class, за которым следует имя параметра (идентификатор). Каждый параметр обязательно должен присутствовать в заголовке функции. При обращении к функции формальные параметры заменяются фактическими параметрами соответствующего типа. Листинг 9.1. В программе из файла с именем “input.txt” читаются две матрицы размером 3 × 5. Одна из них вещественная, а другая целочисленная. Причем у вещественной матрицы оставляется только два знака после запятой с округлением. //L9_1.cpp #include «stdafx.h» //Файлы, помещенные в данный файл заголовка, будут //предварительно откомпилированы. #include <fstream> #include <iostream> using namespace std; //Прототип шаблонной функции можно записать в две строки: template <class pp> //Введение параметров шаблона void print_matrix(pp **a, int n, int m); int _tmain( ) //Компилятор создаст либо функцию main( ), либо функцию //wmain( ) в зависимости от установок UNICODE. { setlocale(LC_CTYPE,"russian"); int n,m,i,j; double **A; //Указатель, который будет связан // с матрицей А. ifstream ff("input.txt"); ff>>n>>m; A=new double*[n]; //Идентификация указателя А и запрос // памяти под n указателей типа double*. for(i=0; i<n; i++) A[i]=new double[m]; //Идентификация указателя А[i] и запрос 72 //памяти под m указателей типа double. for(i=0; i<n; i++) for(j=0; j<m; j++) ff>>A[i][j]; cout<<"Исходная матрица\n"; print_matrix(A,n,m); int **X; //Указатель, который будет связан с //матрицей X. X=new int*[n]; //Идентификация указателя X и запрос //памяти под n указателей типа int*. for(i=0; i<n; i++) X[i]=new int[m]; //Идентификация указателя X[i] и запрос // памяти под m указателей типа int. for(i=0;i<n;i++) for(j=0;j<m;j++) ff>>X[i][j]; ff.close(); cout<<"Исходная целочисленная матрица матрица\n"; print_matrix(X,n,m); cin.get(); return 0; } template <class pp> //Заголовок шаблонной функции void print_matrix(pp **a,int n,int m) //можно записать в две строки. { int i,j; for(i=0;i<n;i++) { for(j=0;j<m;j++) { cout.width(8); int y=int(a[i][j] * 1000); if(y % 10 > 5) y=y/10+1; else { if(y % 10 == 5 && y % 2 != 0) y=y/10+1; else y/=10; } cout<<double(y) / 100; } cout<<'\n'; 73 } } На рис. 9.2 представлен результат выполнения программы листинга 9.1. Рис. 9.2. Результат работы программы листинга 9.1 Листинг 9.2. Пусть задана матрица A размером n × n. Необходимо построить матрицу B размером n × n, причем элементы матрицы определяются следующим образом: по индексам i и j строится область , в которой bij max a kl . Область показана на рис. 9.3 [26]. Индексы k и l изменяются в k ,l этом случае в следующих пределах: k от 0 до i, а l от j – i + k до j + i - k, причем при проведении сравнения с элементом akl следует проверять, что l лежит в диапазоне от 0 до n-1. Исходные данные находятся в файле “input.txt”, представленном на рис. 9.4. l k i,j Рис. 9.3. Вид области для построения матрицы В 74 Содержимое файла “input.txt” Рис. 9.4. Исходные данные для построения матрицы В //L9_2.cpp #include <fstream> #include <iostream> using namespace std; double** bild_matr(double**, int); //Прототип функции bild_matr( ) void print_matr(double**, int); //Прототип функции print_matr( ) int main( ) { double **A, **B; int i, j, n; setlocale(LC_CTYPE, "russian"); ifstream fin("input.txt"); fin >> n; A=new double *[n]; for(i=0;i<n;i++) A[i]=new double[n]; for(i=0;i<n;i++) for(j=0;j<n;j++) fin>>A[i][j]; cout<<"Исходная матрица\n"; print_matr(A,n); B=bild_matr(A,n); cout<<"Полученная матрица\n"; print_matr(B,n); cin.get(); return 0; } void print_matr(double**A, int n) { 75 int i,j; for(i=0;i<n;i++) { for(j=0;j<n;j++) { cout.width(5); cout<<A[i][j]; } cout<<'\n'; } } double** bild_matr(double**A, int n) { int i, j, k, l; double **B; B=new double*[n]; for(i=0;i<n;i++) B[i]=new double[n]; for(i=0; i<n; i++) for(j=0; j<n; j++) { B[i][j]=A[i][j]; for(k=0; k<=i; k++) for(l=j-i+k;l<=j+i-k;l++) if(l>=0 && l<n && B[i][j]<A[k][l]) B[i][j]=A[k][l]; } return B; } Результат выполнения программы листинга 9.2 приведен на рис. 9.5. Рис. 9.5. Результат работы программы листинга 9.2 76 Листинг 9.3. Пусть задан массив из 64 целых чисел. Будем считать, что одномерный массив состоит из целых чисел от 1 до 64. Построить матрицу размером 8 × 8 из данного одномерного массива, вставляя элементы одномерного массива в матрицу согласно схеме (рис. 9.6) [26]. Рис. 9.6. Схема размещения элементов одномерного массива в матрице //L9_3.cpp #include <iostream> using namespace std; int main() { int A[8][8], C[64]; int i, j, k, l=0; //Переменная l принимает значение 0 при //движении по схеме на рис. 9.6 вниз и значение 1 //при движении вверх. for(i=0;i<64;i++) C[i]=i+1; for(i=0;i<=7;i++) { if(i%2!=0) for(k=0,j=7-i;k<=i;k++,j++) { A[k][j]=C[l]; l++; } else for(k=i,j=7;k>=0;k--,j--) { A[k][j]=C[l]; 77 l++; } } for(i=1;i<=7;i++) { if(i%2!=0) for(k=7,j=7-i;j>=0;k--,j--) { A[k][j]=C[l]; l++; } else for(k=i,j=0;k<=7;k++,j++) { A[k][j]=C[l]; l++; } } for(i=0; i<8; i++) { for(j=0; j<8; j++) { cout.width(4); cout<<A[i][j]; } cout<<'\n'; } return 0; } Результат выполнения программы листинга 9.3 приведен на рис. 9.7. Рис. 9.7. Результат работы программы листинга 9.3 78 Листинг 9.4. В программе создается квадратная единичная матрица, порядок которой вводится с клавиатуры. Память под элементы матрицы выделяется динамически во время выполнения программы. Динамически выделенная память освобождается оператором delete [24]. //L9_4.cpp #include "stdafx.h" #include <iostream> #include <locale> using namespace std; void _tmain() {setlocale (LC_ALL,"Russian"); int n; int i, j; cout<<"Введите порядок матрицы: \n"; cin>>n; float **matr; matr=new float *[n]; if(matr==NULL) {cout<<"\n Не создан динамический массив" ; return; } for(i=0; i<n; i++) {matr[i]=new float [n]; if(matr[i]==NULL) {cout<<"\n Не создан динамический массив" ; return; } for(j=0; j<n; j++) if(i!=j) matr[i][j]=0; else matr[i][j]=1; } for(i=0; i<n; i++) {cout<<"\n Строка "<<i+1<<":"; for(j=0; j<n; j++) cout<<'\t'<<matr[i][j]; } for(i=0; i<n; i++) delete matr[i]; delete [] matr; } 79 Результат выполнения программы листинга 9.4 представлен на рис. 9.8. Рис. 9.8. Результат работы программы листинга 9.4 Листинг 9.5. В программе создается матрица, элементы которой задаются случайным образом. Память под элементы матрицы выделяется динамически во время выполнения программы. Программа состоит из трех функций: str( ) – функция вычисления среднего значения по строкам матрицы, stlb( ) – функция вычисления среднего значения по столбцам матрицы и функция _tmain( ). //L9_5.cpp #include "stdafx.h" #include <stdio.h> #include <locale> #include <iostream> #include <stdlib.h> #include <conio.h> using namespace std; double* str (int** arr, int n, int m) { double* res = new double [n]; double k = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { k += arr[i][j]; } res[i] = k / m; k = 0; } return res; } double* stlb (int** arr, int n, int m) 80 { double* res = new double [m]; double k = 0; for (int j = 0; j < m; j++) { for (int i = 0; i < n; i++) { k += arr[i][j]; } res[j] = k / n; k = 0; } return res; } int _tmain() { setlocale(LC_ALL, "Russian"); int n, m; cout << "Введите количество строк: "; cin >> n; cout << "\n"; cout << "Введите количество столбцов: "; cin >> m; cout << "\n"; int** arr; arr = new int*[n]; for (int i = 0; i < n; i++) { arr[i] = new int[m]; } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { arr[i][j] = rand() % 10; } } cout<<"Матрица: \n"<<endl; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << arr[i][j]; cout << " "; 81 } cout << "\n"; } cout<<endl; double* sr_stroki = str(arr, n, m); cout << "Среднее значение по строкам: \n"<<endl; for (int i = 0; i < n; i++) { cout << sr_stroki[i] << " "; } cout << '\n'; cout<<endl; double* sr_stolb = stlb(arr, n, m); cout << "Среднее значение по столбцам: \n"<<endl; for (int i = 0; i < m; i++) { cout << sr_stolb[i] << " "; } cout << '\n'; return 0; } На рис. 9.9 представлен результат выполнения программы листинга 9.5. Рис. 9.9. Результат работы программы листинга 9.5 82 УПРАЖНЕНИЯ 1. В файле “input.txt” задана матрица А размером n × m. В первой строке файла указаны ее размеры (n и m), а в следующих строках файла – значе ния элементов матрицы по строкам. Построить вектор b размерности n, причем bi определяется как максимальное значение в i-ой строке матрицы. Исходную матрицу и полученный вектор записать в файл. 2. В файле “input.txt” задана матрица А размером n × m. В первой строке файла указаны ее размеры (n и m), а в следующих строках файла – значе ния элементов матрицы по строкам. Построить вектор b размерности n, причем bi определяется как сумма значений в i-ой строке матрицы. Исходную матрицу и полученный вектор записать в файл. 3. В файле “input.txt” задана квадратная матрица А размером n × n. В первой строке файла указан ее размер (n), а в следующих строках файла – значения элементов матрицы по строкам. Построить транспонированную матрицу. Исходную и транспонированную матрицы записать в файл. 4. В файле “input.txt” задана квадратная матрица А размером n × n и n мерный вектор b . В первой строке файла указан размер n, а в следующих строках файла – значения элементов матрицы по строкам и значе ние элементов T вектора b. Построить квадратичную форму v b Ab . 5. В файле “input.txt” задана квадратная матрица А размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значения элементов матрицы по строкам. Преобразовать матрицу таким образом, чтобы ее первый столбец был упорядочен по убыванию. 6. В файле “input.txt” задана квадратная матрица А размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значе ния элементов матрицы по строкам. Построить n мерный вектор b , компоненты которого определяются как максимальный элемент соответствующей строки. 7. В файле “input.txt” задана квадратная матрица А размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значения элементов матрицы по строкам. Построить матрицу B размером n × a kl . Вид области для n, причем элементы определяются как bij min k ,l построения матрицы В приведен на рис. 9.10 – 9.15 [26]. 83 Рис. 9.10 Рис. 9.11 Рис. 9.12 Рис. 9.13 Рис. 9.14 Рис. 9.15 8. В файле “input.txt” задана квадратная матрица А размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значения элементов матрицы по строкам. Построить матрицу B размером n × n, причем ее элементы определяются как среднее значение в области . Вид области для построения матрицы В приведен на рис. 1 – рис. 6. 9. В файле “input.txt” заданы квадратные матрицы А и В размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значения элементов матриц по строкам. Написать функцию, которая строит матрицу С=АВ. Полученную матрицу записать в конец файла “input.txt”. 84 10. В файле “input.txt” заданы квадратные матрицы А и В размером n × n. В первой строке файла указан размер n, а в следующих строках файла – значения элементов матриц по строкам. Написать функцию, которая строит матрицу С=А+В. Полученную матрицу записать в конец файла “input.txt”. 11. Дан одномерный массив целых чисел Р размерностью 64. Получить квадратную матрицу А размером 8 × 8, элементы которой являются числами массива Р, расположенный согласно схемам, представленным на рис. 7 и рис. 8 [26]. Рис. 9.16 Рис. 9.17 85 ГЛАВА 10. СТРУКТУРЫ Из базовых типов и типов, определенных программистом, можно формировать производные типы, к которым относятся указатели, массивы, структуры, объединения и функции. Базовые типы (int, float, …) считаются скалярными типами. Массивы и структуры являются агрегирующими типами, так как состоят из набора элементов. Массив состоит из однотипных элементов, а структуры могут содержать разнотипные элементы [24]. Структура – это объединение в единое целое множества поименованных элементов (компонентов) данных. В отличие от массива, в котором компоненты имеют один и тот же тип, компоненты структуры могут иметь различные типы. Формат объявления структурного типа: struct имя_структурного_типа { Определение_компонентов_структуры }; Здесь struct – спецификатор структурного типа; имя_структурного_типа – произвольно выбираемый идентификатор; Определение_компонентов_структуры – совокупность одного или более описаний объектов, каждый из которых служит прототипом для элементов структур вводимого структурного типа. Еще одну возможность введения структурного типа дает служебное слово typedef, позволяющее ввести собственное обозначение для любого определения типа. В случае структурного типа он может быть введен и поименован следующим образом: typedef struct { Определение_компонентов_структуры } имя_структурного_типа_1; Структурный тип, которому назначается имя с помощью typedef, может иметь имя и введенное обычным образом: typedef struct имя_структурного_типа { Определение_компонентов_структуры } имя_структурного_типа_1; В этом случае объекты можно вводить, используя как имя_структурного_типа, так и имя_структурного_типа_1. Структура используется для определения типов вводимых объектов также как и int, double и так далее, то есть под описание структуры память не выделяется. Выделение памяти происходит при объявлении объектов типа структура. Введение объектов происходит следующим образом: 86 имя_структурного_типа список_имен_объектов; В качестве примера иллюстрации выделения памяти рассмотрим структуру вида [24]: struct goods{ char* name; //Название long price; //Цена float percent; //Процент скидки char date[9]; //Дата в символьном формате }; Введем объект типа struct goods: struct goods coat; В табл. 10.1 приведено распределение памяти, выделяемой под объект coat. Таблица 10.1 Выделение памяти под объект coat Название полей Тип Байты name price percent date char* 4 long 4 float 4 char[9] 9 Инициализация объектов типа структуры может быть осуществлена при объявлении объектов. Например, struct goods cit={“Апельсины”, 56, 2.5, ”15.06.13”}; Сравнивая структуры с массивами, следует отметить одну особенность, связанную с операцией присваивания. Если заданы массивы одного и того же типа, то перенос значений из одного массива в другой возможен лишь с использованием оператора цикла. Например, float x[5], y[5]={1.0, 5.7, 4.0, -6.2, 7.1}; for(int i=0; i<sizeof(x) / zizeof(x[0]); i++) x[i]=y[i]; Стандарт языка Си разрешает присваивание структур. Например, если введен объект goods frut; 87 то при выполнении операции присваивания frut = cit; полям объекта frut будут присвоены значения полей объекта cit. Следует отметить, что поле name будет указывать на один и тот же адрес памяти. Доступ к полям структуры обеспечивается с помощью уточненных имен: Имя_объекта.имя_поля Листинг 10.1. В файле с именем "input.txt" задано количество студентов, список студентов с указанием фамилии и номера группы (рис. 10.1). Содержимое файла "input.txt". Рис. 10.1. Информация, находящаяся в файле «input.txt» Необходимо упорядочить список студентов по возрастанию номера группы, а внутри группы упорядочить их в алфавитном порядке. Для описания студента используется структура: struct spisok { char *fam; int group; }; //Фамилия студента //Номер группы студента Файл “stdafx.h” #pragma once #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <tchar.h> 88 #include <string.h> #include <fstream> #include <iostream> using namespace std; //L10_1.cpp #include "stdafx.h" struct spisok { char *fam; int group; }; //Структура для описания студентов void sort(spisok*f, int n); //Прототип функции sort() //Поле структуры //Поле структуры int _tmain( ) { ifstream fin("input.txt"); //Задание объекта для ввода и его идентификация ofstream fout("outout.txt") ;//Задание объекта для вывода и его идентификация int n ,i; char st[30]; spisok *f; fin>>n; //Чтение числа записей в списке f=new spisok[n]; //Формирование списка: for(i=0; i<n; i++) { fin>>st; f[i].fam=strdup(st); fin>>f[i].group; } sort(f,n); //Сортировка списка в заданном порядке //Вывод списка в файл "outout.txt": for(i=0; i<n; i++) { fout.width(20); fout<<f[i].fam; fout.width(5); fout<<f[i].group<<'\n';; } fout.close(); 89 return 0; } void sort(spisok*f, int n) { spisok v; int i, k=0, ff; do { ff=0; for(i=0; i<n-1-k; i++) { l=f[i].group > f[i+1].group||(f[i].group == f[i+1].group && strcmp(f[i].fam, f[i+1].fam)>0); if (l) { v=f[i]; f[i]=f[i+1]; f[i+1]=v; ff=1; } } k++; }while(ff); } Результат выполнения программы листинга 10.2 представлен на рис. 10.2. Содержимое файла "outout.txt" Рис. 10.2. Результат работы программы листинга 10.2 В случае, когда значение некоторого поля должно быть одинаковым для всех записей структуры, его следует объявить статическим. Статические компоненты не «дублируются» при создании новых объектов, то есть каждый ста90 тический компонент существует в единственном экземпляре. Доступ к статическому компоненту возможен лишь после его инициализации. Для инициализации используется следующая конструкция: тип имя_структуры :: имя_компонента инициализатор; Листинг 10.2. В программе описываются продукты, находящиеся на некоторой оптовой базе (рис. 10.3). В качестве статического компонента рассматривается торговая скидка. Содержимое файла "input.txt" Рис. 10.3. Информация, находящаяся в файле «input.txt» //L10_2.cpp #include <stdio.h> #include <string.h> #include <fstream> #include <iostream> using namespace std; typedef struct date { int dd,mm,yy; }; struct baza { char*name; float price; static int percent; date d; //Структура для описания даты // Структура для описания товара //Наименование товара //Цена //Торговая скидка //Дата поступления 91 }; void print_date(date); //Печать даты в формате dd.mm.yy int true_date(date); //Проверка правильности ввода даты void print_baza(baza); //Печать содержимого объекта baza int baza::percent=0; //Начальная инициализация компонента percent int main() { date d1; setlocale(LC_CTYPE,"russian"); baza *p; int n, i, v; ifstream fin("input.txt"); //Файл, описывающий содержимое базы char st[30]; fin >> n; fin>>v; //Введение значения торговой скидка baza::percent=v; //Присваивание этого значения p=new baza[n]; for(i=0;i<n;i++) { fin.get(); fin.getline(st,29); //Наименование товара p[i].name=strdup(st); fin>>p[i].price; //Цена товара do { fin>>d1.dd>>d1.mm>>d1.yy; if(!true_date(d1)) { cout<<"Дата введена неправильно!\n"; return 1; } }while(!true_date(d1)); p[i].d=d1; //Дата поступления товара } fin.close(); for(i=0;i<n;i++) //Печать содержимого базы { print_baza(p[i]); cout<<'\n'; } cout<<"\nВведите новую скидку "; cin>>v; //Ввод новой скидки baza::percent=v; cout<<"\n\n"; 92 for(i=0;i<n;i++) { print_baza(p[i]); cout<<'\n'; } //Печать содержимого базы return 0; } void print_date(date d) { char s[9]; s[8]='\0'; s[0]='0'+d.dd/10; s[1]='0'+d.dd%10; s[2]='.'; s[3]='0'+d.mm/10; s[4]='0'+d.mm%10; s[5]='.'; int y=d.yy%100; s[6]='0'+y/10; s[7]='0'+y%10; cout<<s; } int true_date(date d) { int dm[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int v; if((d.yy/4==0&&d.yy/100!=0)||d.yy%400==0) v=1; else v=0; if(d.yy<=0) return 0; if(d.mm<1||d.mm>12) return 0; if(d.mm!=2&&(d.dd<1||d.dd>dm[d.mm])) return 0; if(d.mm==2&&(d.dd<1||d.dd>28+v)) return 0; return 1; } void print_baza(baza p) { cout.width(20); cout<<p.name; cout.width(12); cout<<p.price; cout.width(5); 93 cout<<p.percent<<" "; print_date(p.d); } Результат выполнения программы листинга 10.2 приведен на рис. 10.4. Рис. 10.4. Результат работы программы листинга 10.2 Листинг 10.3. В программе задается массив структур, который содержит сведения об успеваемости студентов. На экран дисплея выводится список неуспевающих студентов [1]. //L10_3.cpp #include "stdafx.h" #include <iostream> #include <locale> using namespace std; int _tmain() { setlocale (LC_ALL, "Russian"); const int f=5; int i, n, m=1; typedef struct {char fio[35]; int mark[4]; }student; student array[5]; //Массив структур 94 for (i=0; i<f; i++) {cout<<"Введите фамилию студента: "; cin>>array[i].fio; for (n=0; n<4; n++) {cout<<"Введите "<<n+1<<"-ю оценку студента: "; cin>>array[i].mark[n]; } } cout<<endl<<"Список неуспевающих:"<<endl; for (i=0; i<f; i++) for (n=0;n<4;n++) if (array[i].mark[n]==2) {cout<<m++<<") "<<array[i].fio<<endl; i++; } return 0; } Результат выполнения программы листинга 10.3 представлен на рис. 10.5. Рис. 10.5. Результат работы программы листинга 10.3 95 УПРАЖНЕНИЯ 1. В файле “input.txt” задано количество выпускников школ, желающих поступить на механико-математический факультет ННГУ, и их список. В списке для каждого абитуриента указаны фамилия, имя, отчество и сумма баллов ЕГЭ. Создать структуру, описывающую абитуриента, и создать массив из структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию суммы баллов. Полученный список записать в файл. 2. В файле “input.txt” задано количество записей каталога посадочного материала и его список. Каждая запись списка содержит название, вид посадочного материала (дерево, кустарник, овощи, ягоды), и цену единицы экземпляра. Создать структуру, описывающую каталог, и создать массив из структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по виду посадочного материала, а в случае его совпадения, по названиям. Полученный список записать в файл. 3. В файле “input.txt” задано количество записей работ, выполненных автомастерской, и их список. В каждой записи списка указаны фамилия, имя, отчество мастера и сумма за выполненную работу. Создать структуру, описывающую выполненные работы. Создать массив, который содержит фамилию, имя, отчество мастера и общую сумму заработанных им денег, используя информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 4. В файле “input.txt” задано количество записей инструментов, заказанных магазином на оптовой базе, и их список. Каждая запись списка содержит название инструмента, цену единицы товара и его количество. Создать структуру, описывающую данный заказ. Создать массив, который содержит название инструмента и его полную стоимость. Для заполнения массива использовать информацию из файла “input.txt”. Полученный массив упорядочить по названиям инструментов и определить общую стоимость заказа. Полученный результат записать в файл. 5. В файле “input.txt” задано количество записей выполненных работ фотоателье и их список. В каждой записи списка указаны фамилия, имя и отчество клиента, фамилия, имя и отчество мастера, сумма за выполненную мастером работу. Создать структуру, описывающую выполненные работы, и создать массив, который содержит фамилию, имя, отчество мастера и общую сумму заработанных им денег. Для заполнения массива использовать информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 6. В файле “input.txt” задано количество записей выполненных работ фотоателье и их список. В каждой записи списка указаны фамилия, имя и отчество клиента, фамилия, имя и отчество мастера, сумма за выполненную мастером работу. Создать структуру, описывающую выполненные работы, и создать массив, который содержит фамилию, имя, отчество 96 клиента и общую стоимость всех его фотографий. Для заполнения массива использовать информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 7. В файле “input.txt” задано количество участников соревнований зимней спартакиады ННГУ и их список. В каждой строке списка указаны фамилия, имя, отчество участника, вид соревнования (лыжи, коньки и т.д.) и показанный результат. Создать структуру, описывающую участника спартакиады, и создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по видам соревнований, а внутри каждого вида по убыванию результата. Полученный список записать в файл. 8. В файле “input.txt” задано количество участников соревнований по прыжкам в воду и их список. В каждой строке списка указаны фамилия, имя, отчество участника, номер попытки и показанный результат. Создать структуру, описывающую участника соревнований (указывается фамилия, имя, отчество участника, средний балл по всем результатам), создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию результата. Полученный список записать в файл. 9. В файле “input.txt” задано количество записей о денежных выплатах сотрудникам некоторой фирмы. В каждой записи списка указаны фамилия, имя, отчество сотрудника и сумма выплат. Создать структуру, описывающую выплаты сотрудникам, и создать массив, который содержит фамилию, имя, отчество сотрудника и общую сумму выплат. Для заполнения массива использовать информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 10. В файле “input.txt” задано количество записей содержимого промтоварной базы и его список. Каждая запись списка содержит название продукции, цену единицы продукции и количество экземпляров. Создать структуру, описывающую содержимое базы, и создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив в алфавитном порядке по названиям продукции. Подсчитать общую стоимость всех товаров. Полученный список записать в файл. 11. В файле “input.txt” задано количество записей контрактов, заключенных страховой фирмой, и их список. В каждой записи списка указаны фамилия, имя, отчество агента и стоимость контракта. Создать структуру, описывающую заключенные контракты. Создать массив, который содержит фамилию, имя, отчество агента и общую стоимость всех контрактов, заключенных этим агентом. Для заполнения массива использовать информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 12. В файле “input.txt” задано количество записей выполненных сельскохозяйственных работ и их список. В каждой записи списка указаны фамилия, имя, отчество работника и сумма за выполненную работу. Создать 97 структуру, описывающую выполненные работы, и создать массив, который содержит фамилию, имя, отчество работника и общую сумму заработанных денег. Для заполнения массива использовать информацию из файла “input.txt”. Массив упорядочить в алфавитном порядке. Полученный список записать в файл. 13. В файле “input.txt” задано количество студентов механикоматематического факультета ННГУ и их список. В каждой строке списка содержатся фамилия, имя, отчество студента, название сдаваемого предмета и оценка, полученная во время последней экзаменационной сессии. Создать структуру, описывающую студента с указанием фамилии, имени, отчества и среднего балла за эту сессию. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию суммы баллов. Полученный список записать в файл. 14. В файле “input.txt” задано количество студентов механикоматематического факультета ННГУ и их список. В каждой строке списка содержатся фамилия, имя, отчество студента, название сдаваемого предмета и оценка. Создать структуру, описывающую экзаменационную сессию, с указанием предмета и среднего балла за сессию по этому предмету, создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию суммы баллов. Полученный список записать в файл. 15. В файле “input.txt” задано количество участников соревнований летней спартакиады ННГУ и их список. В каждой строке списка указаны фамилия, имя, отчество участника, вид соревнования (прыжки, толкание ядра, метание молота) и показанный результат. Создать структуру, описывающую участника спартакиады. Создать массив структур, заполнив его информацией из файла “input.txt”, и упорядочить этот массив по видам соревнования, а внутри каждого вида по убыванию результата. Полученный список записать в файл. 16. В файле “input.txt” задано количество записей каталога обуви на осень 2013 года и список его содержимого. Каждая запись списка содержит название, цену за пару и количество пар обуви. Создать структуру, описывающую каталог. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию общей стоимости для каждой записи, а в случае равенства – в алфавитном порядке по названию обуви. Полученный список записать в файл. 17. В файле “input.txt” задано количество записей работ, выполненных строительной фирмой, и их список. В каждой записи списка указаны номер контракта и сумма за выполненную работу. Создать структуру, описывающую выполненные работы. Создать массив структур, для заполнения которого использовать информацию из файла “input.txt”. Массив упорядочить по убыванию суммы контракта. Полученный список записать в файл. 98 18. В файле “input.txt” задано количество записей списка, содержащего информацию о школьниках, отдыхающих в лагере ”Орленок”. В каждой записи списка указаны фамилия, имя, отчество школьника и номер отряда. Согласно данной информации создать структуру, описывающую школьников. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по возрастанию номера отряда, а внутри отряда упорядочить список в алфавитном порядке. Полученный список записать в файл. 19. В файле “input.txt” задано количество участников авторалли и их список. Каждая строка списка содержит фамилию, имя, отчество участника и показанный результат. Создать структуру, описывающую участника авторалли. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию результата, а в случае равенства результата – в алфавитном порядке участников соревнований. Полученный список записать в файл. 20. В файле “input.txt” задано количество записей содержимого овощной базы и еѐ список. Каждая запись списка содержит название продукции, цену за килограмм и общий вес в килограммах. Создать структуру, описывающую содержимое базы, и создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив в алфавитном порядке по названиям продукции. Подсчитать общую стоимость всех товаров. Полученный список записать в файл. 21. В файле “input.txt” задано количество участников спартакиады по тяжелой атлетике и их список. В каждой строке списка указаны фамилия, имя, отчество участника, вид соревнования (жим, рывок и толчок) и показанный результат. Создать структуру, описывающую участника спартакиады. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по убыванию суммы результатов. Полученный список записать в файл. 22. В файле “input.txt” задано количество записей содержимого книжной базы и еѐ список. Каждая запись списка содержит название книги, фамилию и инициалы автора, цену за экземпляр и число экземпляров. Создать структуру, описывающую содержимое базы, и создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив в алфавитном порядке по названиям книг. Подсчитать общую стоимость всех книг. Полученный список записать в файл. 23. В файле “input.txt” задано количество студентов механикоматематического факультета ННГУ и их список. Каждая строка списка содержит фамилию, имя, отчество студента, название сдаваемого предмета и оценку. Создать структуру, описывающую экзаменационную сессию. Создать массив структур, заполнив его информацией из файла “input.txt”, и упорядочить его в алфавитном порядке. Создать список неуспевающих студентов. Полученный список записать в файл. 99 24. В файле “input.txt” задано количество студентов механикоматематического факультета ННГУ и их список. Каждая строка списка содержит фамилию, имя, отчество студента, название сдаваемого предмета и оценку. Создать структуру, описывающую экзаменационную сессию. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить массив в алфавитном порядке. Создать список студентовотличников. Полученный список записать в файл. 25. В файле “input.txt” задано количество записей содержимого книжной базы и еѐ список. Каждая запись списка содержит название книги, фамилию и инициалы автора, цену за экземпляр и число экземпляров. Создать структуру, описывающую содержимое базы. Создать массив структур, заполнив его информацией из файла “input.txt”. Упорядочить этот массив по общей стоимости всех экземпляров данной книги. Подсчитать общую стоимость всех книг. Полученный список записать в файл. 100 11. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ Динамические структуры данных могут создаваться, изменять свой размер и уничтожаться в процессе выполнения программы [1, 4]. Динамические структуры, как и обычные структуры, состоят из полей. Кроме информационных полей они обязательно содержат поля-указатели на свой собственный тип структуры. При этом указатель указывает на структуру целиком, а не на отдельные элементы структуры. Рассмотрим следующие динамические структуры данных: списки, очереди, стеки. 11.1. Односвязные списки При работе с совокупностью данных обычно используются массивы. Их преимущество очевидно, когда используется циклическая обработка информации. Если при работе с информацией приходится менять порядок элементов, то использование массивов приводит к большим затратам времени, так как приходится перемещать значительные объѐмы информации. Например, необходимо создать список фамилий (рис. 11.1). 1 2 3 4 5 6 Афанасьев Бирюкова Васильева Миронов Сергеева Яковлева Рис. 11.1. Исходный список фамилий При внесении дополнительной фамилии «Баринова» (рис. 11.2), необходимо будет переместить все фамилии, начиная со второй, на одну позицию ниже. При больших списках это может занимать значительное время. 1 2 3 4 5 6 7 Афанасьев Баринова Бирюкова Васильева Миронов Сергеева Яковлева Рис. 11.2. Список с добавленной фамилией «Баринова» 101 Если в новом списке нужно удалить фамилию «Васильева» (рис. 11.3), то также возникает необходимость в перемещении информации, что тоже приводит к значительным затратам времени. 1 2 3 4 5 6 Афанасьев Баринова Бирюкова Миронов Сергеева Яковлева Рис. 11.3. Список с удаленной фамилией «Васильева» Для более эффективной работы с такими списками лучше использовать структуру. Содержимое еѐ полей можно разделить на две части. Одна содержит информацию о конкретном объекте, а другая (указатель) содержит адрес, по которому находится следующий объект. Таким образом, данный связный список представляет собой отдельные записи, связанные между собой указателями, и называется односвязным (однонаправленным) списком. Схематически его можно изобразить так, как показано на рис. 11.4, где указатель first совпадает с адресом первого элемента списка. Рис. 11.4. Схематическое изображение односвязного списка, представленного на рис. 11.3 Если нужно внести в список новую фамилию, то, двигаясь по списку, сначала необходимо определить те элементы, между которыми должна быть вставлена новая фамилия. Пусть необходимо добавить новую фамилию «Васильева», находящуюся под условным номером «7», в список, представленный на рис. 11.3. Передвигаясь по списку, определяем, что данная фамилия должна находиться между фамилиями «Бирюкова» и « Миронов». 102 В этом случае в поле адреса третьего элемента должен быть адрес седьмого элемента, а в поле адреса седьмого элемента необходимо занести адрес четвертого элемента (рис.11.5) [4]. Рис. 11.5. Схематическое изображение списка при добавлении новой фамилии «Васильева» в список, представленный на рис. 11.3 Если необходимо удалить кого-либо из списка, то, двигаясь по списку, нужно найти этот объект и перестроить связи таким образом, чтобы данный элемент был исключен из списка. Не следует забывать, что необходимо освобождать память, выделенную под этот элемент. Пусть в списке, представленном на рис.11.5, удаляется фамилия «Афанасьев», которая идет первой в односвязном списке. Тогда следует перенастроить указатель first и освободить место, занимаемое этим объектом. Если удаляется фамилия внутри списка (например, «Миронов»), то связь объекта «7.Васильева» перенаправляется по связи удаляемого объекта. Структура для описания таких объектов может иметь вид: struct persona { char *name; persona *next; //Фамилия человека //Указатель на следующий объект }; Следует обратить внимание на то, что структура persona используется до конца ее описания. Это единственный случай нарушения принципа использовать лишь то, что описано выше. Это сделано для того, чтобы создавать такую структуру данных. Листинг 11.1. В программе формирующий односвязный список, состоящий из фамилий, которые вводятся с клавиатуры. Отметим, что фамилии следует вводить на английском языке. Затем из сформированного списка удаляется указанная фамилия. 103 Файл “stdafx.h” #pragma once #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <tchar.h> #include <string.h> #include <iostream> using namespace std; Файл “Spisok.h” //Структура, описывающая объект односвязного списка: struct persona { char *name; persona *next; }; //Прототип функции, добавлябщей новый элемент в односвязный список: persona* add_persona(persona*first, char* new_name); //Прототип функции, удаляющей элемент из односвязного списка: persona* del_persona(persona*first, char* del_name); //Прототип функции печати односвязного списка: void print_persona(persona*first); //L10_1.cpp #include "stdafx.h" #include "Spisok.h" persona* add_persona(persona*first, char* new_name) { persona*ptr,*prev,*new_el; //Создание нового элемента списка: new_el=new persona; //Заполнение информационной части объекта: (*new_el).name=strdup(new_name); //Поле связи нулевое. В процессе встраивания оно при необходимости //переопределяется: (*new_el).next=NULL; //Проверка существования связного списка: if(first==NULL) { //Список пуст и элемент вносится как единственный: 104 first=new_el; return first; } //Поиск места для нового элемента: ptr=first; prev=NULL; while(ptr && strcmp((*ptr).name, new_name)<0) { prev=ptr; ptr=(*ptr).next; } if(prev==NULL) //Новый элемент должен добавляться в начало списка, // так как передвижения по списку не было: { (*new_el).next=first; first=new_el; } else //Новый элемент добавляется в середину или в конец списка: { (*prev).next=new_el; (*new_el).next=ptr; } return first; } void print_persona(persona*first) { setlocale(LC_CTYPE, ".866"); persona*ptr=first; while(ptr!=NULL) { cout<<(*ptr).name<<'\n'; ptr=(*ptr).next; } setlocale(LC_CTYPE,"russian"); } persona* del_persona(persona*first, char* del_name) { persona*ptr,*prev; ptr=first; 105 prev=NULL; //Поиск удаляемой фамилии: while(ptr && strcmp((*ptr).name, del_name)!=0) { prev=ptr; ptr=(*ptr).next; } if(ptr==NULL) //Фамилия не найдена { cout<<"Такой фамилии нет!\n"; return first; } if(prev==NULL) { //Удаляется первая фамилия списка: first=(*first).next; delete (*ptr).name; delete ptr; } else { //Удаляется фамилия в середине списка или в конце его: (*prev).next=(*ptr).next; delete (*ptr).name; delete ptr; } return first; } int _tmain( ) { char st[50]; persona *first=NULL,*ptr; setlocale(LC_CTYPE,"russian"); //Построение односвязного списка: cout<<"Введите фамилию "; cin>>st; do { first=add_persona(first,st); cout<<"Введите фамилию или нажмите 0, если хотите прекратить ввод "; cin>>st; }while(strcmp(st, "0")!=0); //Печать построенного списка: print_persona(first); 106 cout<<"Введите удаляемую фамилию "; cin>>st; //Удаление фамилии из односвязного списка: first=del_persona(first,st); //Печать полученного односвязного списка: print_persona(first); cin.get(); cin.get(); return 0; } Результат выполнения программы листинга 11.1 представлен на рис. 11.6. Рис. 11.6. Результат работы программы листинга 11.1 11.2. Очереди Очередь – это связный список, закон построения которого следующий: новый элемент всегда ставится в конец списка, а удаление элемента происходит из его начала [4, 32]. Таким образом, очередь является структурой данных, которые организованы по принципу FIFO (First In, First Out) – «Первый пришел – первый вышел». Чтобы не ограничивать максимальное число элементов в очереди, очередь может быть реализована в виде однонаправленного списка. В этом случае объекты очереди имеют такую же структуру, как и объекты однонаправленного списка. Часть полей описывает характеристики конкретного объекта и есть поле типа указатель, которое содержит адрес следующего в очереди элемента. 107 С очередью связаны два указателя. Один содержит адрес объекта, находящегося в начале очереди, а другой хранит адрес последнего объекта очереди. Первый из них назовем begin, а второй end. Листинг 11.2. В программе создается очередь из некоторых заданий, характеризующихся номером и длиной выполнения. Структуру этих объектов можно описать так: struct ochered { int number; int count; ochered *next; }; //Номер задания //Объем задания //Указатель на следующий элемент Задания добавляются в очередь и удаляются из очереди. Файл “ stdafx.h” #pragma once #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <tchar.h> #include <iostream> using namespace std; Файл “Och.h” struct ochered { int number; //Номер задания int count; //Объем задания ochered *next; //Указатель на следующий элемент }; // Прототип функции постановки задания в очередь: void add_ochered(ochered **begin, ochered **end, int nn, int dl); //Прототип функции удаления задания из очереди: void del_ochered(ochered **begin, ochered **end); // Прототип функции печати содержимого очереди: void print_ochered(ochered *begin); Файл “Och.cpp” #include "stdafx.h" #include "Och.h" void add_ochered(ochered **begin, ochered **end, int nn, int dl) { ochered *new_el; 108 //Создание нового элемента: new_el=new ochered; (*new_el).number=nn; (*new_el).count=dl; (*new_el).next=NULL; if(*begin==NULL) { //Очередь пуста.Элемент добавляется как единственный: (*begin)=(*end)=new_el; return; } //Добавление нового элемента в очередь: (**end).next=new_el; (*end)=new_el; } void del_ochered(ochered **begin, ochered **end) { ochered *ptr; ptr=*begin; if(*begin==NULL) { //Очередь пуста: cout<<"Очередь пуста"; return; } //Передвигается начало очереди: (*begin)=(**begin).next; //Освобождается место удаляемого элемента: delete ptr; } void print_ochered(ochered *begin) { ochered *ptr=begin; cout<<" Номер задания | Его длина"<<'\n'; while(ptr!=NULL) { cout.width(12); cout<<(*ptr).number; cout.width(18); cout<<(*ptr).count<<'\n'; ptr=(*ptr).next; } } 109 //L11_2.cpp #include "stdafx.h" #include "Och.h" int _tmain( ) { ochered *begin, *end; int nn,dl; setlocale(LC_CTYPE,"rus"); begin=end=NULL; //Постановка задания в очередь: cout<<"Введите номер задания и его длину "; cin>>nn>>dl; cout<<"Если хотите прекратить ввод введите номер и длину нулевыми\n"; do { add_ochered(&begin, &end, nn, dl); cout<<"Введите номер задания и его длину "; cin>>nn>>dl; }while(nn!=0); print_ochered(begin); //Удаляется задание из очереди: del_ochered(&begin, &end); print_ochered(begin); cin.get(); cin.get(); return 0; } Результат выполнения программы листинга 11.2 представлен на рис. 11.7. Рис. 11.7. Результат работы программы листинга 11.2 110 11.3. Стеки Стек – это связный список, закон построения которого следующий: новый элемент всегда ставится в начало списка, удаление элемента также происходит из его начала [4, 32]. Место, куда помещаются и из которого извлекаются элементы стека, называется вершиной. Таким образом, стек является структурой данных, которые организованы по принципу LIFO (Last In, First Out) – «Последний пришел – первый вышел». Стек можно реализовать различными способами. Например, элементы стека можно разместить в массиве, либо реализовать стек в виде односвязного списка [32]. Рассмотрим реализацию стека в виде списка. В этом случае объекты стека имеют такую же структуру, как и объекты однонаправленного списка. Часть полей описывает характеристику конкретного объекта и есть поле типа указатель, которое содержит адрес следующего в стеке элемента. Листинг 11.3. В программе создается стек для проверки правильности расстановок скобок в тексте, содержащимся в файле «input.txt » (рис. 11.7). Будем считать, что есть скобки трех видов – круглые, квадратные и фигурные. Последовательность скобок считается правильной если [4]: 1. Это элементарная последовательность: (), {}, [] 2. Пусть S – это правильно построенная последовательность. Тогда последовательности (S), {S} и [S] – правильно построенные. 3. Пусть S и R правильно построенные последовательности. Тогда последовательность SR – правильно построенная. Алгоритм проверки правильности расстановок скобок заключается в следующем. Если текущий символ является открывающей скобкой, то он заносится в стек. Если текущий символ – закрывающая скобка, то анализируется символ, находящийся в вершине стека. Если это парная скобка, то символ удаляется из стека, а если непарная, то дается информация, что последовательность построена неправильно. Остальные символы игнорируются. В конце анализируется содержимое стека. Если он пуст, то последовательность правильно построена, иначе она построена неправильно. 111 Содержимое файла “input.txt” Рис. 11.8. Информация, находящаяся в файле «input.txt» //L11_3.cpp #include <fstream> #include <iostream> using namespace std; struct stek { char c; stek*next; }; stek* add_stek(stek*, char); stek* del_stek(stek*); //Прототип функции добавления элемета в стек //Прототип функции удаления элемета из стека int main( ) { char nc[3]={'(','{','['}, kc[3]={')','}',']'}, c; int i; setlocale(LC_CTYPE,"russian"); stek *top=NULL; ifstream ff("input.txt"); c=ff.get(); while(!ff.eof()) { for(i=0;i<3;i++) if(c==nc[i]) { top=add_stek(top, c); 112 break; } for(i=0; i<3; i++) { if(c==kc[i]) break; } if(i<3 && top!=NULL) { if(top->c==nc[i]) top=del_stek(top); else { if(top->c!=nc[i]) { cout<<"Последовательность построена неправильно\n"; return 0; } } } else if(i<3 && top==NULL) { cout<<"Последовательность построена неправильно\n"; return 0; } c=ff.get(); } ff.close(); if(top!=NULL) cout<<"Последовательность построена неправильно\n"; else cout<<"Последовательность построена правильно\n"; return 0; } stek* add_stek(stek *top, char c) { stek *new_el; new_el=new stek; new_el->c=c; new_el->next=NULL; if(top==NULL) top=new_el; else 113 { new_el->next=top; top=new_el; } return top; } stek* del_stek(stek *top) { stek *tmp; tmp=top; top=top->next; delete tmp; return top; } Результат выполнения программы листинга 11.3 приведен на рис. 11.9. Рис. 11.9. Результат работы программы листинга 11.3 Листинг 11.4. В программе создаются структуры очереди и стека, хранящие символ. В файле «input.txt» хранится текст (рис. 11.10). Преобразовать его следующим образом: сначала должны идти цифры в том порядке, в котором они встречаются в файле «input.txt», а затем латинские буквы в обратном порядке, чем в файле «input.txt». Для решения этой задачи считываемые цифры следует помещать в очередь, а латинские буквы в стек. Далее необходимо извлечь информацию из очереди, а затем из стека. Содержимое файла “input.txt” Рис. 11.10. Информация, находящаяся в файле «input.txt» //L11_4.cpp #include <fstream> #include <iostream> using namespace std; struct ochered 114 { char c; ochered *next; //Указатель на следующий элемент }; //Прототип функции постановки в очередь: void add_ochered(ochered **begin, ochered **end, char nc); //Прототип функции удаления из очереди: void del_ochered(ochered **begin, ochered **end); struct stek { char c; stek *next; //Указатель на следующий элемент }; //Прототип функции постановки в стек: stek* add_stek(stek *top, char nc); //Прототип функции удаления из стека: stek* del_stek(stek*); //Прототип функции печати содержимого очереди: void print_och(ochered *begin, char *sn); //Прототип функции печати содержимого стека: void print_stek(stek *top, char *sn); void add_ochered(ochered **begin, ochered **end, char nc) { ochered *new_el; new_el=new ochered; //Создание нового элемента (*new_el).c=nc; (*new_el).next=NULL; if(*begin==NULL) //Очередь пуста.Элемент вносится как единственный { (*begin)=(*end)=new_el; return; } //Внесение нового элемента в очередь: (**end).next=new_el; (*end)=new_el; } void del_ochered(ochered **begin, ochered **end) { ochered *ptr; ptr=*begin; if(*begin==NULL) //Очередь пуста { cout<<"Очередь пуста"; 115 return; } //Передвигается начало очереди: (*begin)=(**begin).next; //Освобождается память, выделенная для удаляемого элемента: delete ptr; } void print_och(ochered *begin, char *sn) { ofstream ff(sn); ochered *ptr=begin; while(ptr!=NULL) { ff<<(*ptr).c; ptr=(*ptr).next; } } stek* add_stek(stek *top, char c) { stek* new_el; new_el=new stek; new_el->c=c; new_el->next=NULL; if(top==NULL) //Создание нового элемента //Стек пуст.Элемент вносится как единственный top=new_el; else { //Внесение нового элемента в стек: new_el->next=top; top=new_el; } return top; } stek*del_stek(stek *top) { stek *tmp; tmp=top; if(top==NULL) //Стек пуст { cout<<"Стек пуст"; return NULL; 116 } //Передвигается начало стека: top=top->next; //Освобождается память, выделенная для удаляемого элемента: delete tmp; return top; } void print_stek(stek *top, char *sn) { ofstream ff(sn,ios::app); stek *ptr=top; while(ptr!=NULL) { ff<<(*ptr).c; ptr=(*ptr).next; } } int main( ) { ifstream ff("input.txt"); char cc[81]; int i; ochered *begin,*end; stek *top; begin=end=NULL; top=NULL; ff.getline(cc, 80); while(!ff.eof()) { for(i=0; cc[i]!='\0'; i++) { if(cc[i]>='A' && cc[i]<='z') top=add_stek(top, cc[i]); else if(cc[i]>='0'&&cc[i]<='9') add_ochered(&begin, &end, cc[i]); } ff.getline(cc, 80); } ff.close(); char so[8]="out.txt"; print_och(begin, so); print_stek(top, so); 117 return 0; } Результат выполнения программы листинга 11.4 приведен на рис. 11.11. Рис. 11.11. Результат работы программы листинга 11.4 УПРАЖНЕНИЯ 26. В файле “input.txt” задан текст. Ввести структуру, отражающую уникальное слово и частоту его встречаемости в тексте. Создать очередь, элементы которой тип введенной структуры. Результат записать в файл. 27. В файле “input.txt” задан текст. Ввести структуру, отражающую уникальное слово и частоту его встречаемости в тексте. Создать односвязный список, содержащий слова в алфавитном порядке, и результаты записать в файл. 28. В файле “input.txt” задана последовательность чисел и символов арифметических операций (+, -, *, /). Если из файла считывается число, то оно помещается в стек. Если считывается символ, то из стека извлекаются два числа и над ними производится данная арифметическая операция (если она допустима), и результат вновь помещается в стек. Если операцию по каким-либо причинам выполнить невозможно (не хватает чисел в стеке или делитель равен нулю), то на экран выдается сообщение о причине и необходимо прекратить выполнение программы. Если чтение из файла “input.txt” заканчивается успешно, то выдать информацию о количестве проведенных операций. 29. В файле “input.txt” задан список абитуриентов ННГУ с указанием фамилии, имени и отчества, а также суммы баллов, набранных по профильным предметам. Составить односвязный список абитуриентов по убыванию суммы баллов и результаты записать в файл. 30. В файле “input.txt” задан список сотрудников фирмы с указанием даты их поступления на работу. Для описания дат создать структуру. Написать функцию сравнения двух дат. Составить односвязный список сотрудников в порядке возрастания даты их поступления на работу. 31. Для описания дат создать структуру и написать функцию сравнения двух дат. Разработать структуру для описания интервала, состоящего из двух дат. В файле “input.txt” задан список из нескольких пар дат – концов интервала. Составить из них очередь. Определить, существует ли непустое пересечение этих интервалов. 118 32. В файле “input.txt” задан список студентов ММФ ННГУ с указанием фамилии, имени и отчества, а также название предмета и экзаменационная оценка. Составить односвязный список студентов в алфавитном порядке с указанием среднего балла. 33. Создать структуру для описания комплексных чисел. Написать функции действий с комплексными числами (сложение, вычитание, умножение, деление, нахождение модуля). В файле “input.txt” задан список из четного числа комплексных чисел. Для каждой пары комплексных чисел выполнить все четыре арифметических действия и результат записать в файл. Если действия выполнить нельзя, вывести об этом сообщение. 34. В файле “input.txt” задан список заданий для выполнения на ЭВМ. Задание включает: номер задания, длительность выполнения (в минутах) и фамилию исполнителя. Разработать структуру заданий. Создать из заданного списка очередь на выполнение работ. Определить общее время работы в часах и минутах. 35. В файле “input.txt” задан список заданий для выполнения на ЭВМ. Задание включает: номер задания, длительность выполнения (в минутах) и фамилию исполнителя. Разработать структуру заданий. Создать односвязный список по убыванию длительности выполнения задания. Полученные данные записать в файл. 36. Для описания дат создать структуру и написать функцию проверки правильности вводимой даты. В файле “input.txt” задан список дат. При чтении из файла отмечать неправильно записанные даты и заносить их в стек. Определить число неправильно введенных дат и вывести на экран. 37. Для описания дат создать структуру и написать функцию проверки правильности вводимой даты. В файле “input.txt” задан список дат. При чтении из файла игнорировать неправильно записанные даты. Правильно записанные даты заносить в очередь. Определить число правильно введенных дат и вывести на экран. 38. Для описания дат создать структуру и написать функции: проверки правильности вводимой даты и сравнения двух дат. В файле “input.txt” задан список дат. При чтении из файла игнорировать неправильно записанные даты, а из правильно записанных дат создать односвязный список по возрастанию дат. Определить число неправильно введенных дат и вывести на экран. 39. Создать структуру очереди, хранящую символ. В файле «input.txt” задан текст. Преобразовать его следующим образом: сначала должны идти цифры в том порядке, в котором они встречаются в файле ”input.txt”, а затем буквы кириллицы в том же порядке, в котором они встречаются в файле ”input.txt”. 40. Создать структуры очереди и стека, хранящие символ. В файле ”input.txt” задан текст. Преобразовать его следующим образом: сначала должны идти латинские буквы в том же порядке, в котором они встречаются в файле ”input.txt”, а затем цифры в обратном порядке, чем в файле ”input.txt”. 119 41. Создать структуры очереди и стека, хранящие символ. В файле ”input.txt” хранится текст. Преобразовать его следующим образом: сначала должны идти знаки препинания (, . ; : ! -) в том порядке, в котором они встречаются в файле ”input.txt”, а затем буквы кириллицы в обратном порядке, чем в файле ”input.txt”. 42. Создать структуры очереди и стека, хранящие символ. В файле ”input.txt” задан текст. Преобразовать его следующим образом: сначала должны идти латинские буквы в том порядке, в котором они встречаются в файле ”input.txt”, а затем буквы кириллицы в обратном порядке, чем в файле ”input.txt”. 43. Создать структуру для описания моментов времени (часы, минуты, секунды). Написать функцию сравнения двух моментов времени. Разработать структуру для описания участников олимпиады. В файле ”input.txt” задан список участников, содержащий фамилию, имя, отчество и показанный результат. Составить односвязный список по возрастанию показанных результатов и распечатать информацию о первых шести участниках. 44. Создать структуру для описания моментов времени (часы, минуты, секунды). Написать функцию сравнения двух моментов времени. Разработать структуру для описания участников олимпиады. В файле ”input.txt” задан список участников, содержащий фамилию, имя, отчество и показанный результат. Составить односвязный список по убыванию показанных результатов и распечатать информацию о первых шести участниках. 45. Для описания дат создать структуру и написать функцию, определяющую расстояние в днях между двумя датами. В файле “input.txt” задан список фирм с указанием даты их основания. Составить односвязный список фирм в а порядке возрастания длительности их работы на текущую дату. 46. Для описания дат создать структуру и написать функцию, определяющую расстояние в днях между двумя датами. В файле “input.txt” задан список сотрудников фирмы с указанием начала их контракта и даты его окончания. Составить односвязный список сотрудников в алфавитном порядке с указанием числа дней работы в данной фирме. 47. Для описания дат создать структуру и написать функцию сравнения двух дат. Ввести структуру для описания интервала, состоящего из двух дат. В файле “input.txt” задан список сотрудников фирмы с указанием дат начала и конца их командировки, а также города, куда они были направлены. Определить, какие из сотрудников могут встретиться в командировке, и создать очередь из этих сотрудников. 48. Для описания дат создать структуру и написать функцию сравнения двух дат. В файле “input.txt” задан список продуктов, хранящихся на базе, с указанием срока годности. Создать очередь из продуктов, срок годности которых истек на данную дату. Вывести на экран список продуктов, годных к реализации. 120 49. Для описания дат создать структуру и написать функцию сравнения двух дат. В файле “input.txt” задан список продуктов, хранящихся на базе, с указанием срока годности. Создать стек из продуктов, годных к реализации на данную дату. Вывести на экран информацию о продуктах, срок реализации которых истек. 50. Для описания дат создать структуру и написать функции: сравнения двух дат и определения расстояния в днях между двумя датами. В файле “input.txt” задан список продуктов, хранящихся на базе, с указанием срока годности. Создать очередь из продуктов, срок годности которых истекает не позднее, чем через пять дней до заданной даты. Вывести на экран список продуктов, годных к реализации, но не вошедших в созданную очередь. 121 Список литературы 1. Ашарина И.В. Объектно-ориентированное программирование в С++: лекции и упражнения: Учебное пособие для вузов. – М.: Горячая линия – Телеком, 2008. – 320 с. 2. Бобровский С. Самоучитель программирования на языке С++ в системе Borland C++ Builder 5.0. – М.: ДЕСС КОМ, 2001. – 271 с. 3. Глушаков С.В., Коваль А.В., Смирнов С.В. Язык программирования С++: учебный курс. – Харьков: Фолио; М.: ООО «Издательство АСТ», 2001. – 500 с. 4. Гудман С., Хидетниеми С. Введение в разработку и анализ алгоритмов. – М.: Мир, 1981. – 368 с. 5. Девис С.Р. С++ для чайников, 6-е изд.: пер. с англ. – М.: ООО «И.Д. Вильямс», 2010. – 336 с. 6. Дейтел Х.М., Дейтел П.Дж. Как программировать на С++, 5-е изд.: пер. с англ. – М: ООО «Бином-Пресс», 2008. – 1456 с. 7. Задачи по программированию /С.А. Абрамов, Г.Г. Гнездилова, Е.Н. Капустина, М.И. Селюн. – М. : Наука, 1998 – 224 с. 8. Касаткин А.И., Вальвачев А.Н. От Turbo C к Borland C++. – Минск: Вышейшая школа, 1992. – 240 с. 9. Керниган Б., Ритчи Д. Язык программирования Си: пер. с англ. – СПб.: Невский Диалект, 2001. – 352 с. 10. Кнут Д.Э. Искусство программирования, том 3. Сортировка и поиск. – М.: Издательский дом «Вильямс», 2000. – 832 с. 11. Кузнецов М.В., Симдянов И.В. С++. Мастер-класс в задачах и примерах. – СПб.: БХВ-Петербург, 2007. – 480 с. 12. Культин Н.Б. С/С++ в задачах и примерах: 2-е изд., перераб. и доп. – СПб.: БХВ – Петербург, 2009. – 368 с. 13. Культин Н.Б. С++ Builder в задачах и примерах. – СПб.: БХВ- Петербург, 2007. – 336 с. 14. Лафоре Р. Объектно-ориентированное программирование в С++. Классика Computer Science: 4-е изд. – СПб.: Питер, 2008. – 928 с. 15. Макогон В.С. Язык программирования Си для начинающих: Учебное пособие. – Одесса: НПФ «Астропринт», 1993. – 96 с. 16. Математический энциклопедический словарь / Гл. ред. Ю.В. Прохоров; Ред. кол.: С.И. Адян, Н.С. Бахвалов, В.И. Битюцков и др. – М.: Советская энциклопедия, 1988. – 847 с. 17. Павловская Т.А. С/С++. Программирование на языке высокого уровня. – СПб.: Питер, 2007. – 461 с. 18. Павловская Т.А., Щупак Ю.А. С++. Объектно-ориентированное программирование: практикум. – СПб.: Питер, 2008. – 265 с. 19. Пахомов Б.И. С/С++ и MS Visual С++ 2005 для начинающих. – СПб.: БХВ-Петербург, 2007. – 464 с. 20. Пахомов Б.И. С/С++ и MS Visual С++ 2008 для начинающих. – СПб.: БХВ-Петербург, 2008. – 624 с. 122 21. Перова В.И. Программирование на С++ в среде Visual Studio .NET: Учебное пособие. – Нижний Новгород: Изд-во Нижегородского госуниверситета, 2010. – 261 с. 22. Перова В.И., Чугунова Е.А. Объектно-ориентированное программирование на языке С++ в среде Visual Studio .NET: Ч. 1: Учебно-методическое пособие / Под ред. В.И. Перовой. – Нижний Новгород: Нижегородский госуниверситет, 2009. – 95 с. 23. Перова В.И., Чугунова Е.А. Объектно-ориентированное программирование на языке С++ в среде Visual Studio .NET: Ч. 2: Учебно-методическое пособие / Под ред. В.И. Перовой. – Нижний Новгород: Нижегородский госуниверситет, 2010. – 95 с. 24. Подбельский В.В. Язык Си++: учебное пособие. – М.: Финансы и статистика, 2001. – 560 с. 25. Прата С. Язык программирования С++. Лекции и упражнения, 5-е изд.: пер. с англ. – М.: ООО «И.Д. Вильямс», 2007. – 1184 с. 26. Сборник заданий по вычислительному практикуму на языке Си: Методическое пособие / Сост. В.В. Денисов, М.В. Маркина, Т.А. Сабаева, О.Г. Савихин. – Нижний Новгород: Изд-во ННГУ, 2002. – 56 с. 27. Солтер Н.А., Клеппер С.Дж. С++ для профессионалов: пер. с англ. – М.: ООО «И.Д. Вильямс», 2006. – 912 с. 28. Страуструп Б. Дизайн и эволюция С++: пер. с англ. – М.: ДМК Пресс; СПб.: Питер, 2007. – 445 с. 29. Страуструп Б. Язык программирования С++. Специальное издание: пер. с англ. – М.: ООО «Бином-Пресс», 2005. – 1104 с. 30. Тарасов В.Л. Основы программирования в С++Builder. Ч. 1: Учебнометодическое пособие. – Нижний Новгород: Нижегородский госуниверситет, 2008. – 68 с. 31. Тарасов В.Л. Основы программирования в С++Builder. Ч. 2: Учебнометодическое пособие. – Нижний Новгород: Нижегородский госуниверситет, 2006. – 84 с. 32. Тарасов В.Л. Программирование на С++: Учебное пособие. – Н. Новгород: Изд-во ННГУ, 2006. – 310 с. 33. Уайс М.А. Организация структур данных и решение задач на С++. – М.: ЭКОМ Паблишерз, 2008. – 896 с. 34. Фридман А.Л. Основы объектно-ориентированного программирования на языке Си++. – М.: Горячая линия – Телеком, 2001. – 232 с. 35. Шилдт Г. Полный справочник по С++, 4-е изд.: пер. с англ. – М.: Издательский дом «Вильямс», 2006. – 800 с. 36. Шилдт Г. С++: методики программирования Шилдта: пер. с англ. – М.: ООО «И.Д. Вильямс», 2009. – 480 с. 37. Шилдт Г. Самоучитель С++: пер. с англ. – СПб.: БХВ-Петербург, 2001. – 688 с. 123