Merge sort not working completely - c++

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

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

unable to pass original array in function from main

I am passing array containing four elements in quicksort function, But
only one element is getting passed 3 ,I assured this by printing sizeof(a)
when execution enters for first time in quicksort(a,start,end) the sizeof
was printing only 4 and I always pass array like this it works every time
But I don't know where I am doing wrong here PLease help.
#include<iostream>
#include<algorithm>
using namespace std;
int partition_qs(int a[], int start, int end1) {
int pivot = end1 - 1;
int pindex = start;
for (int i = start; i < end1; i++) {
if (a[i] < a[pivot]) {
swap(a[i], a[pindex]);
pindex++;
}
}
swap(a[pindex], a[pivot]);
return pindex;
}
void quicksort(int a[], int start, int end1) {
cout << sizeof(a);
if (start < end1) {
int pind = partition_qs(a, start, end1);
quicksort(a, start, pind);
quicksort(a, pind, end1);
}
}
int main() {
int a[] = { 3,-1,2,0 };
quicksort(a, 0, 4);
// for(int i=0;i<4;i++)
// cout<<a[i]<<" ";
}

Quicksort gives segmentation fault

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
}

heap sort,I can't figure out what's wrong with my code,which doesn't output right order

#include<iostream>
using namespace std;
int heapSize;
void maxHeapify(int a[],int n,int i)
{
int l=2*i+1;
int r=2*i+2;
int largest=i;
if(l<heapSize&&a[l]>a[i]) largest=l;
if(r<heapSize&&a[r]>a[i]) largest=r;
if(largest!=i)
{
swap(a[i],a[largest]);
maxHeapify(a,n,largest);
}
}
void heapSort(int a[],int n)
{
heapSize=n;
for(int i=n/2;i>=0;i--)maxHeapify(a,n,i);
for(int i=n-1;i>=1;i--)
{
swap(a[0],a[i]);
heapSize--;
maxHeapify(a,n,0);
}
}
int main()
{
int a[]={1,2,3,7,9,15,13,11};
heapSort(a,8);
for(int i=0;i<8;i++)cout<<a[i]<<" ";
return 0;
}
output:1 2 7 11 15 3 9 13
I want to achieve a heap sort,but something went wrong,i have tried to debug it for hours,i can't find any more bugs,maybe something wrong with the logic as well as can't figure out what's wrong with my code, which doesn't output right order.
In your maxHeapify fucntion you missed to compare your heap's right child with current largest. Your function will be
void maxHeapify(int a[], int n, int i) {
int l = 2 * i + 1;
int r = 2 * i + 2;
int largest = i;
if(l < heapSize && a[l] > a[i]) largest = l;
if(r < heapSize && a[r] > a[largest]) largest = r;
if(largest! = i)
{
swap(a[i], a[largest]);
maxHeapify(a, n, largest);
}
}

median 3 quick sort implementation

my median 3 implementation is not working fine here. i have to choose 3 numbers randomly for medium here is my code please help me.
#include"stdafx.h"
#include <iostream>
#include<algorithm>
using namespace std;
#define size 10
int i;
void show(int* array, int n);
int partition(int* array, int pValue, int left, int right);
void QuickSort(int* array, int left, int right);
int main(void)
{
int array[size];
int i;
for( i = 0; i < size; i++)
{
array[i]=rand()%100;
}
cout<<endl<<"The random generated numbers are: "<<endl;
show(array, size);
QuickSort(array,0,size - 1);
cout<<endl<<"The sorted numbers are : "<<endl;
show(array, size);
system("pause");
return 0;
}
void show(int* array, int n)
{
int i;
for( i = 0; i < n; i++) cout<<array[i]<<'\t';
}
void QuickSort(int* array, int left, int right)
{
for(i=0;i<3;i++)
{
array[i]=array[rand()%100];
}
stable_sort(array,array+3);
int p=array[(i+1)/2];
//int p = array[left];
int split;
if(right > left)
{
split = partition(array, p, left, right);
array[split] = p;
QuickSort(array, left, split-1);
QuickSort(array, split+1, right);
}
}
int partition(int* array, int p, int left, int right)
{
int lb = left;
int rb = right;
while(lb < rb)
{
while( p < array[rb]&& rb > lb)
{
rb--;
}
swap(array[lb], array[rb]);
while( p >= array[lb]&& lb < rb)
{
lb++;
}
swap(array[rb], array[lb]);
}
return lb;
}
Your code was way too complex for this simple algorithm, check code below:
void QuickSortMedian(int a[],int start,int end) {
int q;
count++;
if (end-start<2) return;
q=MedianOfThreePartition(a,start,end);
QuickSortMedian(a,start,q);
QuickSortMedian(a,q,end);
}
int MedianOfThreePartition(int a[],int p, int r) {
int x=a[p],y=a[(r-p)/2+p],z=a[r-1],i=p-1,j=r;
if (y>x && y<z || y>z && y<x ) x=y;
else if (z>x && z<y || z>y && z<x ) x=z;
while (1) {
do {j--;count++;} while (a[j] > x);
do {i++;count++;} while (a[i] < x);
if (i < j) swap(&a[i],&a[j]);
else return j+1;
}
}
void QuickSortRandomAndMedian(int a[],int start,int end) {
int q;
count++;
if (end-start<2) return;
q=RandomAndMedianPartition(a,start,end);
QuickSortRandomAndMedian(a,start,q);
QuickSortRandomAndMedian(a,q,end);
}
int RandomAndMedianPartition(int a[],int p, int r) {
int t,x=a[t=((rand()%(r-p))/2)+p+(r-p)/4],y=a[t+1],z=a[t-1],i=p-1,j=r;
if (y>x && y<z || y>z && y<x ) x=y;
else if (z>x && z<y || z>y && z<x ) x=z;
while (1) {
do {j--;count++;} while (a[j] > x);
do {i++;count++;} while (a[i] < x);
if (i < j) swap(&a[i],&a[j]);
else return j+1;
}
}
The second algorithm is just a boost that I wrote for the optimization of quick sort, for example on a 40000 elements array regular quick sorts did about 800k actions, the median one did 650k and the random median one did about 620k. That's the best I got so far. :)
Maybe the problem is here:
array[i]=array[rand()%100];
First, you're changing some elements of the array, when you should be swapping them with others. If you don't you are destroying data.
Second, your array has size 10, but you're asking for an index at a random position between 0 and 99. Obviously, you can't do that, and that's why you're getting garbage.