How do I properly implement merge sort - c++

I have the merge sort code below which is not giving proper output.
Input : 1 7 3 9 4 5 2 6 8
Output : 1 5 2 6 7 3 8 1 9.
#include<iostream>
#include<vector>
using namespace std;
void merge(vector<int>& array,vector<int>& helper,int low,int mid,int high)
{
int size = array.size();
for(int i =0;i<size;i++)
helper.push_back(array[i]);
//helper = array; // copy vector elements i .. copying references doesnt work hence
int current = low;
int helperLeft = low;
int helperRight = mid+1;
while(helperLeft<=mid && helperRight <=high)
{
if(helper[helperLeft]<helper[helperRight])
{ array[current] = helper[helperLeft];
helperLeft++;
}
else
{
array[current] = helper[helperRight];
helperRight++;
}
current++;
}
int remaining = mid - helperLeft;
for (int i = 0; i <= remaining; i++)
array[current + i] = helper[helperLeft + i];
// copy the remaining elements from the left only and not right because right elememts are already there in dest (array) sorted.
}
void mergeSort(vector<int>&array,vector<int>& helper,int low,int high)
{
if(low < high)
{
int mid = (low+high)/2;
mergeSort(array,helper,low,mid);// sort left half
mergeSort(array,helper,mid+1,high);// sort right half
merge(array,helper,low,mid,high);
}
}
void mergeSort(vector<int>& array)
{
vector<int> helper;
mergeSort(array,helper,0,array.size());
}
int main()
{
vector<int> v;
int i =1;
v.push_back(i);
v.push_back(i+6);
v.push_back(i+2);
v.push_back(i+8);
v.push_back(i+3);
v.push_back(i+4);
v.push_back(i+1);
v.push_back(i+5);
v.push_back(i+7);
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<" "<<*it;
it++;
}
cout<<endl;
mergeSort(v);
it = v.begin();
while(it!=v.end())
{
cout<<" "<<*it;
it++;
}
cout<<endl;
}
I am using C++ vectors here instead of arrays as passing size will be a problem?
Can somebody please hep me correct the mistake here?

I got the answer.The correct solution is posted below.
#include<iostream>
#include<vector>
using namespace std;
void merge(vector<int> &array,int low,int mid,int high)
{
vector<int> helper(array);
//helper = array; // copy vector elements i .. copying references doesnt work hence
int current = low;
int helperLeft = low;
int helperRight = mid+1;
while(helperLeft<=mid && helperRight <=high)
{
if(helper[helperLeft]<helper[helperRight])
{
array[current] = helper[helperLeft];
helperLeft++;
}
else
{
array[current] = helper[helperRight];
helperRight++;
}
current++;
}
while(helperLeft<=mid)
array[current++] = helper[helperLeft++];
// copy the remaining elements from the left only and not right because right elememts are already there in dest (array) sorted.
}
void mergeSort(vector<int>&array,int low,int high)
{
if(low < high)
{
int mid = (low+high)/2;
mergeSort(array,low,mid);// sort left half
mergeSort(array,mid+1,high);// sort right half
merge(array,low,mid,high);
}
}
void mergeSort(vector<int>& array)
{
mergeSort(array,0,array.size()-1);
}
int main()
{
vector<int> v;
int i =1;
v.push_back(i);
v.push_back(i+6);
v.push_back(i+2);
v.push_back(i+8);
v.push_back(i+3);
v.push_back(i+4);
v.push_back(i+1);
v.push_back(i+5);
v.push_back(i+7);
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<" "<<*it;
it++;
}
cout<<endl;
mergeSort(v);
it = v.begin();
while(it!=v.end())
{
cout<<" "<<*it;
it++;
}
cout<<endl;
}

Related

I am using quick sort to sort an array. But am getting the array unsorted. I have tried to find the error but have failed

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int partition(int input[], int start, int end)
{
int x = input[start],count=0;
for (int i=start+1;i<=end;i++)
{
if (input[i] <= x)
count++;
}
int temp = input[start+count];
input[start+count] = x;
input[start] = temp;
int i=start, j=end;
while (input[i] != x && input[j] != x)
{
if (input[i] > x && input[j] < x)
{
int temp1 = input[j];
input[j] = input[i];
input[i] = temp1;
i++;
j--;
}
else if (input[i] <= x)
{
i++;
}
else
{
j--;
}
}
return count+1;
}
void helpSort(int input[], int start, int end)
{
if (start >= end)
return;
int c = partition(input, start, end);
helpSort(input, start, start+c-1);
helpSort(input, start+c+1, end);
return;
}
void quickSort(int input[], int size)
{
int start=0,end=size-1;
helpSort(input, start, end);
}
int main()
{
int arr[] = {1,3,7,2,6,4,8,9,0,5};
quickSort(arr, 10);
for (int i=0;i<10;i++)
{
cout<<arr[i]<<" ";
}
return 0;
}
My approach was to find numbers smaller than the first element of the array. Partition it and then call qs on the partitioned array. For eg:- 1 5 7 8 9 3 partitions it wrt to 1. then qs it with two arrays before 1 and after 1. This continues recursively till start is either equal to or greater than end which is the first and last index of my array. End denotes the last element of my array.
This is my code. Thanks in advance.
The issue was in the while loop condition. When it encountered the same element as the one which was the partitioning element the loop closed. (duplicate numbers)
Also the if conditions did not consider duplicate elements i.e if (i>x or j<x).
It should have been i>x or j<=x.
The count return should have been returning count and not count+1. This solved the problem I had.

vector mergesort() nothing happens

I am not too sure what I did wrong in this Mergesort algorithm I made.
my output I am receiving is
4 3 5 5 4 3 8 8 8
I am speculating my int mid value could be causing this but then again I don't think it really matters as I am being consistent in merger func.
#include <iostream>
#include <vector>
using namespace std;
void merger(vector<int> &arr, int beg, int end) {
vector<int> temp;
int mid = (beg + end-1) / 2;
int right=mid+1;
int left = beg;
while (left <= mid && right <= end) {
if (arr[left] <= arr[right]) {
temp.push_back(arr[left++]);
}
else temp.push_back(arr[right++]);
}
if(left<mid){
while (left <= mid) {
temp.push_back(arr[left++]);
}
}
else{
while (right <= end) {
temp.push_back(arr[right++]);
}
}
int j = 0;
for (auto x : temp) {
arr[j++] = x;
}
// temp.clear();
}
void mergesort(vector<int> &arr, int beg, int end) {
//base case
if (beg >= end)return;
//make mid
int mid = (beg+end-1) / 2;
mergesort(arr, beg, mid);
mergesort(arr, mid+1, end);
merger(arr, beg, end);
}
int main() {
vector<int> arr1 = { 7,5,2,4,10,5,4,3,8 };
mergesort(arr1, 0, arr1.size()-1);
for (auto x : arr1) {
cout << x << " ";
}
cout << endl;
return 0;
}
```````````````````````````````````````
In merger, the index variable j needs to start at beg because the elements you copy into temp start with arr[beg]. Change the declaration to
int j = beg;
right before you loop to copy the sorted temp array back into arr.

Sorting vectors in a descending order using the quicksort algorithm

I am new to quick sorting algorithms. Following the principle descried here Pivoting To Understand Quicksort. I try to write quicksort codes for sorting vector in a descending order. Here below is my codes with a simple example:
#include <iostream>
#include <vector>
using namespace std;
void quick_sort(vector<int> vec, int begin, int end)
{
int i; //for left element index
int j; //for right element index
int pivot_idx = (begin+end)/2;
int pivot = vec[pivot_idx]; //pivot element
//cout<<"Pivot = "<<pivot<<endl;
i = begin;
j = end;
//partition data into smaller and larger parts relative to the pivot
while(1)
{
while(vec[i]>pivot)
{
++i;
}
while(vec[j]<pivot)
{
++j;
}
//Once the left index pass right index, partitioning is done
if(i>=j)
{
break;
}
//otherwise do swapping
int temp;
temp = vec[i];
vec[i] = vec[j];
vec[j] = temp;
//keep moving indices
i++;
j--;
}
//recurse into two smaller parts
if(begin<i-1)
{
quick_sort(vec, begin, i-1);
}
if(j+1<end)
{
quick_sort(vec, j+1, end);
}
}
int main()
{
vector<int> v;
v.push_back(9);
v.push_back(5);
v.push_back(2);
v.push_back(6);
v.push_back(1);
v.push_back(11);
v.push_back(3);
cout<<"Before sorting:"<<endl;
for(int i=0;i<v.size();i++)
{
cout<<v[i]<<endl;
}
quick_sort(v,0,v.size()-1);
cout<<"After sorting:"<<endl;
for(int i=0;i<v.size();i++)
{
cout<<v[i]<<endl;
}
return 0;
}
The codes above do not work as expected. No sorting is performed. I need some help to debug my codes to found out why. Thanks!
You are passing the vector by value, and so you sort a copy of the original vector. Pass it by reference instead, that is change the signature to
void quick_sort(vector<int>& vec, int begin, int end)
^^^
There is a mistake in updating j index:
while(vec[j]<pivot){++j;}
should be
while(vec[j]<pivot){--j;}
There were a few other bugs than just passing by reference that I fixed mainly by making this implementation more simple. Your function was trying to do everything and it wasn't giving correct results. I split the partition and the swap into their own functions and used a very standard quicksort function. This seems to work find now:
#include <iostream>
#include <vector>
using namespace std;
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition (vector<int> &vec, int l, int h) {
int x = vec[h];
int i = (l - 1);
for (int j = l; j <= h- 1; j++) {
if (vec[j] <= x) {
i++;
swap (&vec[i], &vec[j]);
}
}
swap (&vec[i + 1], &vec[h]);
return (i + 1);
}
void quick_sort(vector<int> &vec, int begin, int end) {
if (begin < end) {
int pivot_idx = partition(vec, begin, end);
quick_sort(vec, begin, pivot_idx-1);
quick_sort(vec, pivot_idx+1, end);
}
}
int main() {
vector<int> v;
v.push_back(9);
v.push_back(5);
v.push_back(2);
v.push_back(6);
v.push_back(1);
v.push_back(11);
v.push_back(3);
cout<<"Before sorting:"<<endl;
for(int i=0;i<v.size();i++) {
cout<<v[i]<<endl;
}
quick_sort(v,0,v.size()-1);
cout<<"After sorting:"<<endl;
for(int i=0;i<v.size();i++) {
cout<<v[i]<<endl;
}
return 0;
}
I hope this helps

Quicksort algorithm with duplicate keys

I am trying to implement Quick Sort algorithm. Following code works for unique elements but it doesn't working for arrays having duplicate elements. Please tell me where I am doing wrong. Also when I change value of pivot to some other number other than 0 , program crashes. Here is the code:
#include <iostream>
#include <cstdlib>
using namespace std;
void swapme(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void quicksort(int *arr, int size)
{
// these two variables will take care of position of comparison
int lower = 0, upper = size - 1;
int pivot = 0; // assigns pivot
if (size <= 1)
return;
while (lower < upper)
{
while (arr[lower] < arr[pivot])
{
++lower;
}
}
while (arr[upper] > arr[pivot])
{
--upper;
}
if (upper > lower)
{
swapme(arr[upper], arr[lower]);
// upper--;
// lower++;
}
quicksort(arr, lower);
quicksort(&arr[lower + 1], size - 1 - lower);
}
int main()
{
int arr[30];
for(int j = 0; j < 30; j++)
{
arr[j] = 1 + rand() % 5000;
}
for(int j = 0; j < 30; j++)
{
cout << arr[j] << "\t";
}
cout << endl;
quicksort(arr, 30);
for(int j = 0; j < 30; j++)
{
cout << arr[j] << "\t";
}
cout << endl;
cin.get();
cin.get();
}
Update: I have finally managed to make it work. Here is the fixed version:
void swapme(int &a, int &b )
{
int temp = a;
a = b;
b = temp;
}
void quicksort(int *arr, int size)
{
if (size <= 1)
return;
// These two variables will take care of position of comparison.
int lower = 0;
int upper = size-1;
int pivot = arr[upper/2]; // assigns pivot
while (lower <= upper)
{
while (arr[lower] < pivot)
++lower;
while (arr[upper] > pivot)
--upper;
if (upper >= lower)
{
swapme(arr[upper],arr[lower]);
if(arr[upper] == arr[lower])
{
// Can either increment or decrement in case of duplicate entry
upper--; // lower++;
}
}
}
quicksort(arr, lower);
quicksort( &arr[lower+1], size-1-lower);
}
You are storing the index of your pivot element in the pivot variable, so swapping the elements can potentially change the choice of pivot element during the loop. Not a very good idea. I would suggest storing the actual value of the pivot element inside pivot instead.
Also, if this really isn't homework, why don't you simply use the standard library facilities?
#include <algorithm>
// ...
std::sort(arr + 0, arr + 30);
You will get heavily optimized and tested code that will outperform your handwritten Quicksort anytime.
Quick Sort that can implement any number of i/p integers. it also deal with duplicate keys
#include <conio.h>
#include <string>
using namespace std;
void InputArray(int*,int);
void QuickSort(int *,int,int);
int partition(int *,int,int);
void swap(int *,int,int);
void printArr(int *,int Siz=11);
void main(){
int siz;
cout<<"Enter Array length : "; cin>>siz;
int *a=new int[siz];
InputArray(a,siz);
QuickSort(a,0,siz-1);
int i=0,j=11;
printArr(a,siz);
system("pause");
}
void InputArray(int*a,int s){
for(int i=0; i<s; i++){
cout<<"ELement ["<<i<<"] = "; cin>>a[i];
}
}
void QuickSort(int *a,int start,int end){
if(start<end){
int pivot=partition(a,start,end);
QuickSort(a,start,pivot);
QuickSort(a,pivot+1,end);
}
}
int partition(int *a,int start,int end){
int currentPivotValue=a[start];
int i=start-1, j=end+1;
while(true){
i++;
while(i<j && a[i]<currentPivotValue){ i++; }
j--;
while(j>start && a[j]>currentPivotValue) {j--;}
if(i<j) swap(a,i,j);
else return j;
}
}
void swap(int *b,int i,int j){
int t=b[i];
b[i]=b[j];
b[j]=t;
}
void printArr(int *a,int Siz){
for(int i=0; i<Siz; i++) cout<<a[i]<<" ";
}

Heap Sort in C++

Okay, so after struggling with trying to debug this, I have finally given up. I'm a beginner in C++ & Data Structures and I'm trying to implement Heap Sort in C++. The code that follows gives correct output on positive integers, but seems to fail when I try to enter a few negative integers.
Please point out ANY errors/discrepancies in the following code. Also, any other suggestions/criticism pertaining to the subject will be gladly appreciated.
//Heap Sort
#include <iostream.h>
#include <conio.h>
int a[50],n,hs;
void swap(int &x,int &y)
{
int temp=x;
x=y;
y=temp;
}
void heapify(int x)
{
int left=(2*x);
int right=(2*x)+1;
int large;
if((left<=hs)&&(a[left]>a[x]))
{
large=left;
}
else
{
large=x;
}
if((right<=hs)&&(a[right]>a[large]))
{
large=right;
}
if(x!=large)
{
swap(a[x],a[large]);
heapify(large);
}
}
void BuildMaxHeap()
{
for(int i=n/2;i>0;i--)
{
heapify(i);
}
}
void HeapSort()
{
BuildMaxHeap();
hs=n;
for(int i=hs;i>1;i--)
{
swap(a[1],a[i]);
hs--;
heapify(1);
}
}
void main()
{
int i;
clrscr();
cout<<"Enter length:\t";
cin>>n;
cout<<endl<<"Enter elements:\n";
for(i=1;i<=n;i++) //Read Array
{
cin>>a[i];
}
HeapSort();
cout<<endl<<"Sorted elements:\n";
for(i=1;i<=n;i++) //Print Sorted Array
{
cout<<a[i];
if(i!=n)
{
cout<<"\t";
}
}
getch();
}
I've been reading up on Heap Sort but I'm not able to grasp most of the concept, and without that I'm not quite able to fix the logical error(s) above.
You set hs after calling BuildMaxHeap. Switch those two lines.
hs=n;
BuildMaxHeap();
When I implemented my own heapsort, I had to be extra careful about the indices; if you index from 0, children are 2x+1 and 2x+2, when you index from 1, children are 2x and 2x+1. There were a lot of silent problems because of that. Also, every operation needs a single well-written siftDown function, that is vital.
Open up Wikipedia at the Heapsort and Binary heap articles and try to rewrite it more cleanly, following terminology and notation where possible. Here is my implementation as well, perhaps it can help.
Hmmm now that I checked your code better, are you sure your siftDown/heapify function restricts sifting to the current size of the heap?
Edit: Found the problem! You do not initialize hs to n before calling BuildMaxHeap().
I suspect it's because you're 1-basing the array. There's probably a case where you're accidentally 0-basing it but I can't spot it in the code offhand.
Here's an example if it helps.
#include <iostream>
#include <vector>
using namespace std;
void max_heapify(std::vector<int>& arr, int index, int N) {
// get the left and right index
int left_index = 2*index + 1;
int right_index = 2*index + 2;
int largest = 0;
if (left_index < N && arr[left_index] > arr[index]) {
// the value at the left_index is larger than the
// value at the index of the array
largest = left_index;
} else {
largest = index;
}
if (right_index < N && arr[right_index] > arr[largest]) {
// the value at the right_index is larger than the
// value at the index of the array
largest = right_index;
}
// check if largest is still the index, if not swap
if (index != largest) {
// swap the value at index with value at largest
int temp = arr[largest];
arr[largest] = arr[index];
arr[index] = temp;
// once swap is done, do max_heapify on the index
max_heapify(arr, largest, N);
}
}
void build_max_heap(std::vector<int>& arr, int N) {
// select all the non-leaf except the root and max_heapify them
for (int i = N/2 - 1; i >= 0; --i) {
max_heapify(arr, i, N);
}
}
void heap_sort(std::vector<int>& arr) {
int N = arr.size();
int heap_size = N;
// build the max heap
build_max_heap(arr, N);
// once max heap is built,
// to sort swap the value at root and last index
for (int i = N - 1; i > 0; --i) {
// swap the elements
int root = arr[0];
arr[0] = arr[i];
arr[i] = root;
// remove the last node
--heap_size;
// perform max_heapify on updated heap with the index of the root
max_heapify(arr, 0, heap_size);
}
}
int main() {
std::vector<int> data = {5,1,8,3,4,9,10};
// create max heap from the array
heap_sort(data);
for (int i : data) {
cout << i << " ";
}
return 0;
}
# include <iostream> //Desouky//
using namespace std;
void reheapify(int *arr, int n, int i)
{
int parent = i; // initilaize largest as parent/root
int child1 = 2 * i + 1; // to get first chid
int child2 = 2 * i + 2; // to get second child
if (child1 < n && arr[child1] > arr[parent]) // if child2 > parent
{
parent = child1;
}
//if child > the parent
if (child2 < n && arr[child2] > arr[parent])
{
parent = child2;
}
// if the largest not the parent
if (parent != i)
{
swap(arr[i], arr[parent]);
// Recursively heapify the affected sub-tree
reheapify(arr, n, parent);
}
}
void heapsort(int *arr, int n)
{
// build a heap
for (int i = n - 1; i >= 0; i--)
{
reheapify(arr, n, i);
}
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--)
{
// Move current root to end
swap(arr[0], arr[i]);
// call max heapify on the reduced heap
reheapify(arr, i, 0);
}
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
int* arr = new int[n];
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
heapsort(arr, n);
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
}