Лекция 2:
Абстрактные типы данных.
Алгоритмы сортировки
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://mkurnosov.net/teaching
Контроль
2
1. Что такое вычислительная сложность алгоритма
(computational complexity)?
2. T(n) = 3n3 + 2n2, O(3n3 + 2n2) = …. ?
3. T(n) = n + logn, O(n + logn) = …. ?
4. T(n) = nlogn + n2, O(nlogn + n2 ) = …. ?
5. T(n) = 2n + n6 – 1000n3, O(2n + n6 – 1000n3) = …. ?
6. T(n) = n6 + n!, O(n6 + n!) = …. ?
7. Какой асимтотической вычислительной сложностью обладает
алгоритм сортировки методом “пузырька”?
8. Какой асимтотической вычислительной сложностью обладает
алгоритм вычисления факториала числа?
Содержание лекции
3
1. Понятие абстрактного типа данных (АТД)
2. Массивы
3. Алгоритмы сортировки массивов
Абстрактные типы данных
4
Абстрактный тип данных (Abstract Data Type) – это тип
данных, который предоставляет набор функций для работы с
его элементами.
Клиентские программы не имеют доступа к внутренней
реализации типа данных (реализация сокрыта –
инкапсулирована).
Тип данных переменной (Data Type) – множество
значений, которые она может принимать (int, char,
double, float).
Абстрактный тип данных “множество” (Set)
5
Набор операций определенных над элементами абстрактного типа
данных “множество” (Set):
MakeNull(a) – делает множество a пустым
Size(a) – возвращает количество элементов во множестве a (мощность
множества)
Union(a, b, c) – объединяет множеств a и b в множество с
Intersect(a, b, c) – строит пересечение множеств a и b, результат
помещается в множество с
Minus(a, b, c)
Add(a, x) – добавляет элемент x к множеству a
IsIncluded(a, x) – определяет принадлежит ли элемент x множеству a
…
Операция Описание Вычислительная
сложность
Сложность
по памяти
Get(a, i) Возвращает i-й элемент
массива a
O(1) O(1)
Set(a, i, x) Присваивает i-у
элементу массива a
значение x
O(1) O(1)
Size(a) Возвращает количество
элементов в массиве a
O(1) O(1)
Sort(a) Упорядочивает
элементы массива а по
не убыванию
O(n2),
O(nlogn),
O(n + r)
O(1),
O(logn),
O(n), O(n + r)
Search(a, x) Отыскивает позицию
элемента x в массиве a
O(n), O(logn)
Абстрактный тип данных массив (Array)
6
Набор операций определенных над элементами абстрактного типа
данных массив (Array):
#define NELEMS 1024
typedef int elem_t;
elem_t array_get(elem_t *a, int i)
{
return a[i];
}
void array_set(elem_t *a, int i, elem_t x)
{
a[i] = x;
}
int array_size(elem_t *a)
{
return NELEMS;
}
Реализация АТД массив (Array)
7
Алгоритмы сортировки (Sorting)
8
Внутренние методы сортировки – элементы размещены
в оперативной памяти компьютера
Внешняя сортировка – элементы размещены на внешней памяти
(жесткий диск, USB-флеш, …)
Алгоритм сортировки не использующий дополнительной
памяти (кроме сортируемого массива) называется алгоритмом
сортировки на месте (in place)
Алгоритм сортировки не меняющий порядок следования равных
элементов называется устойчивым (stable)
(Жираф, 800), (Слон, 1500), (Лиса, 40), (Волк, 90), (Кит, 3000), (Барсук, 40)
(Барсук, 40), (Лиса, 40), (Волк, 90), (Жираф, 800), (Слон, 1500),
(Кит, 3000) – порядок не соблюден
(Лиса, 40), (Барсук, 40), (Волк, 90), (Жираф, 800), (Слон, 1500),
(Кит, 3000) – порядок соблюден
Алгоритмы сортировки (Sorting)
9
Типы алгоритмов сортировки:
Алгоритмы на основе сравнений (Comparison sort):
Bubble Sort, Selection Sort, Insertion Sort, Shell Sort, QuickSort,
MergeSort, HeapSort и др.
Алгоритмы не основанные на сравнениях:
Counting Sort, Radix Sort – используют структура ключа.
Утверждение. Любой алгоритм сортировки, основанный на
сравнениях, имеет асимптотическую вычислительною сложность
Ω(nlogn)
Вычислительная сложность сортировки
10
Алгоритм Лучший
случай
Средний
случай
Худший
случай
Память Свойства
Пузырьковая
сортировка
(Bubble sort)
O(n) O(n2) O(n2) O(1) Устойчивый,
“на месте”
Сортировка
вставками
(Insertion Sort)
O(n) O(n2) O(n2) O(1) Устойчивый,
“на месте”,
online
Сортировка
выбором
(Selection Sort)
O(n2) O(n2) O(n2) O(1) Неустойчивый,
“на месте”
Сортировка
Шелла
(Shell Sort)
O(n) O(n(logn)2),
O(n32)
O(n32) O(1) Неустойчивый,
“на месте”
Быстрая
сортировка
(Quick Sort)
O(nlogn) O(nlogn) O(n2) O(logn) Устойчивость
зависит от
реализации
“Пузырьковая” сортировка (Bubble Sort)
11
function BubbleSort(v[0:n - 1], n)
swapped = True
while swapped do
swapped = False
for i = 1 to n - 1 do
if v[i - 1] > v[i] then
swap(v[i - 1], v[i])
swapped = True
end if
end for
end while
end function
9
5
54
23
45
2
4
4
42
34
“Легкие” элемент перемещаются (поднимаются)
в начало массива (вверх)
Сортировка вставками (Insertion Sort)
12
function InsertionSort(v[1:n], n)
v[0] = Infinity
for i = 2 to n do
j = i
while v[j - 1] > v[j] do
swap(v[j - 1], v[j])
j = j - 1
end while
end for
end function
Элемент v[i] перемещается в требуемую позицию
уже упорядоченного массива: v[1], v[2], …, v[i – 1]
Inf 15 2 35 88 4 17 23 62 13
j = 2
Быстрая сортировка (Quick Sort)
13
1. Из элементов v[1], v[2], …, v[n] выбирается опорный элемент (pivot).
Элемент желательно выбирать так, чтобы его значение было близко
к среднему значению всех элементов
Вопрос о выборе опорного элемента открыт (первый, средний из
трех, случайный и т.д.)
2. Массив разбивается на 2 части: элементы массива переставляются
так, чтобы элементы расположенные левее опорного были меньше
него, а расположенные правее – больше него.
На этом шаге определяется граница разбиения массива.
3. Шаги 1 и 2 рекурсивно повторяются для левой и правой частей
Быстрая сортировка (Quick Sort)
14
function Partition(v[1:n], n, l, r)
pivot_idx = r /* Выбрали индекс опорного элемента */
swap(v[pivot_idx], v[r])
pivot = v[r]
i = l – 1
for j = l to r – 1 do
if v[j] <= pivot then
i = i + 1
swap(v[i], v[j])
end if
end for
swap(v[i + 1], v[r])
return i + 1
end function
2 8 7 1 3 5 6 4
l = 1
i = 0
r = n
pivot = 4
2 1 7 8 3 5 6 4
j = 1: swap(v[1], v[1])
j = 4: swap(v[2], v[4])
j = 5: swap(v[3], v[5])
2 1 3 8 7 5 6 4
swap(v[4], v[8])
2 1 3 4 7 5 6 8
return 4
Быстрая сортировка (Quick Sort)
15
function QuickSort(v[1:n], n, l, r)
if l < r then
k = Partition(v, n, l, r)
QuickSort(v, n, l, k - 1)
QuickSort(v, n, k + 1, r)
end if
end function
QuickSort(1, n)
QuickSort(l, k – 1) QuickSort(k + 1, r)
Сортировка подсчетом (Counting Sort)
16
Сортировка подсчетом (Counting Sort) – алгоритм
сортировки не использующий операцию сравнения элементов
(non-comparision sort).
Применим к массивам, сортируемые элементы которых
принимают неотрицательные целочисленные значения и не
превосходят значения k.
Алгоритм Лучший
случай
Средний
случай
Худший
случай
Память Свойства
Сортировка
подсчетом
(Counting Sort)
n + k n + k n + k Устойчивый
Сортировка подсчетом (Counting Sort)
17
function CountingSort(v[0:n - 1], n, k)
for i = 0 to k – 1 do
c[i] = 0
end for
for i = 0 to n – 1 do
c[v[i]] = c[v[i]] + 1
end for
for i = 1 to k – 1 do
c[i] = c[i] + c[i - 1]
end for
for i = n - 1 to 0 do
c[v[i]] = c[v[i]] - 1
b[c[v[i]]] = v[i]
end for
2 11 7 1 3 5 6 3
n = 8, k = 11
0 1 1 2 0 1 1 1 0 0 0 1
c[0:k]:
0 1 2 4 4 5 6 7 7 7 7 1
c[0:k]:
b[0:n-1]:
Сортировка подсчетом (Counting Sort)
function CountingSort(a[0:n-1])
for i = 0 to k – 1 do
c[i] = 0
end for
for i = 0 to n – 1 do
c[a[i]] = c[a[i]] + 1
end for
b = 0
for j = 0 to k – 1 do
for i = 0 to c[j] – 1 do
a[b] = j
b = b + 1
end for
end for
end function
Ограничения: входной массив a[0:n–1] содержит целые числа
от 0 до k – 1
18
9
5
54
9
45
2
4
4
42
34
n = 10
k = 55
Сортировка подсчетом (Counting Sort)
function CountingSort(a[0:n-1])
for i = 0 to k – 1 do
c[i] = 0
end for
for i = 0 to n – 1 do
c[a[i]] = c[a[i]] + 1
end for
b = 0
for j = 0 to k – 1 do
for i = 0 to c[j] – 1 do
a[b] = j
b = b + 1
end for
end for
end function
Ограничения: входной массив a[0:n–1] содержит целые числа
от 0 до k – 1
19
9
5
54
9
45
2
4
4
42
34
n = 10
k = 55
TCountingSort = Θ(n + k)
Задание
20
Доказательство асимптотической сложности пузырьковой
сортировки в худшем и среднем случаях (McConnell2004,
C.77-80).
Анализ вычислительной сложности алгоритма быстрой
сортировки (Aho2000, C. 238-243).

Лекция 2: Абстрактные типы данных. Алгоритмы сортировки

  • 1.
    Лекция 2: Абстрактные типыданных. Алгоритмы сортировки Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://mkurnosov.net/teaching
  • 2.
    Контроль 2 1. Что такоевычислительная сложность алгоритма (computational complexity)? 2. T(n) = 3n3 + 2n2, O(3n3 + 2n2) = …. ? 3. T(n) = n + logn, O(n + logn) = …. ? 4. T(n) = nlogn + n2, O(nlogn + n2 ) = …. ? 5. T(n) = 2n + n6 – 1000n3, O(2n + n6 – 1000n3) = …. ? 6. T(n) = n6 + n!, O(n6 + n!) = …. ? 7. Какой асимтотической вычислительной сложностью обладает алгоритм сортировки методом “пузырька”? 8. Какой асимтотической вычислительной сложностью обладает алгоритм вычисления факториала числа?
  • 3.
    Содержание лекции 3 1. Понятиеабстрактного типа данных (АТД) 2. Массивы 3. Алгоритмы сортировки массивов
  • 4.
    Абстрактные типы данных 4 Абстрактныйтип данных (Abstract Data Type) – это тип данных, который предоставляет набор функций для работы с его элементами. Клиентские программы не имеют доступа к внутренней реализации типа данных (реализация сокрыта – инкапсулирована). Тип данных переменной (Data Type) – множество значений, которые она может принимать (int, char, double, float).
  • 5.
    Абстрактный тип данных“множество” (Set) 5 Набор операций определенных над элементами абстрактного типа данных “множество” (Set): MakeNull(a) – делает множество a пустым Size(a) – возвращает количество элементов во множестве a (мощность множества) Union(a, b, c) – объединяет множеств a и b в множество с Intersect(a, b, c) – строит пересечение множеств a и b, результат помещается в множество с Minus(a, b, c) Add(a, x) – добавляет элемент x к множеству a IsIncluded(a, x) – определяет принадлежит ли элемент x множеству a …
  • 6.
    Операция Описание Вычислительная сложность Сложность попамяти Get(a, i) Возвращает i-й элемент массива a O(1) O(1) Set(a, i, x) Присваивает i-у элементу массива a значение x O(1) O(1) Size(a) Возвращает количество элементов в массиве a O(1) O(1) Sort(a) Упорядочивает элементы массива а по не убыванию O(n2), O(nlogn), O(n + r) O(1), O(logn), O(n), O(n + r) Search(a, x) Отыскивает позицию элемента x в массиве a O(n), O(logn) Абстрактный тип данных массив (Array) 6 Набор операций определенных над элементами абстрактного типа данных массив (Array):
  • 7.
    #define NELEMS 1024 typedefint elem_t; elem_t array_get(elem_t *a, int i) { return a[i]; } void array_set(elem_t *a, int i, elem_t x) { a[i] = x; } int array_size(elem_t *a) { return NELEMS; } Реализация АТД массив (Array) 7
  • 8.
    Алгоритмы сортировки (Sorting) 8 Внутренниеметоды сортировки – элементы размещены в оперативной памяти компьютера Внешняя сортировка – элементы размещены на внешней памяти (жесткий диск, USB-флеш, …) Алгоритм сортировки не использующий дополнительной памяти (кроме сортируемого массива) называется алгоритмом сортировки на месте (in place) Алгоритм сортировки не меняющий порядок следования равных элементов называется устойчивым (stable) (Жираф, 800), (Слон, 1500), (Лиса, 40), (Волк, 90), (Кит, 3000), (Барсук, 40) (Барсук, 40), (Лиса, 40), (Волк, 90), (Жираф, 800), (Слон, 1500), (Кит, 3000) – порядок не соблюден (Лиса, 40), (Барсук, 40), (Волк, 90), (Жираф, 800), (Слон, 1500), (Кит, 3000) – порядок соблюден
  • 9.
    Алгоритмы сортировки (Sorting) 9 Типыалгоритмов сортировки: Алгоритмы на основе сравнений (Comparison sort): Bubble Sort, Selection Sort, Insertion Sort, Shell Sort, QuickSort, MergeSort, HeapSort и др. Алгоритмы не основанные на сравнениях: Counting Sort, Radix Sort – используют структура ключа. Утверждение. Любой алгоритм сортировки, основанный на сравнениях, имеет асимптотическую вычислительною сложность Ω(nlogn)
  • 10.
    Вычислительная сложность сортировки 10 АлгоритмЛучший случай Средний случай Худший случай Память Свойства Пузырьковая сортировка (Bubble sort) O(n) O(n2) O(n2) O(1) Устойчивый, “на месте” Сортировка вставками (Insertion Sort) O(n) O(n2) O(n2) O(1) Устойчивый, “на месте”, online Сортировка выбором (Selection Sort) O(n2) O(n2) O(n2) O(1) Неустойчивый, “на месте” Сортировка Шелла (Shell Sort) O(n) O(n(logn)2), O(n32) O(n32) O(1) Неустойчивый, “на месте” Быстрая сортировка (Quick Sort) O(nlogn) O(nlogn) O(n2) O(logn) Устойчивость зависит от реализации
  • 11.
    “Пузырьковая” сортировка (BubbleSort) 11 function BubbleSort(v[0:n - 1], n) swapped = True while swapped do swapped = False for i = 1 to n - 1 do if v[i - 1] > v[i] then swap(v[i - 1], v[i]) swapped = True end if end for end while end function 9 5 54 23 45 2 4 4 42 34 “Легкие” элемент перемещаются (поднимаются) в начало массива (вверх)
  • 12.
    Сортировка вставками (InsertionSort) 12 function InsertionSort(v[1:n], n) v[0] = Infinity for i = 2 to n do j = i while v[j - 1] > v[j] do swap(v[j - 1], v[j]) j = j - 1 end while end for end function Элемент v[i] перемещается в требуемую позицию уже упорядоченного массива: v[1], v[2], …, v[i – 1] Inf 15 2 35 88 4 17 23 62 13 j = 2
  • 13.
    Быстрая сортировка (QuickSort) 13 1. Из элементов v[1], v[2], …, v[n] выбирается опорный элемент (pivot). Элемент желательно выбирать так, чтобы его значение было близко к среднему значению всех элементов Вопрос о выборе опорного элемента открыт (первый, средний из трех, случайный и т.д.) 2. Массив разбивается на 2 части: элементы массива переставляются так, чтобы элементы расположенные левее опорного были меньше него, а расположенные правее – больше него. На этом шаге определяется граница разбиения массива. 3. Шаги 1 и 2 рекурсивно повторяются для левой и правой частей
  • 14.
    Быстрая сортировка (QuickSort) 14 function Partition(v[1:n], n, l, r) pivot_idx = r /* Выбрали индекс опорного элемента */ swap(v[pivot_idx], v[r]) pivot = v[r] i = l – 1 for j = l to r – 1 do if v[j] <= pivot then i = i + 1 swap(v[i], v[j]) end if end for swap(v[i + 1], v[r]) return i + 1 end function 2 8 7 1 3 5 6 4 l = 1 i = 0 r = n pivot = 4 2 1 7 8 3 5 6 4 j = 1: swap(v[1], v[1]) j = 4: swap(v[2], v[4]) j = 5: swap(v[3], v[5]) 2 1 3 8 7 5 6 4 swap(v[4], v[8]) 2 1 3 4 7 5 6 8 return 4
  • 15.
    Быстрая сортировка (QuickSort) 15 function QuickSort(v[1:n], n, l, r) if l < r then k = Partition(v, n, l, r) QuickSort(v, n, l, k - 1) QuickSort(v, n, k + 1, r) end if end function QuickSort(1, n) QuickSort(l, k – 1) QuickSort(k + 1, r)
  • 16.
    Сортировка подсчетом (CountingSort) 16 Сортировка подсчетом (Counting Sort) – алгоритм сортировки не использующий операцию сравнения элементов (non-comparision sort). Применим к массивам, сортируемые элементы которых принимают неотрицательные целочисленные значения и не превосходят значения k. Алгоритм Лучший случай Средний случай Худший случай Память Свойства Сортировка подсчетом (Counting Sort) n + k n + k n + k Устойчивый
  • 17.
    Сортировка подсчетом (CountingSort) 17 function CountingSort(v[0:n - 1], n, k) for i = 0 to k – 1 do c[i] = 0 end for for i = 0 to n – 1 do c[v[i]] = c[v[i]] + 1 end for for i = 1 to k – 1 do c[i] = c[i] + c[i - 1] end for for i = n - 1 to 0 do c[v[i]] = c[v[i]] - 1 b[c[v[i]]] = v[i] end for 2 11 7 1 3 5 6 3 n = 8, k = 11 0 1 1 2 0 1 1 1 0 0 0 1 c[0:k]: 0 1 2 4 4 5 6 7 7 7 7 1 c[0:k]: b[0:n-1]:
  • 18.
    Сортировка подсчетом (CountingSort) function CountingSort(a[0:n-1]) for i = 0 to k – 1 do c[i] = 0 end for for i = 0 to n – 1 do c[a[i]] = c[a[i]] + 1 end for b = 0 for j = 0 to k – 1 do for i = 0 to c[j] – 1 do a[b] = j b = b + 1 end for end for end function Ограничения: входной массив a[0:n–1] содержит целые числа от 0 до k – 1 18 9 5 54 9 45 2 4 4 42 34 n = 10 k = 55
  • 19.
    Сортировка подсчетом (CountingSort) function CountingSort(a[0:n-1]) for i = 0 to k – 1 do c[i] = 0 end for for i = 0 to n – 1 do c[a[i]] = c[a[i]] + 1 end for b = 0 for j = 0 to k – 1 do for i = 0 to c[j] – 1 do a[b] = j b = b + 1 end for end for end function Ограничения: входной массив a[0:n–1] содержит целые числа от 0 до k – 1 19 9 5 54 9 45 2 4 4 42 34 n = 10 k = 55 TCountingSort = Θ(n + k)
  • 20.
    Задание 20 Доказательство асимптотической сложностипузырьковой сортировки в худшем и среднем случаях (McConnell2004, C.77-80). Анализ вычислительной сложности алгоритма быстрой сортировки (Aho2000, C. 238-243).