- •13. Алгоритмы поиска. Основные понятия. Линейный и двоичный (бинарный) поиск. Алгоритмы сортировки. Основные понятия. Внутренние мортировки.
- •Алгоритмы сортировки. Основные понятия. Внутренние cортировки.
- •Типы данных для работы с целыми числами. Внутренне представление. Символьный тип
- •Типы данных для работы с вещ-ми числами. Внутренне представление. Множество значений
2. Операции и выражения в СИ и СИ++. Типы выражений. Преобразование типов
СИ предлагает более 40 операций, которые можно производить над данными. Данные в этом случае наз операндами. Некоторые операции выполняются над 1операндом – унарные (одноместные). Некоторые над 2 – бинарные (двуместные). Над 3 – тернарные (трехместные). В программе операции указываются лексемами, наз знаками операций. Знаки унарных операций могут указываться перед операндом, их наз префиксные; и после операнда – постфиксные. Знак бинарной операции указывается между операндами и наз инфексные. Операции объединяют в группы: арифм операции, операции отношения, логич операции и др.
Арифметич операции и СП-ся для выполнения арифм действий над данными. Унарный плюс (минус) +3, -3, -а. Сложение(вычитание) 3+2, 3-2, а+с, а-с. Умножение 3*2, а*с. Деление (если операнды целочисленные, то выполняется деление нацело 3/2=1. Сравните, 3.0/2.0=1.5). Остаток от деления нацело (только для целочисленных операндов) 5%3=2.
Операции отношения исп-ся для сравнения данных. Равно (неравно) (= =; != результат =1, если отношение указанной операции истинно, и =0, если ложно). Больше, больше либо равно, меньне, меньше либо равно (3= =2 результат 0; 3!=2 результат 1; 3>=2 результат 1).
Логические операции исп-ся для формирования логич выражений. Только над целочисленными данными. Отрицание (!) – унарная, префиксная: результат = 1, если операнд =0 и наоборот(!3 =0). Логическое И (конъюнкция) (&&) : результат =1, если оба операнда неравны 0, иначе =0. Логическое ИЛИ (дезъюнкция) (||): результат =0, если оба операнда = 0, иначе = 1 .
Битовые операции исп-ся на уровне внутреннего представления данных. Выполняются над соответствующими битами операндов. Производятся только над целочисленными операндами. Поразрядная инверсия (~): унарная префиксная операция (был 0 стал 1 и наоборот). Поразрядное И (поразрядная конъюнкция, поразрядное умножение) (&). Поразрядное ИЛИ (поразрядная дизъюнкция, поразрядное сложение) (|). Поразрядное исключающее ИЛИ (^). Сдвиг влево (<<): осуществляет сдвиг влево битов внутреннего представления первого операнда на число разрядов, указанное вторым операндом. При этом младшие освободившиеся разряды заполняются 0, а старшие теряются. Второй операнд должен быть константой. Сдвиг вправо (>>): аналогична операции сдвиг влево. При этом младшие разряды теряются, а освободившиеся старшие разряды заполняются 0, если значение положительное и 1, если – отрицательное (расширение знакового разряда).
Операции присваивания исп-ся для запоминания некоторых значений с целью их дальнейшего исполь-я. Присваивание означает, что значение заносится в ячейку памяти, соответствующей некоторой перемнной, при этом старое значение переменной теряется. Инкремент ++: унарная операция, может быть и префиксная и постфиксная. Префиксная: увелич значение переменной, указанной справа, на 1 и новове значение исп-ся далее. Постфиксная: увелич на 1 значение переменной, указанной слева, но далее операции вып-ся с прежним значением. Декремент (--). Присваивание (=): присваивает значение операнда справа переменной, указанной слева. +=(-=, *=, /= и др) выполняется операция над операндами справа и значением переменной, указанной слева, полученное значение присваивается переменной. Поразрядное И с присваиванием (ИЛИ) и др.
В бинарных операциях присваивания слева от знака операции указывается переменная, которая получает новое значение, т.е. адрес соответствующей ей ячейки памяти. И этот операнд наз l (left) value (l-).Значение, которое должно быть присвоено переменной, указанное операндом справа, (r- ).
Условная операция – тернарная операция. Первый операнд отделяется от второго вопросительным знаком, а второй от третьего знаком : Если первый операнд не равен нулю, то результат операции равен значению второго операнда, иначе – третьего. a>=0?a:-a Результат операции модуль а.
Выражения – это конструкции языка, определяющие порядок вычисления некоторого значения и состоящие из операндов, знаков операций и круглых скобок. Вычисление значения производится по обычным алгебраич правилам: вычисления вып-ся слева на право в соответствии с приоритетом операции и правилами ассоциативности. Операции с одинаковым приоритетом выполняются в порядке по правилам ассоциативности. Круглые скобки позволяют изменить этот порядок. При построении выражений надо учитывать, что пости все бинарные операции (кроме сдвига и присваивания) вып-ся с операндами одного и того же типа. В СИ допустимо смешение типов в выражении, но значения операндов должны быть преобразованы к одному тип. Такое преобразование вып-ся неявно по правилу преобразования короткого типа к длинному:
Если операнд имеет тип double, то второй тоже преобразуется к типу double. Если операнд имеет тип float, то оба преобразуются к double. Если операнд имеет тип unsigned long int, 2й операнд преоборазуется к этому типу. Если операнд имеет тип long int, 2й операнд преоборазуется к этому типу. Если операнд имеет тип unsigned int, 2й операнд преоборазуется к этому типу. В противном случае оба операнда будут преобразованы к типу int.
Преобразование целочисленного типа от длинного к короткому производится путём отбрасывания старших битов представления. Преобразование вещественного типа к целочисленному – отбрасывание дробной части и возможной потери старших битов представления. Преобразование от double к float приводит к потере точности представления или ошибке порядка числа.
Результаты арифм и битовых операций будут того же типа, что и их операнды. Результат операций отношения и логич будет иметь тип int. Результат присваиваевания - тип переменной, указанной слева.
Для явного преобразования сущ унарная префиксная операция (<тип>).
Выражение, в котором операнды – только буквальные константы, наз константным выражением. Значение такого выражения вычисляется при компеллляции программы и при выполнении представляется как буквальная константа.
8. Средства структурного программирования в СИ и СИ++. If, switch, следование, ветвление
Структурное программирование. Осн идеи были сформулированы в 70е годы 19 века. В основе лежит теорема Бема-Якоби: любая программа может быть построена из 3х базовых управляющих структур (следования, выбора или ветвления, повторения). Для наглядного представления программы используют графы (блок-схемы). Сущ несколько видов узлов:
- функциональные узлы представляют вычисления, производимые программой
- узел принятия решения представляет условие, от выполнения которого зависит
дальнейший порядок программы (истина – ложь)
- узел соединения объединяет 2 входящих дуги в одну исходящую.
Узлы графов наз блоками, а дуги – линии связи. Важной особенностью структур явл то, что каждая из них имеет 1 вход и 1 выход, структуры могут вкладываться друг в друга и независимо от глубины вложенности, могут быть представлены в виде следования, состоящего из 1 действия. При разработке программы выполняется обратный процесс – вложенные структуры разворачиваются. Это наз нисходящим проектированием программы (сверху вниз).
Структура следования: { <s1>; - объявления и операторы
<s2>; …
<s3>; }
Структура ветвления реализуется уловным оператором: if (<p>) <s1>; - <p> условие
Else <s2>; - операторы
В соответствии с принципами структурного программирования программа представляет собой структуру следования, т.е. описывается составным оператором (посл-ть объявлений и операторов, заключенные в фигурные скобки. Каждое объявление и оператор заканчивается ; ). Порядок выполнения: операторы, входящие в состав составного оператора, выполняются в порядке их следования в тексте программы.
Оператор-переключатель (switch) применяется для реализации ветвлений особого вида. Применение в таких случаях условного оператора (if) приводит к громоздким программам.
Синтаксически оператор-переключатель записывается в следующем виде:
switch (<e>) { где switch (переключить),
case <зн.1>: <S1>; case (случай), default (отсутствие) - служебные слова;
case <зн.2>: <S2>; <e> - выр-е цел или симв типов, наз переключатель;
<зн.1>, …, <зн.n> - константы или константные выр-я, значения
case <зн.k>: <Sk>; которых различны и входят в мн-во значений переключателя;
<S1>, <S2>, <Sn+1> - оператор или операторы, разделенных (;).
case <зн.n>: <Sn>;
default <Sn+1> }
Служебное слово default и следующие за ним операторы <Sn+1> могут отсутствовать.
Порядок выполнения: вычисляется значение переключателя <e> и поочередно сравнивается со значениями <зн.1>, <зн.2>, …, <зн.k>, … на совпадение. Если совпадение обнаружено, например, со значением <зн.k> , то выполняются операторы <Sk>, <Sk+1>, …, <Sn>, <Sn+1>. Если же совпадение не обнаружено, то выполняются операторы <Sn+1>, указанные после служебного слова default, или выполняется следующий оператор программы, если эта часть оператора отсутствует.
Средства структурного программирования в С и С++. Цикл. Реализация в С и С++: операторы цикла с предусловием (while) и постусловием (do), оператор цикла с параметром (for).
Составной оператор(блок) реализует структуру следования и представляет собой последовательность объявлений и операторов, заключённую в фигурные скобки { }. Каждое объявление и оператор в последовательности завершается “;”.
{ <S1>;
<S2>;
<S3>;
…
<Sn>;
}
Где <S1>; <S2>; …<Sn>; - объявления и операторы
Порядок выполнения(семантика): операторы,
входящие в состав составного оператора, выполняются
в порядке их следования в тексте программы. В общем случае Си-программа, как алгоритм, предст.собой совокупность вызывающих друг друга функций, среди которых обязательно должна быть функция с именем main(главный) , с которой и начинается её выполнение . Простая Си-программа может состоять только из этой функции, начинающейся с заголовка вида main( ), за которым следует описание алгоритма, реализуемого программой, и в соответствии с принципами структурного программирования предст.соб. структуру следования, т.е. описывается составным оператором.
Цикл – последовательность действий, которая выполняется неоднократно, до тех пор пока выполняется некоторое условие.
Оператор цикла с предусловием реализует алгоритмическую структуру цикл с предусловием. While (<P>) <S>; где <P> - выражение, описывающее условие продолжения цикла; <S> - оператор, описывающий тело цикла. Порядок выполнения(семантика) оператора: вычисляется выражение <P>, если его значение не равно 0, то выполняется оператор <S>, затем снова вычисляется выражение <P>, и так до тех пор , пока выражение <P> не примет значение 0. Другими словами, пока(while) значение выражения <P> не равно 0, выполняется оператор <S>. Выражение <P> как правило является логическим. Т.к. вычисление выражения <P> и выполнение оператора <S> производится многократно, то программировать их нужно как можно эффективнее.
Оператор цикла с постусловием. Do <S> while (<P>); <S> - оператор, описывающий тело цикла, <P> - выражение, описывающее условие продолжения цикла. Порядок выполнения: 1) выполняется оператор <S> и вычисляется выражение <P>; 2) если его значение не равно 0(истинно), то выполняется оператор <S> и так до тех пор, пока выражение <P> не примет значение 0. Другими словами, выполняется (do) оператор <S> пока(while) значение <P> 0. Оператор <S> выполняется по крайней мере 1 раз; выражение <P> - логическое. Т.к. выполнение оператора <S> и вычисление выражения <P> производится многократно, то программировать их нужно как можно эффективнее.
Оператор цикла с параметром. Все предыдущие операторы Си реализуют базовые алгоритмические структуры следования, ветвления, цикл, а значит, используя только их и средства рекурсии можно написать любую программу. Язык Си предлагает ряд дополнительных операторов. К ним относится оператор цикла с параметром. For (<инициализация>; <P>;<итерация>) <S>; где <инициализация>, <P>, <итерация> - выражения; <S> - оператор. Порядок выполнения: вычисляется выражение <инициализация>, затем <P>, и если его значение не равно 0, то выполняется оператор <S>, после чего вычисляется выражение <итерация> и опять вычисляется выражение <P> и если его значение не равно 0, то выполняется оператор <S>, после чего опять вычисляется выражение <итерация> и выражение <P> и т.д. до тех пор, пока выражение <P> не примет значение 0. Обычно при организации такого цикла выбирается переменная, называемая управляющей переменной цикла, или параметром цикла. Выражение <инициализация> присваивает этой переменной начальное значение, выражение <итерация> изменяет её значение, а выражение <P> определяет при каком значении этой переменной (конечное значение) цикл должен завершиться. Как правило, выражение <инициализация> и <итерация> содержат операцию присваивания, изменяющую значение параметра цикла, а выражение <P> является логическим. Блок-схема:
18. Понятие подпрограммы я С и С++. Функция. Параметры функции. Механизм передачи параметров. Рекурсия.
В программировании типичной является ситуация, когда в разных местах одной и той же программы, или в разных программах приходится выполнить один и тот же фрагмент алгоритма. Поэтому в каждом языке программирования предоставляются средства для выделения некоторого фрагмента алгоритма в самостоятельную программную единицу, называемую подпрограммой. Принципы программирования на Си основаны на понятии подпрограммы, которая реализуется в нём как функция (в других языках это функции и/или процедуры). И программа на Си предст.собой совокупность таких функций. Описание функций в Си начинается с заголовка, за которым следует тело функции. Заголовок функции имеет вид: <модификатор> <тип> <имя> (<список параметров>) <объявления параметров>; где <имя> – имя функции, задаваемое идентификатором (в Си принято именовать функции строчными буквами); (<список параметров>) – список имён параметров(формальных параметров), задаваемых идентификаторами и разделённых запятой (может быть пустым); <объявления параметров> - объявления параметров, перечисленных в списке, аналогичные объявлениям простых переменных и структур; <тип> - тип возвращаемого функции значения; <модификатор> в заголовке функции может отсутствовать. Кроме того, тип функции можно не указывать, если это тип int. Например, функция c заголовком main( ), т.е. описанная функция имеет имя main, пустой <список параметров> и тип <int>. Тело функции описывает реализуемый функцией алгоритм и предст.собой блок(составной оператор), т.е. последовательность объявлений и операторов, заключённая в { }. Возвращаемое функции значение определяется выражением в операторе возврата return, который имеет вид: return(<выражение>); Выражение вместе с ограничивающими его скобками может отсутствовать.
Для того чтобы в программе выполнился фрагмент алгоритма реализуемой функции в соответствующее место помещают вызов функции вида: <имя>(<список значений параметров>), где имя – имя функции, список значений параметров - перечень значений для формальных параметров функции, при которых функция должна быть выполнена. Скобки, ограничивающие список значений параметров(фактических параметров) в Си считаются знаком операции – “вызов функции”( ), а поэтому должны всегда присутствовать при вызове функции, даже если список её параметров пуст. “Вызов функции” наряду с др. операциями используется в выражениях и производится след.образом: параметры функции получают значения, указанные при вызове функции, выполняется тело функции и если при этом был выполнен оператор возврата return, то выполнение функции завершается и вычисленное значение выражения оператор возврата return, преобразованное к типу функции (если это необходимо), является значением функции. Если выражение в операторе возврата отсутствует или такой оператор вообще не выполнялся, то возвращаемое функции значение является неопределённым.
Значения параметров по умолчанию и примеры функций с переменным числом параметров(в Си++, в Си – нету).
Рекурсия – один из основных принципов программирования, реализующий управляющую структуру программирования. Это объясняется рекурсивной природой многих практических задач. Рекурсия имеет место тогда, когда решение задачи сводится к ней же, но для других исходных данных. Следующая математическая формула вычисления факториала неотрицательного целого числа рекурсивна.
В языках программирования рекурсия реализуется возможностью вызова подпрограммой самой себя. Такие подпрограммы называют рекурсивными, а процесс их выполнения- рекурсией. Цикл можно рассматривать как частный случай рекурсии и любой циклический алгоритм может быть заменён рекурсивным. При программировании рекурсии, как и цикла, есть опасность их бесконечного выполнения. А поэтому программируя рекурсию, всегда нужно помнить об условии её окончания. Реализуя рекурсивный алгоритм, нужно помнить, что каждый вызов функции требует времени на создание фрейма активации и размещения автоматических переменных и место в программном стэке для их размещения. Си допускает и косвенную рекурсию, при которой функция fn1, например, вызывает функцию fn2, а та в свою очередь опять fn1. Косвенная рекурсия требует обращения к функции, описанной ниже. В Си эта проблема решается объявлением функции.
17. Потоковый ввод-вывод в С и С++. Особенности реализации.
С++ предлагает для организации ввода-вывода тот же механизм управления потоками, что и Си. Но реализация его в С++ обладает рядом преимуществ. Средства потокового ввода-вывода С++ включены в стандартную библиотеку классов и доступны через заголовочные файлы: <iostream>(<iostream.h>) – для системных устройств, обычно клавиатуры и дисплея, <fstream>(<fsteam.h>) – для файлов, <iomanip>(<iomanip.h>) – для форматирования ввода-вывода. Основные средства потокового ввода-вывода реализованы в классах: ios – реализует понятие потока; istream – обеспечивает работу со входным потоком; ostream – обеспечивает работу с выходным потоком; iostream – обеспечивает доступ к потоку и для ввода и для вывода; ifstream – обеспечивает работу со входным потоком и с файлом; ofstream – обеспечивает работу с выходным потоком в файле; fstream – обеспечивает доступ к потоку, связанному с файлом и для ввода и для вывода. Эти классы образуют след.иерархию наследования:
Используемое в этой иерархии классов множественное наследование называют ромбовидным, и допустимо оно только при virtual наследовании класса ios. Создание потока выполняется путём объявления объекта одного из классов либо istream, ostream либо fstream, в зависимости от его назначения. Предлагаемые для этого конструкторы предлагают создать объект поток, не открывая его, или открыть, указав при этом источник или приёмник и, возможно режим работы с ним. Открыть созданный, но не открытый объект-поток, можно применив к нему метод open, указав при этом источник или приёмник и один из возможных режимов работы с потоком, предусмотренных классом ios.
Если открытие потока по каким-то причинам не было выполнено, то объект-поток получит значение 0. Проверить, открыт ли поток, можно выполнив над ним перегруженную в классе ios и унаследованную др. классами операцию!, которая возвращает 0, если поток открыт и не 0 – в противном случае. Закрывается поток при уничтожении объекта-потока. Закрыть поток, не уничтожая его, можно применив к нему метод close. Библиотека С++ предлагает 4 открытых объекта-потока: 1) cin класса istream – системный поток для ввода 2) cout класса ostream – системный поток для вывода 3) cerr, 4)clog – класса ostream – небуферизованный и буферизованный потоки ошибок.
Чтение из потока и запись в поток выполняют функции-члены классов istream и ostream соответственно, которые унаследовали и их производные классы. Однако проще для этого использовать перегруженные в этих классах функции – операции >>(сдвиг вправо), <<(сдвиг влево), называемые «взять из потока» и «поместить в поток» соответственно. Эти операции перегружены для всех встроенных в язык типов и для строк стиля Си. Они возвращают ссылку на поток, для которого выполняется, и поэтому могут сцепляться. Операция >> возвращает нуль, если обнаружен признак конца потока. Проверить достигнут ли конец потока можно и применив к нему функцию-член eof без параметров, которая возвращает нуль, если конец потока не обнаружен и не нуль – в противном случае.
13. Алгоритмы поиска. Основные понятия. Линейный и двоичный (бинарный) поиск. Алгоритмы сортировки. Основные понятия. Внутренние мортировки.
Поиск применяется тогда, когда в некоторой совокупности объектов данных произвольной, но одной и той же природы, требуется найти объект данных с заданными свойствами, которые называют ключом поиска(search key). Для выполнения поиска необходимо определить правило выделения в объектах данных ключа поиска и сравнение таких ключей для двух объектов данных. Наиболее естественными и простыми являются методы поиска, применяемые к совокупности объектов данных, образующих линейную последовательность. Такую совокупность можно разместить в массиве. Линейный поиск элементов массива (Linear Search) Рассмотрим сначала этот алгоритм для поиска элементов со значением равным k среди первых n элементов массива данных типа int. Для этого организуем последовательный просмотр элементов, начиная с 1-го, сравнивая каждый со значением k. Просмотр будем выполнять пока не обнаружится элемент со значением k или не будет достигнут последний из рассматриваемых элементов.
i=0;
while (i<n 88!(a[i]= =k))i++;
if (i<n) …; */элемент найден/*
else … ; */элемент не найден/*
Здесь значение переменной k задаёт ключ поиска, а выражение !(a[i]= =k) условие поиска, т.е. пока условие поиска не выполнено поиск продолжается. Этот алгоритм может быть обобщён для поиска в массиве с любым типом элементов элемента с заданными свойствами. В общем случае алгоритм линейного поиска элемента в массиве состоит в следующем: 1) элементы массива рассматриваются в порядке их следования, начиная с 1-го(или последнего) и сравниваются с заданным ключом поиска 2) если условие поиска для рассматриваемого элемента не выполняется , то рассматривается очередной элемент (следующий или предшествующий) и так до тех пор, пока не будет обнаружен элемент, удовлетворяющий условию поиска, или рассматриваемые элементы не будут исчерпаны.
Двоичный(бинарный) поиск(Binary Search) Применяется к массиву элементов, которые упорядочены по ключу поиска. Если элементы массива типа int упорядочены по возрастанию, то для поиска среди первых n его элементов элемента со значением k можно поступить след. образом: сравним заданное значение k со средним (1-им из средних) элементом рассматриваемой части массива. Если k окажется больше него, то поиск следует продолжить среди элементов, следующих за ним, иначе – среди элементов, следующих до него. К выбранной части массива применим этот же метод. Завершим этот процесс, когда в рассматриваемой части массива окажется 1 элемент, который и должен оказаться искомым, иначе – искомый элемент отсутствует в массиве. Этот алгоритм предполагает выполнение над элементами массива операций отношения (>,<,=). Отношение порядка – это бинарное отношение, определённое на некотором множестве А, обладающее свойствами: 1) рефлексивность 2) транзитивность 3) антисимметричность
В общем случае, алгоритм двоичного поиска состоит в следующем: заданный ключ поиска сравнивается в соответствии с заданным отношением порядка со средним (1 из средних) элементов рассматриваемой части массива и выясняется, где должен продолжаться поиск: среди элементов, следующих за средним или до него. К выбранной части массива применяется тот же метод. Завершается этот процесс, когда в рассматриваемой части массива останется 1 элемент, который может оказаться искомым. В противном случае – искомый элемент отсутствует.
Метод двоичного поиска эффективнее линейного, но применяется только тогда, когда элементы в массиве упорядочены по ключу поиска.