Hybrid Mergesort and Insertion sort - c++

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

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

why I get C6001 warning in my merge sort?

I have written code below but I get warning C6001: using uninitialized memory
in merge function before last line at arr[z] = S[z] , I have used dynamic array because VS-2022 don't support VLA.
I have seen different types of merge algorithms but I want this specific code to run because I am using an instruction that I have to follow for my project!
#include <iostream>
void merge(int*, int, int, int);
void merge_sort(int*, int, int);
void printArrey(int*, int);
int main()
{
int arr[9] = { 9,8,7,6,5,4,3,2,1 };
printArrey(arr, 9);
merge_sort(arr, 0, 8);
printArrey(arr, 9);
system("pause");
}
void merge(int* arr, int start, int mid, int end)
{
int i = start, j = mid+1, k = start;
int* S = new int[end+1];
while (i <= mid && j <= end)
{
if (arr[i] < arr[j])
{
S[k] = arr[i];
i++;
}
else
{
S[k] = arr[j];
j++;
}
k++;
}
if (i > mid)
{
for (; j <= end; k++, j++)
{
S[k] = arr[j];
}
}
else if (j > end)
{
for (; i <= mid; k++, i++)
{
S[k] = arr[i];
}
}
for (int z=0; z < k; z++)
{ arr[z] = S[z]; }
delete[] S;
}
void merge_sort(int* arr, int start, int end)
{
if (start < end)
{
int mid = start+ (end - start) / 2;
merge_sort(arr, start, mid);
merge_sort(arr, mid+1, end);
merge(arr, start, mid, end);
}
}
void printArrey(int* arr, int size)
{
for(int i = 0; i < size; i++)
{
std::cout << arr[i] << "\t";
}
std::cout << "\n";
}
I had to use
while(start<=end)
{
arr[start] = S[start];
start++;
}
instead of
for (int z=0; z < k; z++)
{ arr[z] = S[z]; }
tnx to anyone who helped!

My C++ Merge Sort code isn't working. What am i missing here?

In my code , lb refers to lower bound and ub refers to upper bound.I'm using the mergeSort function to recursively split the array into smaller pieces and the merge function to merge in their sorted order.
#include <iostream>
using namespace std;
void merge(int input[], int lb, int ub, int size)
{
int i = lb;
int k = 0;
int mid = (lb + ub) / 2;
int j = mid + 1;
int *arr = new int[size];
while (i <= mid && j <= ub)
{
if (input[i] <= input[j])
arr[k++] = input[i++];
else
arr[k++] = input[i++];
}
while (i <= mid)
arr[k++] = input[i++];
while (j <= ub)
arr[k++] = input[j++];
for (k = 0; k < size; k++)
input[k] = arr[k];
}
void mergeSort(int input[], int size)
{
int lb = 0;
int ub = size - 1;
int mid;
if (size == 0)
{
return;
}
else if (lb < ub)
{
mid = (lb + ub) / 2;
mergeSort(input, mid - lb + 1);
mergeSort(input + mid + 1, ub - mid);
merge(input, lb, ub, size);
}
else
{
return;
}
}
int main()
{
int input[1000], length;
cin >> length;
for (int i = 0; i < length; i++)
cin >> input[i];
mergeSort(input, length);
for (int i = 0; i < length; i++)
{
cout << input[i] << " ";
}
}
You have used i istead of j in the first while loop in merge function. The correct code is the following
while (i <= mid && j <= ub) {
if (input[i] <= input[j])
arr[k++] = input[i++];
else
arr[k++] = input[j++];
}

Merge_sort without sentinel

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

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