Merge_sort without sentinel - c++

Can someone please tell me why I am getting garbage value after sorting?
Initial call is (A,0,n) where n is the size of array? I want to sort the array using merge sort algorithm but without sentinel value.
void merge_sort(int A[], int l, int mid, int r)
{
int n1 = mid - l + 1;
int n2 = r - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
{
L[i] = A[i];
}
for (int i = 0; i <= n2; i++)
{
R[i] = A[i + mid + 1];
}
cout << endl;
int j = 0, k = 0;
for (int i = l; i < r; i++)
{
if (j == n1 || k == n2)
{
if (j == n1 + 1)
{
A[i] = R[k];
k++;
}
else
{
A[i] = L[j];
j++;
}
}
else if (L[j] >= R[k])
{
A[i] = L[j];
j++;
}
else
{
A[i] = R[k];
k++;
}
}
}
void merge_divide(int A[], int l, int r)
{
if (l < r)
{
int mid = (l + r) / 2;
merge_divide(A, l, mid);
merge_divide(A, mid + 1, r);
merge_sort(A, l, mid, r);
}
}

There are a lot of moves in your logic that is hard to read. It is hard to distinguish where is an error or there is some intention here. But here it is how I see it with fixes. See inline comments.
void merge_sort(int A[], int l, int mid, int r) {
int n1 = mid - l;
int n2 = r - mid;
// this is C, but not C++, consider using vector instead
int L[n1], R[n2];
for (int i = 0; i < n1; i++) {
// need `l` here
L[i] = A[l + i];
}
for (int i = 0; i < n2; i++) {
// need to include `mid`
R[i] = A[i + mid];
}
int j = 0, k = 0;
for (int i = l; i < r; i++) {
if (j == n1) {
A[i] = R[k];
k++;
} else if (k == n2) {
A[i] = L[j];
j++;
} else if (L[j] >= R[k]) {
A[i] = L[j];
j++;
} else {
A[i] = R[k];
k++;
}
}
}
void merge_divide(int A[], int l, int r) {
// need properly compute `mid` here
int mid = r - l;
if (mid > 1) {
mid = l + mid / 2;
merge_divide(A, l, mid);
merge_divide(A, mid, r);
merge_sort(A, l, mid, r);
}
}
int main() {
int A[] = {2, 4, 3, 382, 2342334, 3, 42, 234};
int n = sizeof(A) / sizeof(int);
merge_divide(A, 0, n);
for (int i = 0; i < n; ++i)
cerr << A[i] << " ";
cout << endl;
}

Related

Can not understand what's going wrong in my merge sort algo

Here is my code:
#include <iostream>
using namespace std;
int arr[] = { 6, 1, 9, 6, 4, 7, 3 };
int n = 7;
void merge(int l, int mid, int r) {
int n1 = mid - l + l;
int n2 = r - mid;
int arr1[n1], arr2[n2];
for (int i = 0; i < n1; i++) {
arr1[i] = arr[l + 1];
}
for (int i = 0; i < n1; i++) {
arr1[i] = arr[mid + 1 + i];
}
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (arr1[i] <= arr2[j]) {
arr[k] = arr1[i];
i++, k++;
} else {
arr[k] = arr2[j];
j++;
k++;
}
}
while (i < n1) {
arr[k] = arr1[i];
i++;
k++;
}
while (j < n2) {
arr[k] = arr2[j];
j++;
k++;
}
}
void mergeSort(int l, int r) {
while (l < r) {
int mid = (l + r - 1) / 2;
mergeSort(l, mid);
mergeSort(mid + 1, r);
merge(l, mid, r);
}
}
void printArray(int arr[], int length) {
for (int i = 0; i < length; i++)
cout << arr[i] << " ";
cout << endl;
}
int main() {
printArray(arr, n);
mergeSort(0, n - 1);
printArray(arr, n);
}
I am not getting what is wrong with the code, when tried to debug it, it was calling mergeSort function, again and again with the same value.
There are many bugs hiding in plain sight in your merge function:
int n1 = mid - l + l; has an l where there should be a 1. Naming a variable l is risky as depending on the font, l looks confusingly close to 1.
arr1[i] = arr[l + 1]; should be arr1[i] = arr[l + i];
for (int i = 0; i < n1; i++) should be for (int i = 0; i < n2; i++) for the second loop.
arr1[i] = arr[mid + i]; should be arr2[i] = arr[mid + i];
Also note that it would be more consistent with C++ idioms to use the index of the element past the end of the slice instead of the index to the last element of the slice as many algorithmic books advise. This also allows for unsigned index types, such as size_t and remove the need for tricky +1 / -1 adjustments.
Here is a modified version:
#include <iostream>
using namespace std;
void merge(size_t lo, size_t mid, size_t hi) {
size_t n1 = mid - lo;
size_t n2 = hi - mid;
int arr1[n1], arr2[n2];
for (size_t i = 0; i < n1; i++) {
arr1[i] = arr[lo + i];
}
for (size_t i = 0; i < n2; i++) {
arr2[i] = arr[mid + i];
}
int i = 0, j = 0, k = lo;
while (i < n1 && j < n2) {
if (arr1[i] <= arr2[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while (i < n1) {
arr[k++] = arr1[i++];
}
while (j < n2) {
arr[k++] = arr2[j++];
}
}
void mergeSort(size_t lo, size_t hi) {
while (hi - lo > 1) {
size_t mid = lo + (hi - lo) / 2;
mergeSort(lo, mid);
mergeSort(mid, hi);
merge(lo, mid, hi);
}
}
void printArray(const int arr[], size_t length) {
for (size_t i = 0; i < length; i++)
cout << arr[i] << " ";
cout << endl;
}
int main() {
int arr[] = { 6, 1, 9, 6, 4, 7, 3 };
size_t n = sizeof(arr) / sizeof(*arr);
printArray(arr, n);
mergeSort(0, n);
printArray(arr, n);
return 0;
}
merge does not actually need to save the elements of the right half as they are never overwritten before they are read. Here is a simplified version:
void merge(size_t lo, size_t mid, size_t hi) {
size_t n1 = mid - lo;
size_t n2 = hi - mid;
int arr1[n1];
for (size_t i = 0; i < n1; i++) {
arr1[i] = arr[lo + i];
}
int i = 0, j = mid, k = lo;
while (i < n1) {
if (j >= hi || arr1[i] <= arr[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr[j++];
}
}
}

Hybrid Mergesort and Insertion sort

I am trying to implement a hybrid of mergesort and insertion sort. When the subarray size reaches below a threshold, it should switch to insertion sort.
However I tried with a bunch of array of different length and different threshold amount, and most of the time there isn't any noticeable difference, other than just a 2-3 lesser comparisons. I was told that switching to insertion sort for smaller sized array would help greatly.
Am I doing it wrong?
#include <iostream>
int comparisons = 0;
int swaps = 0;
void mergesort(int x[], int l, int r);
void insertionSort(int x[],int start, int end);
int main() {
int x[] = {9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,};
// insertionSort(x,10);
int sizeX= sizeof(x)/sizeof(x[0]) ;
mergesort(x, 0, sizeX-1);
for(int i =0;i<sizeX;i++){
std::cout << x[i] << " ";
}
// std::cout << "\nSWAPS: " << swaps;
std::cout << "\nCOMPARISONS: " << comparisons;
}
void insertionSort(int arr[], int start,int end)
{
int i, key, j;
for (i = start +1 ; i < end; i++)
{
key = arr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key)
{
comparisons++;
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
void insertionSort2(int x[],int start, int end){
for(int i =start; i < end;i++){
for (int j= i; j!= 0;j--){
comparisons++;
if(x[j] < x[j-1]){
int temp = x[j-1];
x[j-1] = x[j];
x[j] = temp;
swaps++;
}
else{
break;
}
}
}
}
void mergesort(int x[], int l, int r) {
if (l >= r)
return;
int mid = (l + r) / 2;
if(r - l < 3){
insertionSort(x, l,r+1);
}else{
mergesort(x, l, mid);
mergesort(x, mid + 1, r);
int i = l;
int j = mid + 1;
int k = 0;
int tmp[r - l + 1];
while (i <= mid && j <= r) {
comparisons++;
if (x[i] >= x[j]) {
tmp[k] = x[j];
j++;
} else {
tmp[k] = x[i];
i++;
}
swaps++;
k++;
}
while (i <= mid) {
tmp[k] = x[i];
i++;
k++;
}
while (j <= r) {
tmp[k] = x[j];
j++;
k++;
}
for (i = 0; i < k; i++) x[l + i] = tmp[i];
}
}

C++ Merge Sort returning original vector

I have been attempting to make a merge sort using vectors in C++ and am running into an issue where any vector input is sorted into its original order. I have based the algorithm off the geeks4geeks site here: https://www.geeksforgeeks.org/merge-sort/
So far I have spent about five hours attempting to find the source of the error and it seems that upon ending the merge function the vector somehow goes back to its original format, but I am unsure why. Any suggestions would be much appreciated.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int> vect, int p, int q, int r) {
int i, j, k, n1, n2;
n1 = q - p + 1;
n2 = r - q;
vector<int> L, R;
L.resize(n1);
R.resize(n2);
for (i = 0; i < n1; i++) {
L[i] = vect[p + i];
}
for (j = 0; j < n2; j++) {
R[j] = vect[q + 1 + j];
}
i = 0;
j = 0;
k = p;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
vect[k] = L[i];
i++;
}
else {
vect[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
vect[k] = L[i];
i++;
k++;
}
while (j < n2) {
vect[k] = R[j];
j++;
k++;
}
}
void mergeSort(vector<int> vect, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
mergeSort(vect, p, q);
mergeSort(vect, q + 1, r);
merge(vect, p, q, r);
}
}
int main() {
vector<int> vect{4,3,5,6,7,8};
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
}
First of all you should know the difference between:
pass by value
pass by reference
Go and check it here.
Secondly, you should change your code as it is shown:
#include <iostream>
#include <vector>
//using namespace std; forget about it, start using std::whatever_it_is_in_here
void merge(std::vector<int> &vect, int p, int q, int r) // note the & near vect
{
int i, j, k, n1, n2;
n1 = q - p + 1;
n2 = r - q;
std::vector<int> L, R;
L.resize(n1);
R.resize(n2);
for (i = 0; i < n1; i++) {
L[i] = vect[p + i];
}
for (j = 0; j < n2; j++) {
R[j] = vect[q + 1 + j];
}
i = 0;
j = 0;
k = p;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
vect[k] = L[i];
i++;
}
else {
vect[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
vect[k] = L[i];
i++;
k++;
}
while (j < n2) {
vect[k] = R[j];
j++;
k++;
}
}
void mergeSort(std::vector<int> &vect, int p, int r) // note the & near vect
{
if (p < r) {
int q = (p + r) / 2;
mergeSort(vect, p, q);
mergeSort(vect, q + 1, r);
merge(vect, p, q, r);
}
}
int main()
{
std::vector<int> vect{4,3,5,6,7,8};
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++)
std::cout << vect[i] << "\n"; // note \n instead of std::endl
return 0; // you forgot the return statement
}
You forgot the return statement in the main function.
Stop using using namespace std. Check why here
Note the "\n" instead of std::endl. You can understand more of it here

Merge Sort Algorithm?

I can't figure out what is wrong with my MergeSort function. This is my code:
void Merge(int* A, int p, int q, int r)
{
int B[100], i = 0, j = 0, k = 0;
i = p;
k = p;
j = q + 1;
while (i <= q && j <= r)
{
if (A[i] <= A[j])
{
B[k] = A[i];
k++;
i++;
}
else
{
B[k] = A[j];
k++;
j++;
}
}
while (i <= q)
{
B[k] = A[i];
k++;
i++;
}
while (j <= r)
{
B[k] = A[j];
k++;
j++;
}
for (i = p; i < r; i++)
{
A[i] = B[i];
}
}
void MergeSort(int A[], int p, int r)
{
int q;
if (p < r)
{
q = (p + r) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
}
int main(void)
{
int N[10];
N[0] = 4;
N[1] = 5;
N[2] = 8;
N[3] = 12;
N[4] = 7;
N[5] = 3;
N[6] = 23;
N[7] = 1;
N[8] = 90;
N[9] = 26;
MergeSort(N, 0, 9);
for (int i = 0; i < 10; i++)
{
cout << N[i] << endl;
}
}
The output of program is: 1, 3, 1, 4, 5, 7, 7, 7, 26, 26, which is obviously wrong. However I just don't see what is wrong in code, to me everthing looks good. I googled some C++ codes of MargeSort and try to debug it but i can't find mistake. Anyone see it?
//you have just one err,in last for you missed = :
//err: for(i = p; i < r; i++)
//correct: for(i = p; i <= r; i++)
#include <iostream>
using namespace std;
void Merge(int* A, int p, int q, int r)
{
int B[100], i = 0, j = 0, k = 0;
i = p;
k = p;
j = q + 1;
while (i <= q && j <= r)
{
if (A[i] <= A[j])
{
B[k] = A[i];
k++;
i++;
}
else
{
B[k] = A[j];
k++;
j++;
}
}
while (i <= q)
{
B[k] = A[i];
k++;
i++;
}
while (j <= r)
{
B[k] = A[j];
k++;
j++;
}
for (i = p; i <= r; i++)
{
A[i] = B[i];
}
}
void MergeSort(int A[], int p, int r)
{
int q;
if (p < r)
{
q = (p + r) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
}
int main(void)
{
int A[10]={9,8,7,6,5,4,3,2,1,0};
MergeSort(A,0,9);
for (int i = 0; i<10; i++)
{
cout<<A[i]<<",";
}
}
//this is cleaned version of your code:
#include <iostream>
using namespace std;
void Merge(int* A, int p, int q, int r)
{
int* B=new int[r-p+1];
int i = p;
int j = q + 1;
int k = 0;
while (i <= q && j <= r) B[k++] = (A[i] <= A[j])? A[i++] : A[j++];
while (i <= q) B[k++] = A[i++];
while (j <= r) B[k++] = A[j++];
for (i = p; i <= r; i++) A[i] = B[i-p];
delete B;
}
void MergeSort(int* A, int p, int r)
{
if (p >= r) return;
int q = (p + r) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
int main(void)
{
int A[15]={10,11,12,13,14,0,8,7,6,5,4,3,2,1,9};
MergeSort(A,0,14);
for (int i = 0; i<15; i++) cout<<A[i]<<",";
}
//this is another answer:
#include <iostream>
#include <climits>
using namespace std;
static void Merge(int* A, int p, int q, int r)
{
int n1 = q - p + 1;// A[p..q]
int n2 = r - q;// A[q+1..r]
int* L = new int[n1 + 1];
int* R = new int[n2 + 1];
int i, j;
for (i = 0; i < n1; i++)
L[i] = A[p + i];
for (i = 0; i < n2; i++)
R[i] = A[q + i+1];
L[n1] = INT_MAX;
R[n2] = INT_MAX;
i = 0;
j = 0;
for (int k = p; k <= r; k++)
A[k] = L[i] <= R[j] ? L[i++] : R[j++];
delete L;
delete R;
}
static void Ascending(int* A, int p, int r)
{
if (p >= r) return;
int q = (p + r) / 2;
Ascending(A, p, q);
Ascending(A, q + 1, r);
Merge(A, p, q, r);
}
int main()
{
int A[10]={9,8,7,6,5,4,3,2,1,0};
Ascending(A,0,9);
for (int i = 0; i<10; i++)
{
cout<<A[i]<<",";
}
}

mergesort in C++

#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
void mergesort(int a[], int p, int r);
void merge(int a[], int p, int q, int r);
int main(array<System::String ^> ^args)
{
int result[2] = { 1, 0 };
int *p;
p = result;
mergesort(p, 0,1);
while (1);
return 0;
}
void mergesort(int a[],int p, int r)
{
if (p < r)
{
int q = (p + r) / 2;
mergesort(a, p, q);
cout << endl;
mergesort(a, q + 1, r);
cout << endl;
merge(a,p,q,r);
for (int i = 0; i < 2; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
}
void merge(int a[], int p, int q, int r)
{
int left[100] = {};
int right[100] = {};
for (int i = 0; i < (q - p + 1); i++)
{
left[i] = *(a + p + i);
left[i + 1] = 999;
}
for (int i = 0; i < (r - q); i++)
{
right[i] = *(a + q + 1 + i);
right[i + 1] = 999;
}
for (int k = p; k < r+1; k++)
{
int i = 0;
int j = 0;
if (left[i] <= right[j])
{
a[k] = left[i++];
}
else
{
a[k] = right[j++]; **// it always goes into this route? why does not left[i]<=right[j] work?**
}
}
}
Here is my code about a basic merge sort. I cannot enter the first IF statement in the merge function. Why does if (left[i] <= right[j]) not work? I have tried may time whatever the left[i] is. The program just goes to the else statement.
for (int k = p; k < r+1; k++)
{
int i = 0;
int j = 0;
if (left[i] <= right[j])
{
a[k] = left[i++];
}
else
{
a[k] = right[j++]; **// it always goes into this route? why does not left[i]<=right[j] work?**
}
}
This does not do what you think it does. It will always compare left[0] with right[0], because you declare i and j inside the for loop, so they will be reset to 0 on each iteration.
To make them retain their values, declare them outside the loop:
int i = 0;
int j = 0;
for (int k = p; k < r+1; k++)
{
if (left[i] <= right[j])
{
a[k] = left[i++];
}
else
{
a[k] = right[j++]; **// it always goes into this route? why does not left[i]<=right[j] work?**
}
}
If your intent is to use variables i and j in the loop only then try to restrict the scope of i and j to the loop by doing following.
for (int k = p, i = 0, j = 0; k < r+1; k++)
{
if (left[i] <= right[j])
{
a[k] = left[i++];
}
else
{
a[k] = right[j++];
}
}