Quicksort gives segmentation fault - c++

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
}

Related

Implementation of Quick Sort C++

I've learned about Quick Sort is a sorting algorithm which follows the principle of Divide and Conquer with average time complexity as n(log n) and worst time complexity as n^2.
Here I've selected middle element as pivot.
When it exceeds length of array then function returns the array.
I have used four functions to implement Merge Sort:
Quick Sort Functions
isSorted( ) returns true if array is sorted.
pivotPositioning( ) arrange pivot at it's ideal position.
quickSort( ) //wrapper function
quickSort( ) returns sorted array
Initial Pivot is selected as the middle element of the array by default argument.
It's giving an error, showing last element as -2 for even length of array (i.e. 4,8,10) after the sorting is done. I would like to know what's causing the error?
//C++ Code
#include<iostream>
void print(int *, int);
bool isSorted(int *arr, int high, int low=0)
{
for(int i=low; (i+1)<high; i++)
{
if(arr[i] > arr[i+1])
{
return false;
}
}
return true;
}
void pivotPositioning(int *arr, int high, int low)
{
for(int i=low; (i+1)<high; i++)
{
if(arr[i] > arr[i+1])
{
int temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
void quickSort(int *arr, int length, int pivot)
{
pivotPositioning(arr, pivot+1, 0);
//print(arr, length);
pivotPositioning(arr, length, pivot);
//print(arr, length);
}
int *quickSort(int *arr, int length)
{
int pivot = length/2;
quickSort(arr, length, pivot);
if (isSorted(arr, length) == false)
{
while (pivot > 0)
{
pivot--;
quickSort(arr, length, pivot);
}
while (pivot<length)
{
pivot++;
quickSort(arr, length, pivot);
}
}
return arr;
}
int main()
{
int length ;
std::cout<<"Enter length of the array: ";
std::cin>>length;
int arr[length] ;
for(int i=0; i<length; i++)
{
std::cout<<"Enter Element "<<(i+1)<<" : ";
std::cin>>arr[i];
}
quickSort(arr, length);
print(arr, length);
return 0;
}
void print(int *arr, int length)
{
std::cout<<"Sorted Array: ";
for(int i=0; i<length; i++)
{
std::cout<<arr[i]<<" ";
}
std::cout<<"\n";
}

I can't see why Im getting segmentation fault error

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

Merge Sort on Array of Int C++

I'm trying to create a program merge-sort on an array of int butI keep having troubles running this merge sort, it gives me a segment fault but I couldn't find anything wrong with it. In void mergesort when I put first <= last then the segment fault appears if not, then 5 5 5 5 is being print.
#include <iostream>
using namespace std;
void merge(int *arr, int size, int first, int middle, int last)
{
int temp[size];
for(int i = first; i<=last; i++)
{
temp[i] = arr[i];
}
int i=first, j=middle+1, k=0;
while(i<=middle && j<=last)
{
if(temp[i] <= temp[j])
{
arr[k] = temp[i];
i++;
}
else
{
arr[k]=temp[i];
j++;
}
k++;
}
while(i<=middle)
{
arr[k]=temp[i];
k++;
i++;
}
}
void mergesort(int *arr, int size, int first, int last)
{
if(first<last)
{
int middle = ( first + last )/2;
mergesort(arr,size,first,middle);
mergesort(arr,size,middle+1,last);
merge(arr,size,first,middle,last);
}
}
int main()
{
cout <<"Him";
const int size = 10;
int numbers [] = {5,10,1,6,2,9,3,8,7,4};
mergesort(numbers,size,0,9);
for( int i= 0; i<size; ++i)
{
cout << numbers[i] << " ";
}
return 0;
}
There are (at least) two bugs. This:
else
{
arr[k]=temp[i];
j++;
}
should be this:
else
{
arr[k]=temp[j];
j++;
}
and this:
int i=first, j=middle+1, k=0;
should be this:
int i=first, j=middle+1, k=first;
In general, you ought to learn to step through the code, at least by putting diagnostic output statements here and there. Once you have the hang of that you can move up to a good debugger.
The standard library already implements a function that merges correctly: std::inplace_merge. Implementation adapted from this more general post
void mergesort(int * first, int * last)
{
std::ptrdiff_t N = std::distance(first, last);
if (N <= 1) return;
int * middle = std::next(first, N / 2);
mergesort(first, middle);
mergesort(middle, last);
std::inplace_merge(first, middle, last);
}
int main()
{
cout <<"Him";
const int size = 10;
int numbers [] = {5,10,1,6,2,9,3,8,7,4};
mergesort(numbers, numbers+size);
for( int i= 0; i<size; ++i)
{
cout << numbers[i] << " ";
}
return 0;
}
Suggestion 1:
Instead of that line:
int temp[size];
If you need a dynamic size array use:
int temp = new int[size];
Then once you are done with it
delete[] temp;
Edit: As Neil suggested using std::vector is may be more useful than arrays in such situations (if you are allowed to use it).
Your code has 3 bugs, Also you can reduce your code length too if required.
void merge(int *arr, int size, int first, int middle, int last)
{
int temp[size];
for(int i = first; i<=last; i++)
temp[i] = arr[i];
int i=first, j=middle+1, k=first; // 1st Change, Set k to first instead of 0
while(i<=middle && j<=last)
{
if(temp[i] <= temp[j])
arr[k++] = temp[i++];
else
arr[k++]=temp[j++]; // 2nd Change, use j instead of i
}
while(i<=middle)
arr[k++]=temp[i++];
while(j<=last) // 3rd Change you missed this case
arr[k++]=temp[j++];
}
Live Code

Merge sort not working completely

The code that I have made for merge sort is given below. The thing is that on giving the input the output is 3 2 1 5 0. What is going wrong?
#include <iostream>
#include <cmath>
using namespace std;
int d[100];
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(i<n2 && j<(n-n2))
{
if(b[i]<c[j])
{
d[k++]=b[i++];
}
else if(b[i]>c[j])
{
d[k++]=c[j++];
}
}
if(i==n2)
{
if(j<(n-n2))
{
d[k++]=c[j++];
}
}
if(i<n2)
{
d[k++]=b[i++];
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<d[i]<<endl;
}
}
The main problem is that the arrays (b and c) passed to merge are not sorted.
Other problems are that the algorithm is not recursive and that merge
does not always put all numbers from b and c into a.
A version that seems to work with minimal changes to your code would be
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(k<n)
{
if((j == (n-n2) || b[i]<c[j]) && i < n2)
{
a[k++]=b[i++];
}
else
{
a[k++]=c[j++];
}
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
if(n2 > 1) {
mergesort(b, n2);
}
if(n - n2 > 1) {
mergesort(c, n - n2);
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
}
}
It is conventional to call merge_sort recursively in order to sort each subrange until the subrange is just one long then merge these together.
In your mergesort, b takes the first n/2 values of a, that is 5 and 4.
c takes the remaining values 3,2,1.
You then call merge (BTW Why do you pass a[] to this? It isn't used)
The first loop
while(i<n2 && j<(n-n2))
will have n2 = 2 and n-n2 = 5-2 = 3
This puts 3 at the start since b[0]>c[0]=3 and 2 next since b[1]>c[1]=2 and 1 at d[2] for similar reasons.
Since you don't recurse you won't sort these.
You then finish the while loop with i = 0 which is less than n2.
You just say
if(i<n2)
so you just copy the first thing from b which is 5.
All this gives 3, 2, 1, 5, and 0 because you made d global.
The input for merge need to be sorted arrays, as Philip mentioned before. Mergesort is recursive. For this you need to divide them till you reach a point where you only have one element in the array (so it is sorted) and merge all arrays to become the sorted result for the input. Wikipedia is your friend to understand the algorithm: Mergesort
Btw: You need to ensure that one of both cases in the comparison in the merge checks also on equality of the values.
Philip is right, there's no recursive in your code at all.
However, there are some more errors. I've marked it with annotations, just as a postscript of Philip's.
#include <iostream>
#include <cmath>
using namespace std;
int d[100];
void merge(int a[], int b[], int c[], int n)
{
int n2=floor(n/2);
int i=0, j=0, k=0;
while(i<n2 && j<(n-n2))
{
if(b[i]<c[j])
{
d[k++]=b[i++];
}
else if(b[i]>c[j])
{
d[k++]=c[j++];
}
/***************************************************/
/* What if b[i] == c[j] here? */
/* Your code will drop into an infinity loop. */
/***************************************************/
}
if(i==n2)
{
if(j<(n-n2))
/****************************************************/
/* Use **while** here? */
/* Because there may be more than one elements left */
/* in c[]. */
/****************************************************/
{
d[k++]=c[j++];
}
}
if(i<n2)
/***************************************************/
/* Use **while** here? - With the same reason */
/***************************************************/
{
d[k++]=b[i++];
}
}
void mergesort(int a[], int n)
{
int n2=floor(n/2);
int b[50],c[50];
int i,j=0,k=0;
for(i=0;i<n2;i++)
{
b[i]=a[k++];
}
while(k<n)
{
c[j++]=a[k++];
}
merge(a,b,c,n);
}
int main()
{
int a[]={5,4,3,2,1};
int n=5;
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<d[i]<<endl;
}
}
template <typename T>
void merge(T arr[], int begin, int mid, int end)
{
int len = end - begin;
T *temp = new T[len];
int i = begin;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= end)
{
if(arr[i] <= arr[j])
temp[k++] = arr[i++];
else
temp[k++] = arr[j++];
}
while (i <= mid)
temp[k++] = arr[i++];
while(j <= end)
temp[k++] = arr[j++];
memcpy(arr + begin, temp, len*sizeof(T));
delete []temp;
}
template <typename T>
void mergeSort(T arr[], int begin, int end)
{
if (begin >= end)
return;
int mid = (end + begin) / 2;
mergeSort(arr, begin, mid);
mergeSort(arr, mid + 1, end);
merge(arr, begin, mid, end);
}

C++ quick sort algorithm

I'm not looking to copy a qsort algorithm. I'm practicing writing qsort and this is what I've come up with and I'm interested in what part of my code is wrong. Please don't tell me that this is homework cause I could just use the code in the link below.
Reference: http://xoax.net/comp/sci/algorithms/Lesson4.php
When this runs I get this in the console:
Program loaded.
run
[Switching to process 10738]
Running…
Current language: auto; currently c++
Program received signal: “EXC_ARITHMETIC”.
void myQSort(int min, int max, int* myArray)
{
// Initially find a random pivot
int pivotIndex = rand() % max;
int pivot = myArray[pivotIndex];
int i = 0 , j = max-1;
// Pointer to begining of array and one to the end
int* begin = myArray;
int* end = &myArray[max-1];
// While begin < end
while( begin < end )
{
// Find the lowest bound number to swap
while( *begin < pivot )
{
begin++;
}
while( *end > pivot )
{
// Find the highest bound number to swap
end--;
}
// Do the swap
swap(begin,end);
}
// Partition left
myQSort(0, pivotIndex-1, myArray);
// Partiion right
myQSort(pivotIndex+1,max, myArray);
}
EDIT--
Code for Swap:
void swap(int* num, int* num2)
{
int temp = *num;
*num = *num2;
*num2 = temp;
}
// sort interval [begin, end)
void myQSort(int* begin, int* end)
{
if(end - begin < 2)
return;
int* l = begin;
int* r = end - 1;
// Initially find a random pivot
int* pivot = l + rand() % (r - l + 1);
while(l != r)
{
// Find the lowest bound number to swap
while(*l < *pivot) ++l;
while(*r >= *pivot && l < r) --r;
// Do the swap
if(pivot == l) { pivot = r; }
std::swap(*l, *r);
}
// Here l == r and numbers in the interval [begin, r) are lower and in the interval [l, end) are greater or equal than the pivot
// Move pivot to the position
std::swap(*pivot, *l);
// Sort left
myQSort(begin, l);
// Sort right
myQSort(l + 1, end);
}
You're not using the min parameter in your code, anywhere. You need to set begin and your pivot value using that.
I tried working out the codes above. But, they don't compile.
#Mihran: Your solution is correct algorithmically but the following line generates an error:
myQSort(min, begin - myArray, myArray);
This is because begin is of type int* and myArray is of type long, following which the compiler shows this error message:
implicit conversion loses integer precision
Here's a working solution in C++:
#include <iostream>
using namespace std;
void mySwap(int& num1, int& num2){
int temp = num1;
num1 = num2;
num2 = temp;
}
void myQsort(int myArray[], int min, int max){
int pivot = myArray[(min + max) / 2];
int left = min, right = max;
while (left < right) {
while (myArray[left] < pivot) {
left++;
}
while (myArray[right] > pivot) {
right--;
}
if (left <= right) {
mySwap(myArray[left], myArray[right]);
left++;
right--;
}
}
if (min < right) {
myQsort(myArray, min, right);
}
if (left < max) {
myQsort(myArray, left, max);
}
}
int main()
{
int myArray[] = {1, 12, -5, 260, 7, 14, 3, 7, 2};
int min = 0;
int max = sizeof(myArray) / sizeof(int);
myQsort(myArray, min, max-1);
for (int i = 0; i < max; i++) {
cout<<myArray[i]<<" ";
}
return 0;
}
Here's a clear C++ implementation, for reference:
#include <iostream>
#include <vector>
using namespace std;
int partition(std::vector<int>& arr, int low, int high) {
// set wall index
int wall_index = low;
int curr_index = low;
int pivot_elem = arr[high]; // taking last element as pivot_element
// loop through the entire received arr
for (int i = curr_index; i < high; ++i) {
// if element is less than or equal to pivot_elem
// swap the element with element on the right of the wall
// i.e swap arr[i] with arr[wall_index]
if (arr[i] <= pivot_elem) {
// swap
int temp = arr[wall_index];
arr[wall_index] = arr[i];
arr[i] = temp;
// move the wall one index to the right
wall_index++;
curr_index++;
} else {
// if the element is greater than the pivot_element
// then keep the wall at the same point and do nothing
curr_index++;
}
}
// need to swap the pivot_elem i.e arr[high] with the element right of the wall
int temp = arr[wall_index];
arr[wall_index] = arr[high];
arr[high] = temp;
return wall_index;
}
void quick_sort(std::vector<int>& arr, int low, int high) {
if (low < high) { // element with single arr always have low >= high
int split = partition(arr, low, high);
quick_sort(arr, low, split-1);
quick_sort(arr, split, high);
}
}
int main() {
std::vector<int> data = {6,13,8,4,2,7,16,3,8};
int N = data.size();
quick_sort(data, 0, N-1);
for (int i : data) {
cout << i << " ";
}
return 0;
}
I don't see a clean implementation of Quicksort on SO, so here is my easy to understand implementation
PLEASE DONT USE IN PRODUCTION CODE
This is only for your understanding
// Swap position a with b in an array of integer numbers
void swap(int *numbers, int a, int b){
int temp = numbers[a];
numbers[a] = numbers[b];
numbers[b] = temp;
}
static int partition(int *data, int low, int high) {
int left = low, right = high, pivot = data[low];
while (left < right) {
// Everthing on the left of pivot is lower than the pivot
while ((left <= right) && data[left] <= pivot) // <= is because left is the pivot initially
left++;
// Everything on the right of the pivot is greater than the pivot
while((left <= right) && data[right] > pivot)
right--;
if (left < right)
swap(data, left, right);
}
// Put the pivot in the 'rigthful' place
swap(data, low, right);
return right;
}
// Quicksort
static void quick_sort(int *numbers, int low, int high)
{
if (high > low) {
int p_index = partition(numbers, low, high);
quick_sort(numbers, low , p_index - 1);
quick_sort(numbers, p_index + 1, high);
}
}