Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Сортировка Шелла




Улучшенная сортировка простыми вставками

Алгоритм можно слегка улучшить. Заметим, что на каждом шаге внутреннего цикла проверяются 2 условия. Можно объединить их в одно, поставив в начало массива специальный сторожевой элемент. Он должен быть заведомо меньше всех остальных элементов массива (рис. 9).

             

 

®
min            

 

Рис. 9

Тогда при j = 0 будет заведомо верно a[0] <= x. Цикл остановится на нулевом элементе, что и было целью условия j >= 0.

Таким образом, сортировка будет происходить правильным образом, а во внутреннем цикле станет на одно сравнение меньше. С учетом того, что оно производилось О(n2) раз, это - реальное преимущество. Однако отсортированный массив будет неполон, так как из него исчезло первое число. Для окончания сортировки это число следует вернуть назад, а затем вставить в отсортированную последовательность a[1]...a[n] (рис. 10).

min 0 1 2 4 7 9
®
  0 1 2 4 7 9
®
0 1 2 3 4 7 9

Рис. 10

// сортировка вставками со сторожевым элементомtemplate<class T>inline void insertSortGuarded(T a[], long size) { T x; long i, j; T backup = a[0]; // сохранить старый первый элемент setMin(a[0]); // заменить на минимальный for (i=1; i < size; i++) { // отсортировать массив x = a[i]; for (j=i-1; a[j] > x; j--) a[j+1] = a[j]; a[j+1] = x; } for (j=1; j<size && a[j] < backup; j++) // вставить backup на правильное место a[j-1] = a[j]; a[j-1] = backup; // вставка элемента}

Функция setmin(T& x) должна быть создана пользователем. Она заменяет x на элемент, заведомо меньший (меньший или равный, если говорить точнее) всех элементов массива.

Сортировка Шелла является довольно интересной модификацией алгоритма сортировки простыми вставками.

Рассмотрим следующий алгоритм сортировки массива a[0].. a[15] (рис. 11).

                               

Рис. 11

1. Вначале сортируем простыми вставками каждые 8 групп из двух элементов (a[0], a[8]), (a[1], a[9]),..., (a[7], a[15]) (рис.12).

 
 


                               

 

Рис. 12

2. Потом сортируем каждую из четырех групп по четыре элемента (a[0], a[4], a[8], a[12]),..., (a[3], a[7], a[11], a[15]) (рис. 13).

Номер группы
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
                               

Рис.13

В нулевой группе будут элементы 4, 12, 13, 18, в первой - 3, 5, 8, 9 и т.п.

3. Далее сортируем 2 группы по 8 элементов, начиная с (a[0], a[2], a[4], a[6], a[8], a[10], a[12], a[14]) (рис. 14).

                 
                               
                 
                                                               

Рис. 14

 

4. В конце сортируем вставками все 16 элементов (рис. 15).

                               

Рис. 15

Очевидно, лишь последняя сортировка необходима, чтобы расположить все элементы по своим местам. Так зачем нужны остальные?

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

Единственной характеристикой сортировки Шелла является приращение - расстояние между сортируемыми элементами, в зависимости от прохода. В конце приращение всегда равно единице - метод завершается обычной сортировкой вставками, но именно последовательность приращений определяет рост эффективности.

Использованный в примере набор - 8, 4, 2, 1 – является обычным выбором в тех случаях, когда количество элементов представляет собой степень двойки. Однако гораздо лучший вариант предложил Р.Седжвик. Его последовательность имеет вид:

 
 


inc[s] = 9*2s-9*2s/2+1, если s четно
8*2s-6*2(s+1)/2+1, если s нечетно

 

При использовании таких приращений среднее количество операций: O(n7/6), в худшем случае - порядка O(n4/3).

Обратим внимание на то, что последовательность вычисляется в порядке, противоположном используемому: inc[0] = 1, inc[1] = 5,... Формула дает сначала меньшие числа, затем все большие и большие, в то время как расстояние между сортируемыми элементами, наоборот, должно уменьшаться. Поэтому массив приращений inc вычисляется перед запуском собственно сортировки до максимального расстояния между элементами, которое будет первым шагом в сортировке Шелла. Потом его значения используются в обратном порядке. При использовании формулы Седжвика следует остановиться на значении inc[s-1], если 3*inc[s] > size.

int increment(long inc[], long size) { int p1, p2, p3, s; p1 = p2 = p3 = 1; s = -1; do { if (++s % 2) { inc[s] = 8*p1 - 6*p2 + 1; } else { inc[s] = 9*p1 - 9*p3 + 1; p2 *= 2; p3 *= 2; } p1 *= 2; } while(3*inc[s] < size); return s > 0? --s: 0;} template<class T>void shellSort(T a[], long size) { long inc, i, j, seq[40]; int s; // вычисление последовательности приращений s = increment(seq, size); while (s >= 0) { // сортировка вставками с инкрементами inc[] inc = seq[s--]; for (i = inc; i < size; i++) { T temp = a[i]; for (j = i-inc; (j >= 0) && (a[j] > temp); j -= inc) a[j+inc] = a[j]; a[j+inc] = temp; } }}

Часто вместо вычисления последовательности во время каждого запуска процедуры, ее значения рассчитывают заранее и записывают в таблицу, которой пользуются, выбирая начальное приращение по тому же правилу: начинаем с inc[s-1], если 3*inc[s] > size.




Поделиться с друзьями:


Дата добавления: 2014-12-27; Просмотров: 536; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.016 сек.