Stack Smashing detected while implementing mergeSort in C++14 - c++

I am implementing standart MergeSort algorithm. I am getting a runtime error 'Stack Smashing Detected'. What is the root cause of such error and how to prevent my code from this error?
I saw that the control is coming to merge function , but somewhere it is getting messed up.
#include<iostream>
using namespace std;
//this particular function will merge 2 sorted array
void merge(int arr[], int res[], int low, int mid, int high) {
int i=low,j=mid+1,k=high;
while(i<=mid && j<=high) //make sure that i remains within the end if left subarray and j remains within the end of right subarray
{
if(arr[i]<=arr[j])
res[k++]=arr[i++];
else
res[k++]=arr[j++];
}
while(i<=mid) // In case there are some elements left in left subarray, just copy it into result
res[k++]=arr[i++];
while(j<=high) //// In case there are some elements left in right subarray, just copy it into result
res[k++]=arr[j++];
//copy the result into original array
for( i=low;i<=high;i++)
arr[i]=res[i];
}
void mergeSort(int arr[], int res[], int low, int high) {
//Don't forget to put the base case in recursion
if(high == low)
return;
int mid = low + (high-low)/2;
mergeSort(arr,res,low,mid);
mergeSort(arr,res,mid+1,high);
merge(arr,res,low,mid,high);
cout<<"end of recursion"<<endl;
}
int main() {
int arr[] = {8,4,3,12,25,6,13,10};
// initialise resultant array (temporary)
int res[]= {8,4,3,12,25,6,13,10};
for(int i=0 ;i<8 ; i++)
cout<<arr[i]<<" ";
cout<<endl;
mergeSort(arr,res,0,7);
for(int i=0 ;i<8 ; i++)
cout<<arr[i]<<" ";
cout<<endl;
}

The problem is in your merge routine. If you look at the case where low and mid are 6 and high is 7, which will happen towards the end of the recursion, the loop
while (i <= mid)
res[k++] = arr[i++];
will end up executing with k being out-of-bounds. I think you meant for k to be initialized to low because it is supposed to be in sync with i.

Related

Randomly Shuffle an array and using quick sort algorithm

I have been trying to write a code to randomly shuffle the array elements, and then use the quick sort algorithm on the array elements. This is the code I wrote:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void randomise(int arr[], int s, int e)
{
int j;
srand(time(NULL));
for (int i = e; i >= s; i--)
{
int j = rand() % (i + 1);
swap(&arr[i], &arr[j]);
}
}
int Partition(int arr[], int s, int e)
{
int pivot = arr[e];
int i = s - 1;
int j;
for (j = s; j <= e; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[e]);
return i + 1;
}
void QuickSort(int arr[], int s, int e)
{
if (s >= e)
return;
int x = Partition(arr, s, e);
QuickSort(arr, s, x - 1);
QuickSort(arr, x + 1, e);
}
int main()
{
int b[] = {1, 2, 3, 4, 5};
randomise(b, 0, 4);
cout << "Elements of randomised array are:";
for (int i = 0; i <= 4; i++)
{
cout << b[i] << endl;
}
QuickSort(b, 0, 4);
cout << "Elements after quick sort are:";
for (int i = 0; i <= 4; i++)
{
cout << b[i] << endl;
}
return 0;
}
However, on debugging on GDB, I found out that this program gives segmentation fault. On execution, this program gives the output as:
Elements of randomised array are:4
5
2
3
1
Can someone tell me what is the bug in this code (I have tried debugging it on GDB, but I am still clueless).
Basically, when the error is segmentation fault, you should be looking for a bug which you will feel like crashing your head into wall, after finding it. On line 26. change <=, to < . It's in your partition function. for (j = s; j < e; j++)
A little explanation about quick sort; After each time quickSort function runs on a partiotion, the last element of the partition, called pivot, will reach its' real place in array. The partition function, returns the real place of the pivot in the array. Then the main array will be split into two more partitions, before the pivot place, and after that. Your bug is returning real-pivot-place + 1, as the output of partition function. So you will run quickSort on wrong partition; the partition that is already sorted but the program will keep trying to sort it over and over because of wrong partitioning. As you may know, each time you run a function, its' variables will be saved into a stack in computer. Since your calling a recursive function over and over(that isn't supposed to stop), this stack will get full and will overflow. After that, computer will represent some undefined behavior and maybe throw an exception that can not describe the problem correctly. This is why your getting segmentation fault. But why you return real-pivot-place + 1? Because in your for loop in partition function, you will visit the pivot too, which you shouldn't. Because pivot isn't supposed to be compared with itself. So you will increase i variable unnecessarily. https://en.wikipedia.org/wiki/Call_stack Check this link for additional information about stack and how a function runs in computer.

I am getting garbage values in my Merge Sort code

I am trying to implement merge sort algorithm in C++. This is my code.Logic seems to be fine.
But the output I'm getting is garbage values.I'm not able to get where the problem is in the code.
I think my logic is correct but I'm not sure.
#include <iostream>
using namespace std;
void Merge(int A[],int L[],int nL,int R[],int nR);
void MergeSort(int A[]);
//Function to Merge Arrays L and R into A.
//nL = number of elements in L
//nR = number of elements in R.
void Merge(int A[],int L[],int nL,int R[],int nR)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
int i=0;
int j=0;
int k=0;
while(i<nL && j<nR)
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<nL)
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<nR)
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(int A[],int n)
{
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
int left[mid];
int right[n-mid];
for(int i=0;i<mid-1;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n-1;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left,mid);
MergeSort(right,n-mid);
Merge(A,left,mid,right,n-mid);
}
int main()
{ int A[]={2,4,7,1,5,3};
int n=sizeof(A)/sizeof(A[0]);
MergeSort(A,n);
for(int i=0;i<n;i++) cout<<A[i]<<" ";
return 0;
}
Expected output is 1 2 3 4 5 7
But actual is 0 -785903160 1 0(every time it's different)
This has been answered at, how-to-implement-classic-sorting-algorithms-in-modern-c. But I thought I'd post an answer that beginners my find valuable as I've seen this asked many times in the past. It must be a popular homework question.
In my opinion, if this is a modern C++ assignment, there should be a lot less of using indexing.
So in this implementation, I have not used std::merge and wrote the merge so some method could be seen.
Avoid the idiom: using namespace std; Why it is taught is beyond me. Typedef your types, it is much clearer.
using data_vect = std::vector<int>;
Hopefully this is clear enough and completely done with iterators. It is not as efficient as possible, the push_back in Merge could be avoided among other things. I DuckDucked this sort and the first few hits were not that great.
#include <iostream>
#include <vector>
using data_vect = std::vector<int>;
using dv_iter = data_vect::iterator;
data_vect Merge(data_vect& first, data_vect& second)
{
data_vect result;
dv_iter fval = first.begin();
dv_iter sval = second.begin();
for (;fval != first.end() || sval != second.end();)
{
if (fval == first.end())
result.push_back(*sval++);
else if (sval == second.end())
result.push_back(*fval++);
else if (*fval < *sval)
result.push_back(*fval++);
else
result.push_back(*sval++);
}
return result;
}
void MergeSort(data_vect& input)
{
int half = input.size() / 2;
if (! half)
return;
data_vect left(input.begin(), input.begin() + half );
data_vect right(input.begin() + half, input.end());
MergeSort(left);
MergeSort(right);
input = Merge(left, right);
}
int main()
{
data_vect A = { 6,2,7,4,1,5,3 };
MergeSort(A);
for ( auto& val : A )
std::cout << val << " ";
return 0;
}
Although understandable,
it is not possibile in C++ to declare an array with a variable size, e.g. int[mSize].
All arrays must have a constant size, e.g. int[10] or
const int mSize = 10;
int[mSize] mArray...
You want a storage container which has a variable size. as #PaulMcKenzie suggested,
you might want to use a Vector object. Your code would look something like this:
#include <iostream>
#include <vector>
using namespace std;
void Merge(vector<int>& A, vector<int>& L, vector<int>& R);
void MergeSort(vector<int>& A);
//Function to Merge Arrays L and R into A.
void Merge(vector<int>& A, vector<int>& L, vector<int>& R)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
unsigned int i=0;
unsigned int j=0;
unsigned int k=0;
while(i<L.size() && j<R.size())
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<L.size())
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<R.size())
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(vector<int>& A)
{
int n = A.size();
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
vector<int> left(mid);
vector<int> right(n-mid);
for(int i=0;i<mid;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left);
MergeSort(right);
Merge(A,left,right);
}
int main()
{ vector<int> A={2,4,7,1,5,3};
MergeSort(A);
for(unsigned int i=0;i<A.size();i++) cout<<A[i]<<" ";
return 0;
}
[Edit]
I noticed I accidentally used comma's instead of dots in vector.size() calls. Also, I noticed 2 arrays stopping one item too early in copying left and right vectors.
Your code did not work. Above code compiles fine, but produces 1 3 5 2 4 7 as output. Also, have you thought of a vector of uneven length, such as 5 4 3 2 1?
At this point, the code will not split properly

Quicksort Algorithm,Incorrect answer and segmentation fault with some specific input sequences

I am learning c++ and I am relatively new to programming. I wrote a C++ program that implements the quick sort algorithm using the last element as the pivot. Whenever I try to execute it, the answer is always wrong and for some specific input sequences I get a segmentation fault error.
I have tried playing around with the while loop and changing it to "if" statements to see if anything happens. The results change but they are incorrect.
// Example program
#include <iostream>
using namespace std;
int partition(int a[],int l,int r)
{
//int l=0,r=p-1;
int p=r+1;
while(r>l)
{
while (a[l]<a[p])
{
l=l+1;
}
while(a[r]>a[p])
{
r=r-1;
}
//if(a[l]>a[r]){
int f=a[r];
a[r]=a[l];
a[l]=f;
//}
}
int k=a[l];
a[l]=a[p];
a[p]=a[l];
p=l;
return p;
}
void quicksort(int a[],int l,int r)
{
int p;
if (l<r){
p=partition(a,l,r);
quicksort(a,0,p-2);
quicksort(a,p+1,r);
}
}
int main(){
int k;
cout<<"enter the number of elements in array";
cin>>k;
int a[k];
for (int i=0;i<k;i++)
{
cin>>a[i];
}
//int p=k-1;
int l=0;
int r=k-2;
quicksort(a,l,r);
for (int i=0;i<k;i++)
{
cout<<a[i];
}
return 0;
}
actual results:
enter the number of elements in array
4
3
0
1
2
sorted result
1322
expected results:
0123
If the posted code is compiled with warnings enabled, the following diagnostic is produced:
prog.cc:25:9: warning: unused variable 'k' [-Wunused-variable]
int k=a[l];
^
prog.cc:47:10: warning: variable length arrays are a C99 feature [-Wvla-extension]
int a[k];
^
The first one is generated by what seems to be a typo in function partition:
int k=a[l];
a[l]=a[p];
a[p]=a[l]; // <-- That should be 'a[p] = k;' to swap the values
Of course, the proper way of swapping those two values should be
std::swap(a[l], a[p]);
The second warning is easily fixed by using the proper data structure, which in C++ is a std::vector and passing a reference to it to the other functions, instead of a int *.
Those aren't the only issues in OP's code, which seems to implement a variant of the Quicksort algorithm using the Lomuto partition scheme.
In OP's code the first call is something like
quicksort(a, 0, k - 2); // k beeing the size of the VLA, it skips the last element
While, using a vector and following the convention of denoting a range by its first element and the one past the end, we could write the entry point as
// Note that std::vector::size() returns an unsigned type
quicksort(a, 0, a.size());
So that the quicksort function could be implemented as
void quicksort(std::vector<int> &a, size_t low, size_t high)
{
if ( low < high) {
size_t p = partition(a, low, high);
quicksort(a, low, p); // <- Note that OP's code uses '0' instead of 'low'
quicksort(a, p + 1, high);
}
}
If I correctly guessed the variant which the OP is trying to implement, the partition function could be simplified (and fixed) to
size_t partition(std::vector<int> &a, size_t low, size_t high)
{
size_t p = high - 1; // <- Assumes high > 0
size_t i = low;
for( size_t j = low; j < p; ++j )
{
if(a[j] < a[p]) {
std::swap(a[i], a[j]);
++i;
}
}
std::swap(a[i], a[p]);
return i;
}

Finding Quartils with cpp

Problem:
Find the 3 quartils of a set;
The first line contains an integer, n , denoting the number of elements in the array.
The second line contains n space-separated integers describing the array's elements.
So what are quartils? There are 3 quartiles, the 2nd one is the median, the middle element of your set, if n%2==0 is the sum of the middle 2 devided by 2, the 1st and the 3rd one, we get the first and the second half of our set and we find the medians of these sets, that basicly all, here is full info( https://en.wikipedia.org/wiki/Quartile ).
So I want to submit my code in hackerrank and I can't seem to find my mistake, the test case passes, I made my test and everything is working find but I can't seem to find my mistake, can you help me find it but generally.. what is the way to debug this type of problem where everything is working but the output is not fine for some output ? Can unit testing help me out here? Here is my code:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
// A utility function to swap two elements
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int partition (int arr[], int low, int high)
{
int pivot = arr[high]; // pivot
int i = (low - 1); // Index of smaller element
for (int j = low; j <= high- 1; j++)
{
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot)
{
i++; // increment index of smaller element
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
/* 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);
}
}
int getQuartil(int arr[],int len){
int q=0;
if(len%2){
q=arr[len/2];
}else{
q=(arr[len/2]+arr[len/2-1])/2;
}
return q;
}
int main() {
int n;
std::cin >> n;
int arr[n];
for(int i =0; i < n; i++){
std::cin >> arr[i];
}
quickSort(arr,0,n);
int q1=getQuartil(arr,n/2);
int q2=getQuartil(arr, n);
int q3=getQuartil(arr, (n+n/2+1));
std::cout << q1 << std::endl;
std::cout << q2 << std::endl;
std::cout << q3 << std::endl;
return 0;
}

merge sort incorrect output

I'm trying to use the following merge sort function to sort an array. However it is not giving me the expected output.
It will not print out correct/expected output i.e
Input: 5,4,3,2,1
Output: 1,2,3,4,5
Instead it gives: 2,3,4,5,1,9,8,7,8,4,1,8,8,2.
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>
using namespace std;
void mergeSort(int a[], int low , int high,int res[]);
void merge(int a[], int low , int mid , int high,int res[]);
void mergeSort(int numbers[], int temp[], int array_size);
const int SIZE=5;
int main () {
int sorted[SIZE];
for (int i=0; i<SIZE; i++) {
cout << "input numbers" <<endl;
cin >>sorted[i];
}
int merge[SIZE];
mergeSort(sorted,merge,SIZE);
for (int i=0; i<SIZE; i++) {
cout << merge[i];
}
return 0;
}
void mergeSort(int numbers[], int temp[], int array_size)
{
mergeSort(numbers, 0, array_size-1, temp);
}
void mergeSort(int a[], int low , int high,int res[])
{
int mid = (low + high) /2;
if (low + 1 < high)
{
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid,high,res);
// Merge back to "res"
merge(a,low,mid,high,res);
}else{
res[low] = a[low];
}
}
void merge(int a[], int low , int mid , int high,int res[])
{
int i = low;
int j = mid;
int k = low; // Use "low" instead of 0.
while (i < mid && j < high)
if(a[i] < a[j])
res[k++] = a[i++];
else
res[k++] = a[j++];
while (i < mid)
res[k++] = a[i++];
while (j < high)
res[k++] =a[j++];
// Copy back to "a"
for (int c = low; c < high; c++){
a[c] = res[c];
}
}
I think this is causing the problem --
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid,high,res);
It should be
// Sort sub-parts
mergeSort(a,low,mid,res);
mergeSort(a,mid+1,high,res);
Also if (low + 1 < high) should be changed to if (low < high)
Furthermore while (i < mid && j < high) should be while (i <= mid && j <= high) and single while loops below it too need to be updated with <=
There is a bit of confusion in your handling of indexing limits.
Two very common ways to represent ranges are:
range limits are pointing between elements
range limits are pointing to elements
In the picture the numbering above is using the "pointing between elements" approach and the grayed out range is (2, 5).
The numbering below is instead using the "pointing to elements" approach and the same range is (2, 4).
As a personal preference I like the "between elements" approach much more: for example the size of a range is high-low and you can represent easily empty ranges or even inverted ranges. The important thing is however that you keep always clear in your mind if you're using the first or the second approach when writing code that is managing ranges.
In your code there's that kind of confusion; for example in mergesort you are checking if
low + 1 < high
and this means that you're using the "between elements" approach because when high - low = 1 means there is only one element and no sorting is needed. Also you recurse passing (low, mid) and (mid, high): another clear sign that the "between elements" approach is used because you surely don't want to move around array[mid] twice.
In the same code however you're passing the function 0 and array_size-1 in the main program, a clear sign that in this case you're using the "pointing to elements" approach instead.
Just double-check that all your index and range usage is coherent and the code will be fine.
According to your sample code, only 5 numbers should be printed as result (because of const int SIZE=5).
That aside, note that you provide the position of the last element of your list as "high" parameter.
However, in your merge function, your while(j < high) conditions make sure that this last element in the list will not be sorted, because sorting stops just before reaching it.
Update: The for loop at the end of the merge function needs to be adapted to also copy the last ("high") element back into the array a.