I'm currently trying to learn Quick Sort, and here is my code:
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
int partition(vector<int> &A, int low, int high)
{
int pivot = A[low];
int i = low;
int j = high;
while(i < j){
do
{
i++;
}while(A[i]>=pivot);
do
{
j--;
}while(A[j]<pivot);
if(i < j)
{
swap(A[i], A[j]);
}
}
swap(A[low], A[j]);
return j;
}
void QuickSort(vector<int> &A, int low, int high)
{
int j = partition(A, low, high);
QuickSort(A, low, j);
QuickSort(A, j+1, high);
}
int main()
{
vector<int> A{-7, 11, -3, 3, 2};
QuickSort(A, 0, A.size()-1);
for(int i:A)
{
cout << i << endl;
}
}
after the code ran, I keep getting Segmentation fault (core dumped), how do I fix this error.
also, could any one recommend a good c++ debugger. thank you so much
You have infinite recursion in your QuickSort function. Whenever it gets called, it'll call itself and there is no condition there to break the cycle.
Also, your swap function does not work. As it is written, the values in the A bins will be supplied to the function and interpreted as addresses. That should not compile. The only reason why it does compile is that you don't use that function in your program. You are using std::swap because you've done using namespace std;, so don't do that.
Your swap function should take the arguments by reference and you need to add a condition in the QuickSort function.
I wasn't sure exactly which partitioning scheme you tried implementing so I made some changes to make it work in accordance with the Hoare partition scheme.
#include <iostream>
#include <vector>
void swap(int& a, int& b) { // take arguments by reference
int t = a;
a = b;
b = t;
}
size_t partition(std::vector<int>& A, size_t low, size_t high) {
int pivot = A[(high + low) / 2];
size_t i = low;
size_t j = high;
while(true) {
while(A[i] < pivot) ++i;
while(A[j] > pivot) --j;
if(i >= j) return j;
swap(A[i], A[j]);
++i;
--j;
}
}
void QuickSort(std::vector<int>& A, size_t low, size_t high) {
if(low < high) { // added condition
size_t j = partition(A, low, high);
QuickSort(A, low, j);
QuickSort(A, j + 1, high);
}
}
int main() {
std::vector<int> A{-7, 11, -3, 3, 2};
QuickSort(A, 0, A.size() - 1);
for(int i : A) {
std::cout << i << '\n';
}
}
Related
Here is the pseudocode straight from the book (CORMEN):
Partition(A,p,r)
x=A[p]
i=p-1
j=r+1
while(TRUE)
repeat
j=j-1
until A[j]<=x
repeat
i=i+1
until A[i]>=x
if i<j
SWAP A[i] <=> A[j]
else return j
Here is code in C++:
#include<bits/stdc++.h>
using namespace std;
int partition(int a[], int low, int high)
{
int pivot = a[low];
int i = low - 1;
int j = high + 1;
while (1)
{
do {
i++;
} while (a[i] < pivot);
do {
j--;
} while (a[j] > pivot);
if (i >= j) {
cout<<j<<endl;
return j;
}
swap(a[i], a[j]);
}
}
/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place*/
int pi = partition(arr, low, high);
// Separately sort elements before
// partition and after partition
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
/* Function to print an array */
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// Driver program to test above functions
int main()
{
int arr[] = {7,3,2,6,4,1,3,5};
int n = sizeof(arr)/sizeof(arr[0]);
cout<<"partition:\n";
partition(arr,0,7);
printArray(arr, n);
quickSort(arr, 0, n-1);
printf("Sorted array: \n");
printArray(arr, n);
return 0;
}
If I use this array in input:
[5,3,2,6,4,1,3,7]
everything works logically well because the array returned by the partitioning will be:
[3,3,2,1,4,6,5,7]
Termination i=5 and j=4 so my pivot is 4. And all elements to the left of 4 are minor and all to the right are major
Now if I use this array in input:
[7,3,2,6,4,1,3,5]
I will have this situation at the end of the partition
[5,3,2,6,4,1,3,7]
which will return to me as pivot j = 6 that is 3. Now the elements on the left of 3 are not all minor and on the right are major.
But how is it possible that this works? Shouldn't I have the elements to the left of the pivot minor and to the right major?
With Hoare partition the pivot and values equal to the pivot can end up anywhere. The returned index is not an index to the pivot, but just a separator. For the code above, when partition is done, then elements <= pivot will be at or to the left of j, and elements >= pivot will be to the right of j. After doing a partition step, the C++ code should be:
quickSort(arr, low, pi); // not pi - 1
quickSort(arr, pi + 1, high);
example code that includes testing of quicksort:
uint32_t Rnd32()
{
static uint32_t r = 0;
r = r*1664525 + 1013904223;
return r;
}
int Partition(int ar[], int lo, int hi)
{
int pv = ar[lo+(hi-lo)/2];
int i = lo - 1;
int j = hi + 1;
while(1){
while(ar[++i] < pv);
while(ar[--j] > pv);
if(i >= j)
return j;
std::swap(ar[i], ar[j]);
}
}
void QuickSort(int ar[], int lo, int hi)
{
while (lo < hi){
int pi = Partition(ar, lo, hi);
if((pi - lo) < (pi - hi)){
QuickSort(ar, lo, pi);
lo = pi + 1;
} else {
QuickSort(ar, pi + 1, hi);
hi = pi;
}
}
}
#define COUNT (16*1024*1024)
int main(int argc, char**argv)
{
size_t i;
int * ar = new int [COUNT];
for(i = 0; i < COUNT; i++){
ar[i] = Rnd32();
}
QuickSort(ar, 0, COUNT-1);
for(i = 1; i < COUNT; i++)
if(ar[i-1] > ar[i])
break;
if(i == COUNT)
std::cout << "passed" << std::endl;
else
std::cout << "failed" << std::endl;
delete[] ar;
return(0);
}
I have implemented quick sort in c++. Following is my code .
#include <iostream>
using namespace std;
template <typename T>
void swap(T *a, T *b)
{
T temp;
temp = *a;
*a = *b;
*b = temp;
}
template <typename T>
void PrintArray(T arr[], int n)
{
cout << "---------- Array ----------" << endl;
for (int i=0; i<n ; i++)
{
cout << arr[i] <<'\t';
}
cout << endl;
}
template <typename T>
int partition(T arr[], int low, int high)
{
T pivot = arr[low];
int i = low+1, j = high;
do
{
while (pivot >= arr[i])
{
i += 1;
}
while (pivot < arr[j])
{
j -= 1;
}
if (i<j)
{
swap<T>(arr[i], arr[j]);
}
}while( i < j);
swap<T>(arr[low], arr[j]);
return j;
}
template <typename T>
void quick_sort(T arr[], int low, int high)
{
if (low < high)
{
int parition_index;
parition_index = partition<T>(arr, low, high);
quick_sort<T>(arr, low, parition_index-1);
quick_sort<T>(arr, parition_index+1, high);
}
}
int main()
{
// Array creation
int n = 8;
int a[] ={4, 3,2, 1, 18, -1, 89, -200};
// Array sorting
quick_sort<int>(a,0, n);
PrintArray<int>(a, n);
return 0;
}
It gives sorted array i.e -200, -1, 1, 2, 3, 4, 18, 89 most of the times. However, re-running the code may gives garbage values at some indices (for ex: -968225408, -200, -1, 1, 2, 3, 4, 18). To check, I replaced all the functions in the code above with the functions from blocks in the post https://www.geeksforgeeks.org/quick-sort/ . Nonetheless, the problem persists.
What could be the problem with the code and what is the solution to the problem.
#FrançoisAndrieux comments were very useful in finding out the problem.
As he pointed out that j is taking 8 as value which is out of bounds.
To solve the problem
step 1: quick_sort<int>(a,0, n-1); in the int main().
steps 2: knock off the custom swap function
Like the title says, I am trying to write a code for QuickSort, but I am trying to do this following a psuedocode given to us in the lecture. This isn't an assignment that's due it's just me trying to figure it out on my own. I've found a sample of QuickSort online, but it looks different than what our psuedocode says. The QuickSort code i found online uses pointers, i don't think pointers are mentioned in the given psuedocode. In other words, could someone check if im on the right path and maybe point out where I messed up. Thank you!
My code
#include <iostream>
using namespace std;
int Partition(int arr[], int p, int r)
{
int x = arr[r];
int i = p - 1;
for (int j = p; j < r - 1; j++)
{
if (arr[j] <= x)
{
i = i + 1;
swap(arr[i], arr[j]);
}
swap(arr[i + 1], arr[r]);
}
return i + 1;
}
void Quicksort(int arr[], int p, int r)
{
if (p < r)
{
int k = Partition(arr, p, r);
Quicksort(arr, p, k - 1);
Quicksort(arr, k + 1, r);
}
}
void print(int arr[], int n)
{
int i;
for (i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
}
int main()
{
int arr[] = { 5, 3, 4, 9, 10 };
int n = sizeof(arr) / sizeof(arr[0]);
Quicksort(arr, 0, n);
print(arr, n);
//I get an error here "Stack around the variable 'arr' was corrupted"
}
This is the psuedocode for my QuickSort function
Picture number two is the given psuedocode for my Partition function
In Partition(), if i is never incremented, then a swap(arr[p-1], ...) is done, probably the cause of the stack error. Normally, quick sort parameters are first and last index, as opposed to first and end (= last+1) index, in this case, Quicksort(arr, 0, n-1). The inner loop is looking for values < pivot (not <= pivot). The final swap needs to be done after the for loop. Fixes noted in comments.
#include <iostream>
using namespace std;
int Partition(int arr[], int p, int r)
{
int x = arr[r];
int i = p; // fix
for (int j = p; j < r; j++) // fix
{
if (arr[j] < x) // fix
{
swap(arr[i], arr[j]);
i = i + 1; // fix
}
}
swap(arr[i], arr[r]); // fix
return i; // fix
}
void Quicksort(int arr[], int p, int r)
{
if (p < r)
{
int k = Partition(arr, p, r);
Quicksort(arr, p, k - 1);
Quicksort(arr, k + 1, r);
}
}
void print(int arr[], int n)
{
int i;
for (i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
}
int main()
{
int arr[] = { 5, 3, 4, 9, 10 };
int n = sizeof(arr) / sizeof(arr[0]);
Quicksort(arr, 0, n-1); // fix
print(arr, n);
return 0; // fix
}
I tried to implement the Quicksort algorithm. Here is the code for the Quicksort itself
void quicksortlast(double* a, int first, int last)
{
if(first<last)
{
int pIndex=partition(a, first, last);
quicksortlast(a, first, pIndex-1);
quicksortlast(a, pIndex+1, last);
}
}
The pIndex variable is the location of the element which is at the right position. I choose the last array element as pivot in the partitioning scheme. The following code is supposed to partition the array:
int partition(double* a, int first, int last)
{
int pivot=last;
int i=0;
int j=last-1;
while(i<j && i<=last && j>=0)
{
while(a[i++]<a[pivot])
{
if(i>last)
break;
}
while(a[j--]>a[pivot])
{
if(j<0)
break;
}
if(i<j && i<=last && j>=0)
{
swap(a,i,j);
i++;
j--;
}
}
swap(a,j,pivot);
return j;
}
The partition function uses the swap function defined as
void swap(double* a, int left, int right)
{
int temp=a[left];
a[left]=a[right];
a[right]=temp;
return;
}
And, of course, there is the test.cpp function that tests the algo.
#include <iostream>
#include "qsort.h"
using namespace std;
int main()
{
int len;
cin>>len;
double* a= new double[len];
for(int i=0;i<len;i++)
cin>>a[i];
cout<<"Unsorted array"<<endl;
print(a,len);
quicksortlast(a, 0, len-1);
cout<<"printed array"<<endl;
print(a, len);
return 0;
}
The print function on its first call prints the unsorted array but the it gives me error an message :
Segmentation fault(core is dumped).
I understand, that some memory location is accessed, but I do not understand where the actual mistake lies. Any help is highly appreciated.
You're code goes into a infinite loop which result in a stack overflow error. The pseudo code of the algorithm can be found on wikipedia and the right implementation should be something like that :
#include <stdio.h>
// Example program
#include <iostream>
#include <string>
void swap(double* a, int left, int right)
{
int temp = a[left];
a[left] = a[right];
a[right] = temp;
return;
}
int partition(double* a, int first, int last)
{
int pivot = last;
int i = 0;
for (int j = 0; j < last - 1; j++) {
if (a[j] < pivot) {
swap(a, i, j);
i++;
}
}
swap(a, i, last);
return i;
}
void quicksortlast(double* a, int first, int last)
{
if (first < last)
{
int pIndex = partition(a, first, last);
quicksortlast(a, first, pIndex - 1);
quicksortlast(a, pIndex + 1, last);
}
}
using namespace std;
int main()
{
int len;
cin >> len;
double* a = new double[len];
for (int i = 0; i < len; i++)
cin >> a[i];
quicksortlast(a, 0, len - 1);
return 0;
}
The partition code needs several fixes. The code is using 0 in cases where it should be using first instead. The swap function is converting from double to int and back, and std::swap can be used instead.
For a quicksort that scans from both ends of an array towards the middle, the middle is normally used for the pivot, since this eliminates having to use index checks to avoid scanning beyond the ends of the array, which is probably the reason the code is getting a segmentation fault. The scanning stops when the scanning indexes cross each other. Which index to return and what that index represents depends on the specific implementation.
Example code for typical Hoare partition scheme. If using iterators instead of indexes, low-1 can't be used and the partition function needs a minor change to handle the initial compare using a[i] < pivot instead of a[++i] < pivot. High+1 isn't an issue because that is the same as the "end" iterator.
int Partition(double a[], int low, int high)
{
double pivot = a[low+(high-low)/2];
int i = low - 1;
int j = high + 1;
while(1)
{
while(a[++i] < pivot);
while(a[--j] > pivot);
if(i >= j)
return j;
std::swap(a[i], a[j]);
}
}
void QuickSort(double a[], int low, int high)
{
if (low < high)
{
int index = Partition(a, low, high);
QuickSort(a, low, index); // not index - 1 for Hoare
QuickSort(a, index + 1, high);
}
}
Example Hoare like partition scheme which uses post increment and post decrement
int partition(double a[], int first, int last)
{
double pivot = a[first+(last-first)/2]; // use middle for pivot
while(first <= last) {
while (a[first] < pivot)
first++;
while (a[last] > pivot)
last--;
if(first > last)
break;
std::swap(a[first],a[last]);
first++;
last--;
}
return first; // index to 1st element of right part
}
void quicksort(double a[], int first, int last)
{
if(first >= last) // style change
return;
int index=partition(a, first, last);
// index to 1st element of right part
quicksort(a, first, index-1);
quicksort(a, index, last); // not index+1 for this implementation
}
#include <iostream>
#include <cstdlib>
using namespace std;
void print(int a[], int sz)
{
for (int i = 0; i < sz; i++) cout << a[i] << " ";
cout << endl;
}
void merge(int a[], const int low, const int mid, const int high)
{
int *temp = new int[high-low+1];
int left = low;
int right = mid+1;
int current = 0;
// Merges the two arrays into temp[]
while(left <= mid && right <= high)
{
if(a[left] <= a[right])
{
temp[current] = a[left];
left++;
}
else { // if right element is smaller that the left
{
// if right element is smaller that the left
temp[current] = a[right];
right++;
}
current++;
}
// Fills the array
// The temp array has already been filled
// Use the right side of array to fill temp
if(left > mid)
{
for(int i=right; i <= high;i++)
{
temp[current] = a[i];
current++;
}
}
// Use the left side of array to fill temp
else
{
for(int i=left; i <= mid; i++)
{
temp[current] = a[i];
current++;
}
}
//Fill into original array
for(int i=0; i<=high-low;i++)
{
a[i+low] = temp[i];
}
delete[] temp;
}
void merge_sort(int a[], const int low, const int high)
{ // <-- Error #68
if(low >= high) return;
int mid = (low+high)/2;
merge_sort(a, low, mid); //left half
merge_sort(a, mid+1, high); //right half
merge(a, low, mid, high); //merge them
}
int main()
{ //<-- Error #77
int a[] = {26, 5, 33, 6, 19, 69, 99};
int arraySize = sizeof(a)/sizeof(int);
print(a, arraySize);
merge_sort(a, 0, (arraySize-1));
print(a, arraySize);
return 0;
} //<-- Error #87
// This code is supposed to implement the Merge sort algorithm in c++.
However when ever i compile my code it runs into a bunch of errors.
mergesort.cpp: In function ‘void merge(int*, int, int, int)’:
mergesort.cpp:68: error: a function-definition is not allowed here before ‘{’ token
mergesort.cpp:77: error: a function-definition is not allowed here before ‘{’ token
mergesort.cpp:87: error: expected ‘}’ at end of input
I have indicated where the erros are in the code
Can anyone help me please?
#include <iostream>
#include <cstdlib>
using namespace std;
void print(int a[], int sz)
{
for (int i = 0; i < sz; i++) cout << a[i] << " ";
cout << endl;
}
void merge(int a[], const int low, const int mid, const int high)
{
int *temp = new int[high-low+1];
int left = low;
int right = mid+1;
int current = 0;
// Merges the two arrays into temp[]
while(left <= mid && right <= high)
{
if(a[left] <= a[right])
{
temp[current] = a[left];
left++;
}
else
{
// if right element is smaller that the left
temp[current] = a[right];
right++;
}
current++;
}
// Fills the array
// The temp array has already been filled
// Use the right side of array to fill temp
if(left > mid)
{
for(int i=right; i <= high;i++)
{
temp[current] = a[i];
current++;
}
}
// Use the left side of array to fill temp
else
{
for(int i=left; i <= mid; i++)
{
temp[current] = a[i];
current++;
}
}
//Fill into original array
for(int i=0; i<=high-low;i++)
{
a[i+low] = temp[i];
}
delete[] temp;
}
void merge_sort(int a[], const int low, const int high)
{
if(low >= high) return;
int mid = (low+high)/2;
merge_sort(a, low, mid); //left half
merge_sort(a, mid+1, high); //right half
merge(a, low, mid, high); //merge them
}
main()
{
int a[] = {26, 5, 33, 6, 19, 69, 99};
int arraySize = sizeof(a)/sizeof(int);
print(a, arraySize);
merge_sort(a, 0, (arraySize-1));
print(a, arraySize);
}
You are getting this error because you write an extra { on line 27, which will mess up all those { } matching.
Delete that you will pass the compile.
Hope this helps.