В информатике адаптивная сортировка кучей — это алгоритм сортировки на основе сравнения из семейства адаптивных сортировок . Это вариант сортировки кучей , который работает лучше, когда данные содержат существующий порядок. Опубликованный Христосом Левкопулосом и Олой Петерссоном в 1992 году, алгоритм использует новую меру предварительной сортировки, Osc, как число колебаний. [1] Вместо того, чтобы помещать все данные в кучу, как это делала традиционная сортировка кучей, адаптивная сортировка кучей берет только часть данных в кучу, так что время выполнения значительно сокращается, когда предварительная сортировка данных высока. [1]
Сортировка кучи — это алгоритм сортировки, который использует двоичную структуру данных кучи . Метод рассматривает массив как полное двоичное дерево и создает Max-Heap/Min-Heap для достижения сортировки. [2] Обычно он включает следующие четыре шага.
Ниже представлена реализация на языке C/C++, которая создает Max-Heap и сортирует массив после создания кучи.
/* Пример кода сортировки кучи на AC/C++, сортирующего массив в порядке возрастания */// Функция, которая создает двоичное дерево с максимальной кучей void heapify ( int array [], int start , int end ) { int parent = start ; int child = parent * 2 + 1 ; while ( child <= end ) { if ( child + 1 <= end ) // когда есть два дочерних узла { if ( array [ child + 1 ] > array [ child ]) { child ++ ; // берем больший дочерний узел } } if ( array [ parent ] > array [ child ]) { return ; // если родительский узел больше, то он уже кучный } if ( array [ parent ] < array [ child ]) // когда дочерний узел больше родительского узла { swap ( array [ parent ], array [ child ]); // меняем местами родительский и дочерний узлы parent = child ; child = child * 2 + 1 ; // продолжаем цикл, сравниваем дочерний узел и его дочерние узлы } } } // heap_sort function void heap_sort ( int array [], int len ) { for ( int i = len / 2 - 1 ; i >= 0 ; i -- ) //Шаг 1: создаем максимальную кучу { heapify ( array , i , len ); } for ( int i = len - 1 ; i >= 0 ; i -- ) //Шаг 4: повторяем шаги 2 и 3 до завершения { swap ( array [ 0 ], array [ i ]); //Шаг 2: помещаем максимум в конец массива heapify ( array , 0 , i -1 ); //Шаг 3: удаляем максимум из дерева и снова выполняем heapify } } инт мейн () { // массив, который будет отсортирован int array [] = { 42 , 1283 , 123 , 654 , 239847 , 45 , 97 , 85 , 763 , 90 , 770 , 616 , 328 , 1444 , 911 , 315 , 38 , 5040 , 1 }; int array_len = sizeof ( array ) / sizeof ( * array ); // длина массива heap_sort ( array , array_len ); вернуть 0 ; }
Меры предварительной сортировки измеряют существующий порядок в заданной последовательности. [3] Эти меры предварительной сортировки определяют количество данных, которые будут помещены в кучу во время процесса сортировки, а также нижнюю границу времени выполнения. [4]
Для последовательности Cross ( x i ) определяется как число ребер линейного графика X , которые пересекаются горизонтальной линией, проходящей через точку ( i, x i ). Математически это определяется как . Осцилляция ( Osc ) X — это просто общее число пересечений, определяемое как . [1]
Помимо исходного измерения Osc, другие известные меры включают число инверсий Inv , число запусков Runs , число блоков Block и меры Max , Exc и Rem . Большинство из этих различных измерений связаны с адаптивной сортировкой кучи. Некоторые меры доминируют над другими: каждый Osc-оптимальный алгоритм является Inv-оптимальным и Runs-оптимальным; каждый Inv-оптимальный алгоритм является Max-оптимальным; и каждый Block-оптимальный алгоритм является Exc-оптимальным и Rem-оптимальным. [4]
Адаптивная сортировка кучей — это вариант сортировки кучей, которая ищет оптимальность (асимптотически оптимальную) относительно нижней границы, полученной с помощью меры предварительной сортировки, используя существующий порядок в данных. В сортировке кучей для данных мы помещаем все n элементов в кучу, а затем продолжаем извлекать максимум (или минимум) n раз. Поскольку время каждого действия по извлечению максимума является логарифмическим по размеру кучи, общее время выполнения стандартной сортировки кучей составляет . [2] Для адаптивной сортировки кучей, вместо помещения всех элементов в кучу, в кучу будут помещены только возможные максимумы данных (максимальные кандидаты), так что потребуется меньше запусков, когда каждый раз мы пытаемся найти максимум (или минимум).
Сначала декартово дерево строится из входных данных со временем путем помещения данных в двоичное дерево и делая каждый узел в дереве больше (или меньше), чем все его дочерние узлы, а корень декартового дерева вставляется в пустую двоичную кучу. Затем многократно извлекается максимум из двоичной кучи, извлекается максимум в декартовом дереве и добавляется его левый и правый потомки (если есть), которые сами являются декартовыми деревьями, в двоичную кучу. Если входные данные уже почти отсортированы, декартовы деревья будут очень несбалансированными, с немногими узлами, имеющими левых и правых потомков, в результате чего двоичная куча остается небольшой и позволяет алгоритму сортировать быстрее, чем для входных данных, которые уже почти отсортированы. [5]
Ниже представлена реализация в псевдокоде: [1]
Входные данные: массив из n элементов, которые необходимо отсортировать.Построить декартово дерево l ( x )Вставьте корень l ( x ) в кучудля i = от 1 до n{ Выполнить ExtractMax в куче если максимальный извлеченный элемент имеет какие-либо дочерние элементы в l ( x ) { получить детей в l ( x ) вставить дочерний элемент в кучу }}
Несмотря на десятилетия исследований, между теорией адаптивной сортировки кучи и ее практическим применением все еще существует разрыв. Поскольку алгоритм использует декартовы деревья и манипуляцию указателями, он имеет низкую эффективность кэширования и высокие требования к памяти, что ухудшает производительность реализаций. [4]