Пирамидальная сортировка

advertisement
Двоичный поиск в упорядоченном массиве
33
0
1
2
3
1
3
4
8 10 14 16 21 24 27 31 33 36 38 42 44 50 51 53 59
l
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
m
private static int binSearch(int[] data, int key) {
int l = 0,
h = data.length-1;
while (l < h) {
int m = (l + h) / 2;
// (l <= m < h)
if (data[m] < key) l = m + 1; else h = m;
}
return (data[l] == key ? l : -1);
}
Инвариант цикла: l <= h && «если key == data[k], то l <= k <= h»
19
h
Сортировки массива
1. Сортировка «пузырьком»
public static void bubbleSort(int[] data) {
int n = data.length;
for (int i = 1; i < n; i++) {
for (int j = 0; j < n-i; j++) {
if (data[j] > data [j+1]) {
int tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
}
}
}
}
4 27 51 14 31 42 1
4 27 14 31 42 1
4 14 27 31 1
4 14 27 1
4 14 1
4
1
8 24 3 59 33 44 53 16 10 38 50 21 36
8 24 3 51 33 44 53 16 10 38 50 21 36 59
8 24 3 42 33 44 51 16 10 38 50 21 36 53 59
8 24 3 31 33 42 44 16 10 38 50 21 36 51 53 59
8 24 3 27 31 33 42 16 10 38 44 21 36 50 51 53 59
8 14 3 24 27 31 33 16 10 38 42 21 36 44 50 51 53 59
2. Сортировка простыми вставками
4 27 51 14 31 42 1
8 24 3 59 33 44 53 16 10 38 50 21 36
4 14 27 51 31 42 1
8 24 3 59 33 44 53 16 10 38 50 21 36
4 14 27 31 51 42 1
8 24 3 59 33 44 53 16 10 38 50 21 36
4 14 27 31 42 51 1
8 24 3 59 33 44 53 16 10 38 50 21 36
public static void simpleSort(int[] data) {
int i, j;
for (i = 1; i < data.length; i++) {
int c = data[i];
for (j = i-1; j >= 0 && data[j] > c; j--) {
data[j+1] = data[j];
}
data[j+1] = c;
}
}
3. Сортировка двоичными вставками
public static void binInsertSort(int[] data) {
int n = data.length;
// Длина массива
for (int i = 1; i < n; i++) {
int c = data[i];
// Вставляемое значение
// Организация поиска места для вставки значения c
int low = 0, high = i;
// Inv : (low <= high) && место для c - внутри data[low:high]
while (low < high) {
int m = (low+high) >> 1;
// low <= m < high
if (data[m] < c) low = m+1; else high = m;
}
// Найдено место вставки - low
// Сдвигаем элементы в сторону больших индексов.
for (int j = i-1; j >= low; j--) {
data[j+1] = data[j];
}
// Заносим значение на найденное место
data[low] = c;
}
}
4. Сортировка Шелла
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
4 27 51 14 31 42 1
8 24 3 59 33 44 53 16 10 38 50 21 36
4 10 3 14 21 36 1
8 24 38 50 31 42 53 16 27 51 59 33 44
step=7
step=3
1
8
3
4 10 36 14 21 24 27 44 31 33 50 16 38 51 59 42 53
1
4
3
8 10 21 14 27 16 31 24 36 33 38 42 50 44 53 51 59
1
3
4
8 10 14 16 21 24 27 31 33 36 38 42 44 50 51 53 59
step=2
step=1
4. Сортировка Шелла
public static void ShellSort(int[] data) {
int n = data.length;
// Длина массива
int step = n;
// Шаг поисков и вставки
int i, j;
do {
// Вычисляем новый шаг
step = step / 3 + 1;
// Производим сортировку простыми вставками с заданным шагом
for (i = step; i < n; i++) {
int c = data[i];
for (j = i-step; j >= 0 && data[j] > c; j -= step) {
data[j+step] = data[j];
}
data[j+step] = c;
}
} while (step != 1);
}
Количество перестановок элементов
(по результатам экспериментов со случайным массивом)
n = 25
n = 1000
n = 100000
Сортировка Шелла
50
7700
2 100 000
Сортировка простыми вставками
150
240 000
2.5 млрд.
5. Алгоритм слияния упорядоченных массивов
4
14
27
51
1
3
8
24
31
42
59
public static int[] merge(int[] a, int[] b) {
int na = a.length,
nb = b.length,
nc;
int[] c = new int[nc = na + nb];
int ia = 0,
ib = 0,
ic = 0;
while (ia < na && ib < nb) {
if (a[ia] < b[ib])
c[ic++] = a[ia++];
else
c[ic++] = b[ib++];
}
while (ia < na) c[ic++] = a[ia++];
while (ib < nb) c[ic++] = b[ib++];
return c;
}
6. Сортировка фон Неймана (слиянием)
0
1
2
3
4
5
6
4 27 51 14 31 42 1
И так далее…
7
8
9
10
11
12
13
14
15
16
17
18
19
8 24 3 59 33 44 53 16 10 38 50 21 36
Алгоритм сортировки фон Неймана
public static void mergeSort(int[] data) {
int n = data.length;
// Длина массива
int[] altData = new int[n];
// Дополнительный массив
int[] from = data,
// Указатели "откуда" и "куда" происходит слияние
to = altData;
int len = 1;
// Длина сливаемого фрагмента
do {
int start = 0;
while (start < n) {
// Сливаем участки from[start:(start+len-1)] и from[(start+len):(start+2*len-1)]
// в to[start:(start+2*len-1)]
mergeSection(
from, start, Math.min(start+len, n),
from, Math.min(start+len, n), Math.min(start+(len<<1), n),
to, start);
start += (len << 1);
}
// Меняем направление слияния
int[] interm = from; from = to; to = interm;
} while ((len <<= 1) < n);
// Если после последнего слияния результат оказался "не там",
// то переносим результат "куда надо"
if (from != data) {
mergeSection(from, 0, n, from, n, n, data, 0);
}
}
7. Пирамидальная сортировка (сортировка «кучей»)
0
1
2
3
4
5
6
7
4 27 51 14 31 42 1
8
9
10
11
12
13
14
15
16
17
0
15
27
51
1
2
14
31
42
1
3
4
5
6
8
24
3
59
33
44
53
16
7
8
9
10
11
12
13
14
38 50 21 36
16
17
18
19
8 24 3 59 33 44 53 16 10 38 50 21 36
4
10
18
19
И так далее…
7. Пирамидальная сортировка (продолжение)
59
0
51
53
1
2
50
36
42
44
3
4
5
6
24
38
31
7
8
9
4
10
8
21
3
15
16
17
18
19
14
10
27
33
1
16
11
12
13
14
И так далее…
Алгоритм пирамидальной сортировки
public static void heapSort(int[] data) {
int n = data.length;
// Длина массива
buildPyramid:
// Построение пирамиды
for (int i = 1; i < n; i++) {
// Inv: Элементы data[0:i-1] уже образуют пирамиду;
int c = data[i];
// "Протаскиваемое" значение
int p = i, q;
// Индексы для "протаскивания" вверх к вершине
do { q = p;
if ((p = (q-1) >> 1) >= 0 && data[p] < c) data[q] = data[p];
else {
data[q] = c;
continue buildPyramid;
}
} while (true);
}
meltPyramid:
// Постепенное разрушение пирамиды
for (int i = n-1; i > 0; i--) {
int c = data[i];
data[i] = data[0];
int q, p = 0;
// Индексы для протаскивания
do { q = p;
p = (q << 1) | 1;
if (p >= i) { // Вышли за границу пирамиды
data[q] = c;
continue meltPyramid;
}
if (p < i-1 && data[p+1] > data[p]) p++;
if (data[p] > c) data[q] = data[p];
else {
data[q] = c;
continue meltPyramid;
}
} while (true);
}
}
8. Быстрая сортировка
0
1
2
3
4
5
6
4 27 51 14 31 42 1
7
8
9
10
11
12
13
14
15
16
17
18
19
8 24 3 59 33 44 53 16 10 38 50 21 36
h
l
1
3
4 10 8 14 51 42 24 27 59 33 44 53 16 31 38 50 21 36
1
3
4
8 10 14 36 42 24 27 21 33 44 50 16 31 38 51 53 59
1
3
4
8 10 14 31 16 24 27 21 33 36 50 44 42 38 51 53 59
1
3
4
8 10 14 21 16 24 27 31 33 36 38 44 42 50 51 53 59
1
3
4
8 10 14 16 21 24 27 31 33 36 38 44 42 50 51 53 59
1
3
4
8 10 14 16 21 24 27 31 33 36 38 42 44 50 51 53 59
Дополнения и улучшения алгоритма
Первый элемент в сортируемом куске выбирается случайно и запоминается;
Участки, меньшие определенного размера, сортируются простыми способами;
Иногда исключение рекурсивных вызовов приводит к повышению эффективности.
Программа быстрой сортировки
public static void quickSort(int[] data) {
quickSort(data, 0, data.length-1);
}
private static void quickSort(int[] data, int from, int to) {
if (to-from < 50)
// Небольшие фрагменты быстрее сортировать методом простых вставок
simpleSort(data, from, to);
else {
int c = data[from];
// Выбираем некоторый элемент
// Распределяем элементы массива на значения меньшие и большие c.
int low = from, high = to+1;
// Inv: (low <= high) && data[from:(low-1)] <= c && data[high:to] >= c
while (low < high) {
while (low < high && data[--high] >= c) ;
data[low] = data[high];
while (low < high && data[++low] <= c) ;
data[high] = data[low];
}
// Вставляем элемент на свое место
data[low] = c;
// Независимо сортируем верхнюю и нижнюю половины массива
quickSort(data, from, low-1);
quickSort(data, low+1, to);
}
}
9. Поиск α-медианы
public static int mediana(int[] data, double alpha) {
int n = data.length;
// Длина массива
int m = (int)(alpha*(n-1));
// Номер alpha-медианы в упорядоченном массиве
// Ищем элемент номер m в участке массива с индексами от low до high.
// Для этого выбираем произвольный элемент и делим массив на две части так,
// как это делалось в алгоритме быстрой сортировки.
int low = 0, high = n-1; // Границы обрабатываемого участка массива
do {
int c = data[low];
// Выбранный элемент
int ndxLow = low, ndxHigh = high;
// "Сдвигающиеся" индексы
// Цикл фильтрации элементов на меньшие c и большие c.
while (ndxLow < ndxHigh) {
while (ndxLow < ndxHigh && data[ndxHigh] >= c) ndxHigh--;
data[ndxLow] = data[ndxHigh];
while (ndxLow < ndxHigh && data[ndxLow] <= c) ndxLow++;
data[ndxHigh] = data[ndxLow];
}
// Нашли порядковый номер элемента c.
data[ndxLow] = c;
if (ndxLow == m) return data[m];
// Продолжаем поиск в одной из двух половин массива
if (m < ndxLow) high = ndxLow-1; else low = ndxLow+1;
} while (true);
}
10. Сортировка подсчетом
0
1
2
3
4
5
6
7
8
9
2
1
0
6
5
4
3
2
1
7
6
10
3
9
8
7
14
13
12
10
11
4
14
0
16
15
14
2
17
16
1
19
18
17
2
20
19
1
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
4
7
1
4
1
2
1
8
4
3
9
3
4
3
6
0
8
0
1
6
Программа для сортировки подсчетом
public static void countSort (int[] src, int[] dest) {
// Предполагается, что все элементы src[i] из диапазона 0..15
int n = src.length;
// Длина массива
int[] count = new int[16];
// Массив для подсчета элементов
// 1. Подсчет
for (int i = 0; i < n; i++) {
count[src[i]]++;
}
// 2. Суммирование
for (int i = 1; i < 16; i++) {
count[i] += count[i-1];
}
// 3. Расстановка
for (int i = n-1; i >= 0; i--) {
dest[--count[src[i]]] = src[i];
}
}
11. Цифровая сортировка
4 27 51 14 31 42 1
8 24 3 59 33 44 53 16 10 39 50 21 36
После сортировки по последней цифре:
10 50 51 31 1 21 42 3 33 53 4 14 24 44 16 36 27 8 59 39
После устойчивой сортировки по первой цифре:
1
3
4
8 10 14 16 21 24 27 31 33 36 39 42 44 50 51 53 59
Программа для цифровой сортировки
public static void digitSort(int[] data) {
int n = data.length;
// Длина массива
int[] data2 = new int[n];
// Вспомогательный массив
for (int step = 0; step < 8; step++) { // step - номер "цифры"
// Сортировка "подсчетом" по цифре с заданным номером
countSort(data, step, data2);
// Меняем указатели на массивы
int[] temp = data; data = data2; data2 = temp;
}
}
private static void countSort (int[] src, int nDig, int[] dest) {
int n = src.length;
// Длина массива
int[] count = new int[16];
// Массив для подсчета элементов
// 1. Подсчет
nDig <<= 2;
for (int i = 0; i < n; i++) {
count[(src[i] & (0xF << nDig)) >> nDig]++;
}
// 2. Суммирование
for (int i = 1; i < 16; i++) {
count[i] += count[i-1];
}
// 3. Расстановка
for (int i = n-1; i >= 0; i--) {
dest[--count[(src[i] & (0xF << nDig)) >> nDig]] = src[i];
}
}
Download