Why won't my quick sort work - c++

I can't figure out why this code isn't quite correct. It sorts most of the array, but some numbers are out of place. Any help would be much appreciated.
int partition(int* an_array, int from, int to)
{
int pivot = an_array[(from + to) / 2];
int left = from;
int right = to;
while(left < right)
{
while(an_array[left] < pivot)
{
left = left + 1;
}//end while loop
while(an_array[right] > pivot)
{
right = right - 1;
}//end while
if(left < right)
{
swap_numbers(an_array[left], an_array[right]);
left = left + 1;
right = right - 1;
}//end if
}//end while loop
return right;
}//end partition function
void quick_sort(int* an_array, int from, int to)
{
if(from >= to) return;
int p = partition(an_array, from, to);
quick_sort(an_array, from, p);
quick_sort(an_array, p + 1, to);
}//end quick_sort

You forget to add:
swap_numbers(an_array[from], an_array[right]);
just before
return right;

Related

Infinite loop problem with the merge sort during the portion recursively calls mergeSort

Im working on a homework assignment comparing both execution time and theoretical O-notation of 10 separate sorts. However, as the question says I keep having an infinite loop when I get to the point that the code recursively calls merge sort. I know that it is when the left is at 2 and the right is at 3 so middle continuously returns as 3. is merge supposed to be outside of the if statement? I don't think that would be right either though when I look at it.
void merge(int arr[], int left, int middle, int right)
{
// get the temporary array lengths
int first = middle - left + 1;
int second = right - middle;
// make the temp dynamic arrays
int *Left = new int(first);
int *Right = new int(second);
for (int i = 0; i < first; i++)
{
Left[i] = arr[left + i];
}
for (int i = 0; i < second; i++)
{
Right[i] = arr[middle + 1 + i];
}
// merge the arrays back into arr
int i = 0;
int j = 0;
int k = left;
while (i < first && j < second)
{
// check which one is bigger
if (Left[i] <= Right[j])
{
arr[k] = Left[i];
i++;
}
else
{
arr[k] = Right[j];
j++;
}
k++;
}
// copy Left remainder
while (i < first)
{
arr[k] = Left[i];
i++;
k++;
}
// copy right remainder
while (j < second)
{
arr[k] = Right[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right)
{
if (left < right)
{
int middle = left + (right - 1) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
In mergeSort function, you forgot parenthesis when calculating middle. It should be:
int middle = (left + (right - 1)) / 2;
Also, in merge function, Left and Right should have type int[]. Instead of new int(SIZE), you should use new int[SIZE]. Moreover, you should use delete[] to delete them before leaving the function to prevent memory leak.
// make the temp dynamic arrays
int* Left = new int[first];
int* Right = new int[second];
// ...
// at the end of the `merge` function
delete[] Left;
delete[] Right;

Partitioning algorithm issue with iterative quicksort method

Short version of original question: I am trying to convert this example: http://programmertech.com/program/cpp/quick-sort-recursive-and-iterative-in-c-plus-plus of iterative quicksort to use vectors rather than arrays and begin simplifying a few things. Originally the direct conversion failed, so I tried through it line by line to get a better understanding, but my logic is stuck and broken.
EDIT: Deleted everything from the question, providing a minimal (not quite working) example of what I'm attempting. This is everything I have so far. I have worked through this on paper by hand, and the more I've touched it the worse it gets, and now gets stuck in an infinite loop (originally wasn't sorting correctly).
Here is my thinking: getMedian as I've written it should swap the pivot value, and the left and right values so that they are ordered: left <= med <= right. When we go to the while (right > left) loop in the partition algorithm, it should keep swapping elements to put all of those greater than the pivot to the right of it, and those less to the left. The stack keeps a track of the Sub(vectors) (in this case) which need to be partitioned still. But that doesn't seem to be working. I feel as if I've missed something very important to this working.
#include <iostream>
#include <vector>
class QuickSort {
public:
QuickSort(std::vector<int> toBeSorted) : toBeSorted(toBeSorted) {}
void sortVector();
void print();
private:
int partition(int left, int right);
int getMedian(int left, int right);
std::vector<int> toBeSorted;
};
// Iterative method using a stack
void QuickSort::sortVector() {
int stack[toBeSorted.size()];
int top = 0;
stack[top++] = toBeSorted.size() - 1;
stack[top++] = 0;
int left, right, pivIndex;
while (top > 0) {
// Popping values for subarray
left = stack[--top];
right = stack[--top];
pivIndex = partition(left, right);
if (pivIndex + 1 < right) {
stack[top++] = right;
stack[top++] = pivIndex+1;
}
if (pivIndex - 1 > left) {
stack[top++] = pivIndex-1;
stack[top++] = left;
}
}
}
int QuickSort::partition(int left, int right) {
int pivotValue = getMedian(left, right);
if (right - left > 1) {
while (right > left) {
while (toBeSorted[left] < pivotValue) { left++; }
while (toBeSorted[right] > pivotValue) { right--; }
if (toBeSorted[right] < toBeSorted[left]) {
std::swap(toBeSorted[right], toBeSorted[left]);
left++;
right--;
}
}
} else {
if (toBeSorted[right] < toBeSorted[left]) {
std::swap(toBeSorted[right], toBeSorted[left]);
}
}
return 0;
}
int QuickSort::getMedian(int left, int right) {
int med = (right - left)/2;
// if there are an even number of elements, instead of truncating
// goto the rightmost value.
if ((right - left)%2 != 0) {
med = (right-left)/2 + 1;
}
// Organise the elements such that
// values at indexes: left <= med <= right.
if (toBeSorted[med] < toBeSorted[left]) {
std::swap(toBeSorted[left], toBeSorted[med]);
}
if (toBeSorted[right] < toBeSorted[left]) {
std::swap(toBeSorted[left], toBeSorted[right]);
}
if (toBeSorted[right] < toBeSorted[med]) {
std::swap(toBeSorted[right], toBeSorted[med]);
}
return toBeSorted[med];
}
void QuickSort::print() {
for (int i = 0; i != toBeSorted.size(); i++) {
std::cout << toBeSorted[i] << ",";
}
std::cout << std::endl;
}
int main() {
std::vector<int> values = {5, 8, 7, 1, 2, 5, 3};
QuickSort *sorter = new QuickSort(values);
sorter->sortVector();
sorter->print();
return 0;
}
In partition method, you shouldn't swap(data[low], data[high]) in every iteration. Your mistake is this portion. You can do it like this:
void partition(int left, int right) {
// listOfNums is a vector
int middle = getMidPiv(left, right);
int low = left;
int high = right-1;
while (low < high) {
while (listOfNums[low] < middle) {
lower++;
}
while (listOfNums[high] > middle) {
high--;
}
if (low < high) {
swap(data[low], data[high]);
low++;
high--;
}
}
// swap(data[low], data[high]); it is incorrect
return low;
}
In the first inner while loop, use low++ instead of lower++ and change the return type of function to int.

Heap Corruption Detected (C++)

I am having a problem with merge sorting. I'm using the code below, and I'm getting a heap corruption detected. It happens when I try to deallocate memory, so I would imagine I'm writing an out of bound index.
More specifically I think it's at the last for loop. When I print out the array, the first index is some garbage number, and the last index is actually the one before the last that I want. I've tried everything and I can't get around to solving this, can somebody tell me what exactly I'm doing wrong? 'Cause I can't seem to understand what the problem is.
Here's the code I'm using:
template <class T>
int Mergesort(T arr[], int n) {
MergeSortRec(arr, 0, n, n);
return 0;
}
template <class T>
void MergeSortRec(T arr[], int left, int right, int size) {
if(right > left) {
int mid = ((left + right) /2);
MergeSortRec(arr, left, mid, size);
MergeSortRec(arr, mid+1, right, size);
Merge(arr, left, mid, right, size);
}
return;
}
template <class T>
void Merge(T arr[], int left, int mid, int right, int size) {
int i = 0;
int j = left;
int k = mid + 1;
T* temp = new T[right - left];
while(j <= mid && k <= right) {
if(arr[j] < arr[k]) {
temp[i++] = arr[j++];
} else {
temp[i++] = arr[k++];
}
}
while(j <= mid) {
temp[i++] = arr[j++];
}
while(k <= right) {
temp[i++] = arr[k++];
}
for(int a = left; a <= right; a++) {
arr[a] = temp [a-left];
}
Cheers.
The problem is here:
T* temp = new T[right - left];
//...
for(int a = left; a <= right; a++) {
arr[a] = temp [a-left];
}
You allocate right-left elements, but the for loop steps through right-left+1 entries, so you run off the end of the array and trample on some memory you shouldn't. If you added delete [] temp; after that for loop (without it you are leaking memory!) you would probably see your error much earlier.
In fact, all your loops go one too far; it's just most obvious in this simple loop.

Can't find bug in program (Quicksort implementation)

For some reason, whenever I try to compile the program it says "File has stopped working". It doesn't give any specific errors so I have no clue what is wrong. I've looked it over many times and can't find any errors.
This is an implementation of a quicksort algorithm.
int partition(int arr[], int left, int right) {
int pivotPos = left + rand() % right;
int pivot = arr[pivotPos];
int p = left;
swap(arr[pivotPos], arr[right]);
for (int i = left; i < right; i++) {
if (arr[i] <= pivot) {
swap(arr[i], arr[p]);
p++;
}
}
swap(arr[p], arr[pivotPos]);
return p;
}
void quickSort(int arr[], int left, int right) {
if (left < right) {
int partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
}
int main() {
int theArr[10000];
clock_t d1, d2;
for (int i = 0; i < 10000; i++) {
theArr[i] = 1 + rand() % 500;
}
for (int i = 0; i < 10; i++) {
d1 = clock();
quickSort(theArr, 0, 10000);
d2 = clock();
cout << "Time: " << ((double) (d2 - d1) / (CLOCKS_PER_SEC)) << endl;
}
return 0;
}
As hvd pointed out in the comments section, the following line appears wrong.
int pivotPos = left + rand() % right;
What you are looking for is:
int pivotPos = left + rand() % (right-left);
I do not understand why do you are swapping arr[p] and arr[pivotPos] after the loop has ended.
pivotPos is the initial location of the pivot. The final location of the pivot will be p-1. At the end of the loop the array is already arranged as required. This swapping will only make the array more haphazard. And therefore, in addition to replacing
int pivotPos = left + rand() % right;
by
int pivotPos = left + rand() % (right - left);
and replacing
arr[right] by arr[right-1]
You should also replace
swap(arr[p], arr[pivotPos]);
return p;
by
return p-1;
And, since the third argument of the function quickSort is <maximum index> + 1, the recursive call
quickSort(arr, left, partitionIndex - 1);
should be replaced by
quickSort(arr, left, partitionIndex);

c++ quicksort sort string text

I am doing my homework, and completed quicksort recursive, however it doesn't sort in a correct way. Seems to be it doesn't swap correctly.
Here is my code
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int quick_sort_help(string &text,int left, int right, int pivot){
char val = text[pivot];
char temp;
//swap
// temp =text[pivot];
//text[pivot]= text[right];
//text[right]=temp;
//swap(&text[left],&text[right]);
int l = left;
int r = right;
int i=left;
while (i<=r)
{
while (text[i]<val)
i++;
while (text[right]>val)
r--;
if (i<=r)
{
temp=text[i];
text[i]=text[r];
text[r]=temp;
i++;
r--;
}
}
return l;
}
void quicksort(string &text,int left, int right){
if (left < right){
int pivot=(left+right)/2;
int pivottwo = quick_sort_help(text, left, right, pivot);
quicksort(text, left, pivottwo - 1);
quicksort(text, pivottwo + 1, right);
}
}
void quick_sort(string &text,int size){
quicksort(text,0,size);}
int main()
{
string text="this is a test string text,.,!";
int size = text.length();
float t1, t2;
t1 = clock();
quick_sort(text,size);
t2=clock();
cout<<"quicksort Sort: "<<(t2-t1)/CLK_TCK*1000<<" msec\n";
cout<<text<<endl;
system("pause");
return 0;
}
the output I am getting:
hi a e e,g.nii,r!tssssxttttt
You have to:
1) Don't use size but size-1 value
void quick_sort(string &text,int size){
quicksort(text,0,size-1);}
2) Pivot is not (left+right)/2 but it's the value returned by quick_sort_help, and pivottwo is not necessary:
void quicksort(string &text,int left, int right)
{
if (left < right)
{
int pivot = quick_sort_help(text, left, right);
quicksort(text, left, pivot - 1);
quicksort(text, pivot + 1, right);
}
}
3) Test my j value (your r) in the second while and make the exchange before returning the pivot (the i value):
int quick_sort_help(string &text,int left, int right)
{
char val = text[right];
char temp;
int j = right;
int i = left - 1;
while (true)
{
while (text[++i] < val);
while (text[--j] > val) {
if(j == left)
break;
}
if(i >= j)
break;
temp=text[i];
text[i]=text[j];
text[j]=temp;
}
temp=text[i];
text[i]=text[right];
text[right]=temp;
return i;
}
Take a look at this : Quicksort implementation
while (text[right]>val)
r--;
That doesn't seem likely. You're decrementing r, but the condition you test never changes (should depend on r, probably...)
Also
return l;
looks suspicious, since the calling function seem to expect it to be the new position of the pivot, whereas it is the old left.
Another one, you use closed intervals (see why you shouldn't), which means you're accessing the string out-of bounds (which is UB).