简体   繁体   中英

Runtime errors in C++ implementation of quicksort

I am writing an implementation of quicksort to brush up on my C++ skills, but am running into an error that is stumping me. The algorithm seems to be working fine about 25% of the time, but I keep running into the errors the other 75% of the time, where the program reports either a segmentation fault or stack overflow. If anyone could help, it would be much appreciated. Thanks in advance.

#include <iostream>
#include <string.h>
#include <ctime>
using namespace std;

#define size 20

void printSet(int* set);
int* quicksort(int* set, int l);
int* concat(int* less, int countL, int* greater, int countG);

int main()
{
    srand(time(NULL));
    int* set;
    set = new int[size];
    for(int i=0; i<size; i++)
        set[i]=rand()%200;
    printSet(set);
    set = quicksort(set, size);
    printSet(set);
    delete set;
    int i;
    cin>> i;
    return 0;
}

int* quicksort(int* set, int l)
{
    //cout<<"QS\n";
    if (l <= 1)
        return set;
    int*      less = new int[l];
    int*   greater = new int[l];
    int pivotIndex = rand() % l, 
          pivotVal = set[pivotIndex],
            countL = 0,
            countG = 0;

    for(int i=0; i<l; i++)
    {
        if (set[i] < pivotVal)
            less[countL++]=set[i];
        else
            greater[countG++]=set[i];
    }
    set = concat(quicksort(less, countL), countL, quicksort(greater, countG), countG);

    return set;
}

int* concat(int* less, int countL, int* greater, int countG)
{
    //cout<<"concat\n";
    int* set;
    set = new int[size];

    int i;

    for(i=0; i<countL; i++)
        set[i]=less[i];
    for(int j=0; j<countG; j++)
        set[i+j]=greater[j];

    return set;
}

void printSet(int* set)
{
    cout<<"******************\nPrinting Set\n";
    for(int i=0; i< size; i++)
    {
        cout<<i<<": "<<set[i]<<endl;
    }
}

I believe that one of your errors is in this line in main:

delete set;

The problem here is that set is an array allocated with new[] . To free its memory, you need to delete it with a matching call to delete[] . This can be fixed by rewriting the line as

delete[] set;

Additionally, your code has the chance to infinitely recurse in some cases. In particular, suppose that you try sorting a list that's two copies of 0. In that case, consider what this code will do:

for(int i=0; i<l; i++)
{
    if (set[i] < pivotVal)
        less[countL++]=set[i];
    else
        greater[countG++]=set[i];
}
set = concat(quicksort(less, countL), countL, quicksort(greater, countG), countG);

Since your pivot element is 0 (it's the only choice!), you'll iterate across the array and put both of the 0's in the array into greater . Consequently, when you recursively invoke quicksort on greater , you'll end up recursively trying to sort the exact same range that you started with, leading to infinite recursion.

To fix this, try updating your code so that you partition into three groups - elements less than the pivot, elements greater than the pivot, and elements equal to the pivot. You would still recurse on the less and greater ranges, but you wouldn't recursively invoke yourself on the equal values. This would ensure that the recursion always is invoked on smaller ranges than what you started with.

Finally, as others have pointed out, your current implementation leaks a lot of memory because you never free any of the temporary arrays you construct. To avoid this, consider replacing your use of raw arrays with std::vector , which does its own memory management and won't leak any memory. Plus, it makes it substantially easier to split the array into regions, since you can just use push_back to append the elements.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM