merge sort incorrect output - c++

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.

Related

Stack Smashing detected while implementing mergeSort in C++14

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.

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.

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

Programming Quicksort Algorithm Q

I'm trying to write quicksort and understand the algorithm. I understand the 3 basic principles of quick sort
The element a[i] is in its final place in the array for some i.
None of the elements in a[l], a[i1] is greater than a[i].
None of the elemtns in a[i+1],..., a[r] is less than a[i].
I think I'm missing something about this algorithm. Any guidance much appreciated.
My first question is l and r, those are the min and max of the array? or is it any place within the left and right side of the array.
#include <iostream>
using namespace std;
void quicksort(int a[], int l , int r);
int partition(int a[], int l, int r);
void exchange(int a[], int i, int j);
int main()
{
const int MAX_ARRAY = 9;
// Quicksort
// Array of integers
int numArray[MAX_ARRAY] = {25,10,25,34,38,7,6,43,56};
for ( int i = 0 ; i < MAX_ARRAY ; i++)
{
cout << numArray[i] << endl;
}
quicksort(numArray, 4, 7);
// Call quicksort
for ( int i = 0 ; i < MAX_ARRAY ; i++)
{
cout << numArray[i]<< endl;
}
system("pause");
return 0;
}
void quicksort(int a[], int l , int r)
{
//
if (r <= l) {return;} // The max position and least position are now overlapping
int i = partition(a, l, r); // send the array and the two positions to partition
// i gives me the next position
quicksort(a,l,i-1); // sort left side
quicksort(a,i+1,r); // sort right side
}
int partition(int a[], int l, int r)
{
//Declarations
int i = l-1, j = r; int v = a[r];
for(;;) // Infinite ForLoop
{
// go through till you find a value in the array that is less than v = our pivot
while(a[++i] < v) ;
while (v < a[--j]) if (j == 1) break; // THis condition is to go thorugh and check for a number that is larger than v then if j is not at 1 then we break
if ( i >= j) break; // Overlap array
exchange(a, i , j); // swap the values
}
exchange(a,i,j); // swap the values
return i;
}
void exchange(int a[], int i, int j )
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
My first question is l and r, those are the min and max of the array? or is it any place within the left and right side of the array.
No, those are the left and right borders of the current sub-array being sorted. I have no idea why you invoke method with parameters 4 and 7: it means none of the elements before 4-th or after 7-th will be sorted.
first, quicksort(numArray, 4, 7); should be quicksort(numArray, 0, 8);
second, to make it a little bit faster, you can set a cutoff number like 10 on which you switch to insertion sort. Insertion sort is faster than quick sort for small input.