Я пытаюсь написать алгоритм quicksort на C #, последнее время получаю System.StackOverflowExceptions и не могу понять почему.

Вот мой класс:

    class quicksort : sortalgorithm
{
    int pivotIndex = -1;
    int pivotSwapped = 0;
    Random rand = new Random();

    public quicksort(int[] arr)
    {
        if (arr.Length < 5)
        {
            throw new Exception("Array has too few Entries");
        }
        toSort = arr;
    }

    protected override int sort()
    {
        if (pivotIndex == -1) getPivot();
        int indexL = getIndexLeft();
        int indexR = getIndexRight();
        if (indexR != -1 && indexL != -1 && indexL != toSort.Length-1)
        {
            swap(indexL, indexR);
        }
        if (indexL > indexR)
        {
            Console.WriteLine("Index thingy");
            swap(toSort.Length - 1, indexL);
            pivotSwapped++;
            if (pivotSwapped == toSort.Length - 1)
            {
                return 1;
            }
            else
            {
                Console.WriteLine("new piv");
                pivotSwapped++;
                getPivot();
                sort();
                return -1;
            }
        }
        else
        {
            sort();
            return -1;
        }
    }

    private void swap(int i, int j)
    {
        int temp = toSort[i];
        toSort[i] = toSort[j];
        toSort[j] = temp;
    }

    private void getPivot()
    {
        pivotIndex = rand.Next(0, toSort.Length - 1);
        swap(toSort.Length - 1, pivotIndex);
    }

    private int getIndexLeft() // Larger then Pivot Starting: Left
    { //Error Here
        int itemFromLeft = -1;
        for (int i = 0; i < toSort.Length - 1; i++)
        {
            if (toSort[i] >= toSort[toSort.Length - 1])
            {
                itemFromLeft = i;
                i = toSort.Length + 1;
            }
        }
        //Console.WriteLine(itemFromLeft);
        return itemFromLeft;
    }

    private int getIndexRight()// Smaller then Pivot Starting: Right
    {
        int itemFromRight = -1;
        for (int i = toSort.Length - 1; i >= 0; i--)
        {
            if (toSort[i] < toSort[toSort.Length - 1])
            {
                itemFromRight = i;
                i = -1;
            }
        }
        //Console.WriteLine(itemFromRight);
        return itemFromRight;
    }
}

Я надеюсь, что кто-то может мне помочь.

P.S. класс sortalgorithm в этом случае имеет только массив toSort.

Мой вывод в консоль всегда выглядит примерно так:

[4, 28, 62, 33, 11] // The unsorted array
Index thingy
new piv
Index thingy
new piv
Index thingy
new piv

Process is terminated due to `StackOverflowException`.
0
ScarVite 8 Июн 2021 в 12:54

2 ответа

Лучший ответ

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

Единственный очевидный кандидат

            **sort();**
            return -1;
        }
    }
    else
    {
        **sort();**
        return -1;
    }

Поэтому один или другой рекурсивный вызов, вероятно, неверен и требует удаления, и я подозреваю, что проблема будет решена

РЕДАКТИРОВАТЬ:

Так как вы не можете отлаживать свой код, вот как должна выглядеть быстрая сортировка

public int sort()
{
    qsort(0, toSort.Length - 1);
    return 0;
}

private void qsort( int left, int right)
{
    if (left < right)
    {
        int pivot = Partition( left, right);

        if (pivot > 1)
        {
            qsort( left, pivot - 1);
        }
        if (pivot + 1 < right)
        {
             qsort( pivot + 1, right);
        }
    }
}
private int Partition( int left, int right)
{
    int pivot = toSort[left];
    while (true)
    {

        while (toSort[left] < pivot)
        {
            left++;
        }

        while (toSort[right] > pivot)
        {
            right--;
        }

        if (left < right)
        {
            if (toSort[left] == toSort[right]) return right;

            int temp = toSort[left];
            toSort[left] = toSort[right];
            toSort[right] = temp;


        }
        else
        {
            return right;
        }
    }
}

Обратите внимание, что если left> = right ничего не делать

1
MikeT 8 Июн 2021 в 11:46

Эта простая реализация схемы разделов Хоара демонстрирует, как избежать переполнения стека путем рекурсии на меньшем разделе и возврата в цикл для большего раздела - идея, использованная в исходной быстрой сортировке. Сложность пространства стека ограничена O (log2 (n)), но сложность времени наихудшего случая по-прежнему O (n ^ 2).

        static public void Quicksort(int [] a, int lo, int hi)
        {
            while(lo < hi){                 // while partition size > 1
                int p = a[(lo + hi) / 2];
                int i = lo, j = hi;
                i--;                        // Hoare partition
                j++;
                while (true)
                {
                    while (a[++i] < p) ;
                    while (a[--j] > p) ;
                    if (i >= j)
                        break;
                    int t = a[i];
                    a[i] = a[j];
                    a[j] = t;
                }
                i = j++;                    // i = last left, j = first right
                if((i - lo) <= (hi - j)){   // if size(left) <= size(right)
                    Quicksort(a, lo, i);    //   recurse on smaller partition
                    lo = j;                 //   and loop on larger partition
                } else { 
                    Quicksort(a, j, hi);    //   recurse on smaller partition
                    hi = i;                 //   and loop on larger partition
                }
            }
        }
0
rcgldr 8 Июн 2021 в 20:13