Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теорминимум.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
141.82 Кб
Скачать
  1. Как можно выделить память?

Статическое выделение памяти: пространство для объектов создаётся в области хранения данных кода программы в момент компиляции; время жизни таких объектов совпадает со временем жизни этого кода. static int arr[5];

Автоматическое выделение памяти: объекты можно временно хранить в стеке; эта память затем автоматически освобождается и может быть использована снова, после того, как программа выходит из блока, использующего её. int arr[5]; //в теле функции/метода

Динамическое выделение памяти: блоки памяти нужного размера могут запрашиваться во время выполнения программы с помощью библиотечных функций malloc, realloc и free из области памяти, называемой кучей. Эти блоки освобождаются и могут быть использованы снова после вызова для них функции free. int *arr = new int[5];

_______________________________________________________________________________

  1. Как можно освободить память?

С помощью free(delete).

  1. Как проверить, что память выделилась?

Пример: … int *buf;

buf = NULL;

buf = (int*)malloc(n*sizeof(int));

if (buf == NULL)

malloc возвращает пустой указатель на выделенное пространство или NULL, если недостаточно доступной памяти.

_______________________________________________________________________________

  1. Как создать массив на стеке? Любой ли массив можно создать на стеке?

Int arr[10];

Создали массив из 10 целочисленных элементов.

Размер массива ограничивается размером стека.

________________________________________________________________________________

  1. Что такое "выделение памяти в куче"?

Ку́ча — структура данных, с помощью которой реализована динамически распределяемая память приложения. Память в куче используется для размещения объектов, динамически созданных программой.

В любой момент времени существования кучи вся память, на которой работает куча, разделена на занятую и свободную. Занятая память использована под размещение объектов, уже созданных и ещё не освобождённых к этому моменту времени. Из объёма свободной памяти можно выделять память под новые объекты.

Int* p = new int[s]; - выделение памяти в куче Delete[] p; - удаление данных из кучи

______________________________________________________________________________

  1. Как получить значение, на которое указывает указатель? Как называется эта операция?

Получить само значение переменной, на который указывает указатель, можно только выполнив операцию разыменовывания *.

int n = 1;

int *pn = 0;

pn = &n;

cout << *pn;

______________________________________________________________________________

  1. Какой тип получается при взятии адреса переменной?

&a - получение указателя (взятие адреса) тип - *тип_переменной_а (указатель на тип переменной а)

_______________________________________________________________________________

  1. Напишите функцию swap, меняющую значения двух переменных.

Void swap (int &a, int &b) { int t=a; a=b; b=t; }

  1. Что такое передача аргументов по ссылке и по значению?

Если мы передаем переменную по значению, то в функции используется копия этой самой переменной. Для передачи по значению пишем просто void f (int a)

Если мы передаем переменную по ссылке, то в функции мы работаем с самой переменной. Для передачи по ссылке пишем void g (int& a)

______________________________________________________________________________

Ввод-вывод

  1. Какие функции для форматированного ввода из файла Вы знаете?

FILE *f; f=fopen(f"file.txt", "r"); fscanf(f, “%d”, &i); fclose(f);

_______________________________________________________________________________

  1. Какие функции для форматированного вывода в файл Вы знаете?

FILE *f; f=fopen("file.txt", "w"); fprintf(f, “%d”, i); fclose(f);

_______________________________________________________________________________

  1. Какие функции для форматированного чтения из стандартного потока ввода Вы знаете?

Считать из стандартного потока ввода целочисленную переменную i: C: scanf("%d", &i); C++: cin>>i;

_______________________________________________________________________________

  1. Какие функции для форматированного вывода в стандартный поток вывода Вы знаете?

Вывести в стандартный поток вывода целочисленную переменную i: C: printf("%d", i); C++: cout<<i;

_______________________________________________________________________________

  1. Как прочитать один символ из стандартного потока ввода?

char a=getchar(); char b=cin.get();

_______________________________________________________________________________

  1. Как открыть файл для записи?

f=fopen("file.txt", "w");

_______________________________________________________________________________

  1. Как закрыть файл после завершения записи?

fclose(f);

  1. Как считать строку?

Сhar sym = getchar(); char str[1000]; int len = 0; for (int i=0; sym!= ‘ ‘; i++, len++) {str[i]=sym; sym=getchar();}

  1. Как вывести строку?

for (int i = 0; i<len; i++) printf(“%c”, str[i]); или str[len] = 0; printf(“%s”, str);

_______________________________________________________________________________

Общее по алгоритмам

  1. Какие нотации используют для обозначения сложности алгоритмов?

T(n) – время работы алгоритма, тогда

f(n)=Θ(g(n)) означает, что найдутся такие константы c1>0 и с2>0 и n0, что 0<=c1g(n)<=f(n)<=c2g(n) для всех n>=n0

f(n)=O(g(n)) означает, что найдется такая константа с>0 и n0, что 0<=f(n)<=cg(n) для всех n>=n0

f(n)=Ω(g(n)) означает, что найдется такая константа с>0 и n0, что 0<=cg(n)<=f(n) для всех n>=n0

Если к тому же при n , тогда

f(n)=о(g(n)) означает, что для всякого ε>0 найдется такое n0, что 0<=f(n)<=εg(n) при всех n>=n0

f(n)=ω(g(n)) означает, что для всякого с>0 найдется такое n0, что 0<=cg(n)<=f(n) при всех n>=n0

_______________________________________________________________________________

  1. Затраты каких ресурсов обычно меряют при оценке сложности?

Алгоритмы оцениваются по скорости выполнения и эффективности использования памяти

_______________________________________________________________________________

  1. Может ли алгоритм со сложностью O(n2) работать в практической задаче быстрее, чем алгоритм со сложностью O(n lоgn)?

Может. Пример: быстрая сортировка (nlogn) и сортировка пузырьком (n2) при отсортированном массиве

_______________________________________________________________________________

  1. Что такое рекурсия?

В программировании рекурсия — вызов функции (процедуры) из неё же самой.

_______________________________________________________________________________

  1. Какую опасность несет рекурсия?

Наиболее очевидная опасность рекурсии заключается в бесконечной рекурсии.

Другая опасность рекурсии заключается в потерях памяти. При каждом вызове подпрограммы, система выделяет память для локальных переменных новой процедуры.

_______________________________________________________________________________

  1. Покажите на примере, как можно избавиться от рекурсии.

n-ое число Фиббоначи можно вычислять как рекурсивным методом (с помощью рекурсии подсчитывая предыдщее число), а можно обычным циклом, считая числа Фиббоначи, начиная с первого.

_______________________________________________________________________________

  1. Оцените сложность алгоритма поиска простых чисел.

При простом переборе делителей O(n sqrt(n) )

  1. Примените основную теорему об оценках для оценки сложности сортировки слиянием.

T(n) = 2*T(n/2) + θ(n) Данная формула означает, что чтобы отсортировать массив из n элементов, нужно согласно алгоритму отсортировать две его половины(2*Т(n/2)) и слить в один массив за (θ(n)). Из основной теоремы об оценках получаем, что a=2, b=2, n^(log(b)a)=n^(log(2)2)=n=θ(n) и f(n)=θ(n). Подходит случай 2 теоремы об оценках, значит T(n)=θ(n*logn).

  1. Примените основную теорему об оценках для оценки сложности быстрой сортировки .

Для лучшего случая, когда каждый раз массив делится на две равные части, доказательство аналогично пункту 8, худший и средний случай смотри в Кормене с.154.

Сортировки

  1. В чем заключается задача сортировки?

Задача сортировки - упорядочивание элементов массива по неубыванию (или какому-то иному признаку)

_______________________________________________________________________________

  1. Какова наименьшая сложность алгоритма сортировки?

Сортировка сравнениями не может работать быстрее чем O (n log n)

_______________________________________________________________________________

  1. Какова сложность алгоритма сортировки пузырьком?

O(n2)

_______________________________________________________________________________

  1. Какова сложность алгоритма сортировки пузырьком в лучшем случае?

O (n) В том случае, когда массив уже отсортирован

_______________________________________________________________________________

  1. Какова сложность алгоритма сортировки Шелла?

Зависит от последовательности, которая используется в сортировке. В среднем O(n3/2) Последовательности и их сложность: Шелла: d1=N/2 di=di-1/2 dk=1 O(c n2) Хиббард: все (2i-1)/2 <= n/2 O(n3/2) Пратт: все 2i*3j<=n/2 O(n (log n)2 )

_______________________________________________________________________________

  1. Какова сложность алгоритма сортировки вставками?

Худший и средний случаи O(n2), лучший O(n)

_______________________________________________________________________________

  1. Какова сложность алгоритма быстрой сортировки?

O(n log n) в среднем и лучшем, O(n2) в худшем случае

  1. Какие оптимизации быстрой сортировки Вы знаете?

  • При выборе опорного элемента из данного диапазона случайным образом худший случай становится очень маловероятным и ожидаемое время выполнения алгоритма сортировки — O(n log n).

  • Выбирать опорным элементом средний из трех (первого, среднего и последнего элементов). Такой выбор также направлен против худшего случая.

  • Во избежание достижения опасной глубины рекурсии в худшем случае (или при приближении к нему) возможна модификация алгоритма, устраняющая одну ветвь рекурсии: вместо того, чтобы после разделения массива вызывать рекурсивно процедуру разделения для обоих найденных подмассивов, рекурсивный вызов делается только для меньшего подмассива, а больший обрабатывается в цикле в пределах этого же вызова процедуры. С точки зрения эффективности в среднем случае разницы практически нет: накладные расходы на дополнительный рекурсивный вызов и на организацию сравнения длин подмассивов и цикла — примерно одного порядка. Зато глубина рекурсии ни при каких обстоятельствах не превысит log2n, а в худшем случае вырожденного разделения она вообще будет не более 2 — вся обработка пройдёт в цикле первого уровня рекурсии.

  • Разбивать массив не на две, а на три части(меньше опорного элемента, равные опорному элементу, больше опорного элемента)

  • Из-за рекурсии и других "накладных расходов" Quicksort может оказаться не столь уж быстрой для коротких массивов. Поэтому, если в массиве меньше CUTOFF элементов (константа зависит от реализации, обычно равна от 3 до 40), вызывается сортировка вставками. Увеличение скорости может составлять до 15%.

_______________________________________________________________________________

  1. Какова сложность пирамидальной сортировки?

Во всех случаях O(n log n)

_______________________________________________________________________________

  1. Какова сложность сортировки слиянием?

Во всех случаях θ(n log n)

_______________________________________________________________________________

  1. Какова сложность поразрядной сортировки?

Во всех случаях O(dn+dk), где d – количество разрядов, k – основание системы счисления.

_______________________________________________________________________________

  1. Что такое задача выбора (k-я порядковая статистика)? Какова ее сложность?

k-ой порядковой статистикой набора элементов линейно упорядоченного множества называется такой его элемент, который является k-ым элементом набора в порядке сортировки.

В среднем случае работает за O(n), в худшем O(n n), в лучшем случае O(1).

  1. Какова сложность алгоритма бинарного поиска?

В среднем и худшем O(log n), в лучшем O(1)

_______________________________________________________________________________

  1. Можно ли применить алгоритм бинарного поиска к списку?

Нельзя, т.к. в списке каждый элемент ссылки только на последующий элемент или на соседние элементы.

_______________________________________________________________________________

Структуры данных

  1. Что такое структура?

Структура — конструкция программирования, позволяющая содержать в себе набор переменных различных типов, совокупность нескольких переменных, часто различных типов, сгруппированных под единым именем для удобства обращения.

_______________________________________________________________________________

  1. Как выделить массив структур?

struct key

{

char sym;

int num_in_alphabet;

};

key mass[1000];

или

key* m = NULL;

m = (key*)malloc(26*sizeof(key));

  1. Что такое список?

динамический список представляет из себя некоторое количество компонентов (узлов), содержащих непосредственно информационную часть (число, строка или более сложные типы данных), а также ссылку на следующий компонент (возможно, что узел содержит 2 ссылки: на следующий и на предыдущий, в таком случае, список называется двусвязным). 

_______________________________________________________________________________