QuickSort по двойному связанному списку

Я хочу реализовать алгоритм QuickSort для синхронного двойного списка. Я предоставляю функции "разделять" левую и правую границу, затем начинает искать более низкие значения с левой стороны и класть большие с правой стороны. Это работает, потому что мой элемент-поворот всегда самый ранний, и после этого он находится посередине.

Я всегда получаю бесконечный цикл, и я не знаю почему? Может быть, неправильное условие прерывания?

Ее мой код:

private void quickSortRec(DoublyLinkedList in, ListElement l, ListElement r) {

    ListElement pivot = partition(in, l, r);



    if(pivot!=null && l!=r){
        quickSortRec(in, in.first, pivot.prev);
        quickSortRec(in, pivot.next, in.first.prev);
    }
}


public ListElement partition(DoublyLinkedList in, ListElement l, ListElement r){


    ListElement pivot = r;
    ListElement walker = l;


    if(l!=r){


        while(walker != pivot){

            if(walker.getKey() >= pivot.getKey()){

                System.out.println(walker.getKey());

                if(walker.prev == r){
                    l = walker.next;
                    r = walker;
                }
                else{


                    ListElement h1 = walker.prev;
                    ListElement h2 = walker.next;

                    h1.next = h2;
                    h2.prev = h1;
                    walker.prev = pivot;
                    walker.next = l;
                    pivot.next = walker;
                    l.prev = walker;
                    r = walker;

                }

            }
            walker = walker.next;
        }

        if(l.prev == r)
            in.first = l;

        ListElement p = in.first;
        do{
            System.out.print(p.toString()+" ");
            p = p.next;
        }while(p != in.first);

        System.out.println();



        return pivot;

    }

    return null;
}


}

Ответ 1

Просто из-за быстрого обезболивания кажется, что ваш список не только дважды связан, но также подключен к концам (так что он больше напоминает кольцо, чем список). Другими словами, если бы я перебирал ваш список (содержащий элементы A, B, C, D), это не было бы:

A -> B -> C -> D -> stop

Вместо этого было бы

A -> B -> C -> D -> A -> B -> C -> D -> A -> B ..... etc.

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

Я бы создал ссылку на последний элемент вашего списка в вашем классе DoublyLinkedList (пример: in.last), используйте его для получения последнего элемента и привяжите первый и последний элементы к null или какой-то NullListElement extends ListElement


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

if(walker == in.last) break; // stop

Ответ 2

Node partition(Node start, Node end){
    Node l = start;
    Node h = end.previous;
    Node pivot = end;

    if(end!=null && end.next!=start){ //Whenever deal with end.next, check null check
        while(h!=null && h.next!=l){//Whenever deal with end.next, check null check
            System.out.println("gumi");
            if(l.data<pivot.data)
                l=l.next;
            else if(h.data>pivot.data)
                h=h.previous;
            else{
                int temp = l.data;
                l.data = h.data;
                h.data = temp;
            }   
        }   
        int temp = pivot.data;
        pivot.data = l.data;
        l.data = temp;
    }
    return l;

}
void quicksort(Node start, Node end){
     System.out.println("jose");
   if(end!=null && end.next!=start ){ //Whenever deal with end.next, check null check , end should not be less than start: so the condition end.next!=start 
       System.out.println("Quixk");
       Node pivot = partition(start,end);
       quicksort(start, pivot.previous);
       quicksort(pivot.next, end);
   }

}

Ответ 3

Вот реализация для QuickSort с помощью класса DoublyLinkedList, который содержит ссылку на первый (in.first) ListElement, элемент списка содержит key и prev и next ссылки:

public DoublyLinkedList quicksort(DoublyLinkedList in, int numOfElements) {
    in.first = partition(in.first, in.first.prev);
    return in;
}

private ListElement partition(ListElement first, ListElement pivotElement) {
    ListElement left = first;
    ListElement right = pivotElement;

    while (left != pivotElement) {
        if (left.getKey() > pivotElement.getKey()) {
            ListElement next = left.next;
            if (left == first)
                first = next;
            //Remove currentLeft
            left.prev.next = left.next;
            left.next.prev = left.prev;

            //Connect with element after currentRight
            left.next = right.next;
            right.next.prev = left;

            //Connect with pivotElement
            left.prev = right;
            right.next = left;

            right = left; //Switch right with left, since we just swapped their positions
            left = next;  //Assign left to the next object (from the left part)
        } else {
            left = left.next;
        }
    }
    if (first != pivotElement.prev && first != pivotElement)
        first = partition(first, pivotElement.prev);
    if (pivotElement != right)
        partition(pivotElement.next, right);
    return first;
}

На момент написания этой статьи, когда я запускаю ее на своем настольном компьютере с очень недавним процессором Haswel, я получаю следующие результаты:

Quicksort:
1.000.000 Предметы: 696ms
8.300.000 Предметы: 8131мс

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

Сортировка слиянием:
1.000.000 Предметы: 466ms
8.300.000 Предметы: 5144мс

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