Быстрая сортировка по двусвязному списку

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

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

Ее мой код:

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;
}


}

person mr_jonify    schedule 30.04.2013    source источник
comment
Какой у Вас вопрос?   -  person Adam Arold    schedule 30.04.2013
comment
Ой, извини :) Я всегда получаю бесконечный цикл, и я не знаю почему? Может быть неправильное условие прерывания?   -  person mr_jonify    schedule 30.04.2013


Ответы (2)


На первый взгляд кажется, что ваш список не только дважды связан, но и связан на концах (так что это больше похоже на кольцо, чем на список). Другими словами, если бы я перебирал ваш список (содержащий элементы 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
person durron597    schedule 30.04.2013
comment
Да, но я хочу сделать это для кольца. Я также написал, что это двусвязный список SYNC ... Я думаю, что синхронизация имеет в виду это. - person mr_jonify; 30.04.2013
comment
Если это кольцо, сортировка бессмысленна, верно? Потому что после самого большого элемента снова идет самый маленький элемент. (Кстати, я никогда не слышал, чтобы это означало "синхронизация") - person durron597; 30.04.2013
comment
Да, конечно, но это школьный проект, так что я должен его сделать ... И у нас есть отметка для списка, где он начинается, если вы это имеете в виду. - person mr_jonify; 30.04.2013
comment
@mr_jonify Я думаю, что это не синхронно, а циклично. - person Viktor Seifert; 30.04.2013

Вот реализация 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, я получил следующие результаты:

Быстрая сортировка:
1.000.000 элементов: 696 мс - 8,300 000 элементов: 8131 мс.

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

Сортировка слиянием:
1.000.000 элементов: 466 мс - 8,300 000 элементов: 5144 мс.

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

person lanoxx    schedule 10.01.2014