I am new to programming, and I have been learning about Merge Sort Algorithm, I wrote the following code:
#include <iostream>
using namespace std;
void Merge(int *arr1, int i, int m, int n, int j)
{
int sizeOfNewArray = j - i + 1;
int sizeOfFirstArray = m - i + 1;
int sizeOfSecondArray = j - n + 1;
int *finalArray = new int[sizeOfNewArray];
int *k = &finalArray[i];
int *ptr1 = &arr1[i];
int *ptr2 = &arr1[n];
while (i < sizeOfFirstArray && j < sizeOfSecondArray)
{
if (*ptr1 >= *ptr2)
{
*k = *ptr1;
i++;
k++;
}
else if (*ptr1 < *ptr2)
{
*k = *ptr2;
j++;
k++;
}
}
while (i < sizeOfFirstArray)
{
*k = *ptr1;
i++;
k++;
}
while (j < sizeOfSecondArray)
{
*k = *ptr2;
j++;
k++;
}
}
void MergeSort(int *arr1, int i, int j)
{
if (i != j)
{ //i represnts first index of array, j represents last index of array
int m = (i + j) / 2;
MergeSort(arr1, i, m);
MergeSort(arr1, m + 1, j);
Merge(arr1, i, m, m + 1, j);
}
if (i == j)
{
return;
}
}
int main()
{
int arr[] = {8, 6, 7, 1, 2, 4, 3, 5};
MergeSort(arr, 0, 7);
for (int i = 0; i < 8; i++)
{
cout << arr[i] << endl;
}
return 0;
}
According to me, this program should return the sorted array 1,2,3,4,5,6,7,8. However,on executing this code, it prints
8
6
7
1
2
4
3
5
I have tried debugging the code, but I am not able to find out what the error is. Can someone please have a look at the code, and tell me where is the error?
Apologies in advance for any silly error and thanks for taking out your time and concern.
Merge merges into the finalArray, which has nothing to do with arr1. Once Merge returns, finalArray ceases to exist (leaking memory), and arr1 remains untouched.
Before return, copy finalArray back to arr1, and delete[] it.
Related
This code is supposed to be an Insertion sort but is it implemented as such? I'm lost. The first loop goes through the array and checks if the next element is smaller than the current element. The nested loop inserts the next element(j) correctly in its place in the sorted portion of the array.
#include <iostream>
using namespace std;
// Print array
void printArray(int array[], int arraySize)
{
for (int i = 0; i < arraySize; i++)
{
cout << array[i] << " ";
}
cout << endl;
}
int main()
{
int array1[] ={5, 3, 1, 9, 8, 2, 4, 7};
int array1Size = sizeof(array1)/sizeof(int);
printArray(array1, array1Size);
for (int i = 0; i < array1Size - 1; i++)
{
int oldNum = array1[i];
if (array1[i] > array1[i + 1])
{
array1[i] = array1[i + 1];
array1[i + 1] = oldNum;
}
int newI = array1[i];
// Check if arranged correctly
if ( i > 0)
{
// Swap bigger number and newI
for (int j = i - 1; newI < array1[j]; j--)
{
if (j < 0)
{
break;
}
array1[j + 1] = array1[j];
array1[j] = newI;
}
}
printArray(array1, array1Size);
}
return 0;
}
The key to insertion sort is to maintain a "sorted zone" and expand it in loop. In the beginning the zone is only one element, and finally it's all the list. We take an element outside the sorted zone and decide which position in sorted zone that it should be placed in.
BTW, loop invariant is easy to understand but powerful and awesome. Recommended.
int main() {
int array1[] ={5, 3, 1, 9, 8, 2, 4, 7};
int array1Size = sizeof(array1)/sizeof(int);
// loop invariant: array1[0..i-1] is sorted
// array1[i] is the element to be inserted
for (size_t i = 1; i < array1Size; i++) {
int temp = array1[i];
// find the right place to insert array1[i]. Can be replaced by binary search(but moving elements is more expensive than comparing)
size_t j = i; // j is used to save the right place
for (; j > 0 && array1[j-1] > temp; j--) {
array1[j] = array1[j-1];
}
array1[j] = temp;
}
return 0;
}
This for loop
for (int j = i - 1; newI < array1[j]; j--)
{
if (j < 0)
{
break;
}
array1[j + 1] = array1[j];
array1[j] = newI;
}
can invoke undefined behavior when j is equal to -1 due to this expression in the condition of the for loop
newI < array1[j]
And the code is too complicated. For example this code snippet
if (array1[i] > array1[i + 1])
{
array1[i] = array1[i + 1];
array1[i + 1] = oldNum;
}
where two elements are swapped is redundant. And this if statement
if ( i > 0)
{
also is redundant. It is enough to start the outer loop from 1 instead of from 0.
It is better to define a separate function. It can look for example the following way
void InsertionSort( int a[], size_t n )
{
for (size_t i = 1; i < n; i++)
{
if (a[i] < a[i - 1])
{
int tmp = a[i];
size_t j = i;
for ( ; j != 0 && tmp < a[j - 1]; --j )
{
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
}
Pay attention to that the operator sizeof yields a value of the type size_t. You should use this type size_t for the variable that will be store the number of elements in the array. In general the type int is not large enough to store sizes of arrays.
If your compiler supports C++ 17 then instead of using the expression with the sizeof operator
int array1Size = sizeof(array1)/sizeof(int);
you could write at least
#include <iterator>
//...
int array1Size = std::size( array1 );
Also as the function printArray does not change the passed array then it first parameter should be declared with the qualifier const.
void printArray(const int array[], int arraySize);
Here is a demonstration program that shows usage of a separate function that sorts arrays using the insertion sort method..
#include <iostream>
#include <iterator>
void InsertionSort( int a[], size_t n )
{
for (size_t i = 1; i < n; i++)
{
if (a[i] < a[i - 1])
{
int tmp = a[i];
size_t j = i;
for ( ; j != 0 && tmp < a[j - 1]; --j )
{
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
}
int main()
{
int array1[] ={5, 3, 1, 9, 8, 2, 4, 7};
for ( const auto &item : array1 )
{
std::cout << item << ' ';
}
std::cout << '\n';
InsertionSort( array1, std::size( array1 ) );
for ( const auto &item : array1 )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
The program output is
5 3 1 9 8 2 4 7
1 2 3 4 5 7 8 9
I've been trying to do the count inversions question using mergesort for the past 2-3 days and after much trying, I just picked up the answer from Hackerrank's editorial, now their code is using an Array, and if I use a Vector instead of an Array, the answer is Actual answer + 1 (or different to say the least haven't tried it on many cases). I was wondering what might be the reason for it.
I also have another question on explanation of this code, in particular the variable declarations and their use in the mergei function. I understand the rest of the code conceptually, but because of this part, I have some confusion.
int ni = ((i+j)/2) + 1, nj = j + 1;
int s = i;
int* arr = new int [j - i + 1];
j = ni; int k = 0;
Code:
void mergei(int a[], int i, int j) {
int ni = ((i+j)/2) + 1, nj = j + 1;
int s = i;
int* arr = new int [j - i + 1];
j = ni; int k = 0;
while(i < ni && j < nj) {
if(a[i] <= a[j]) {
arr[k++] = a[i++];
} else {
arr[k++] = a[j++];
ans += (ni-i);
}
}
for(; i < ni; i++, k++) arr[k] = a[i];
for(; j < nj; j++, k++) arr[k] = a[j];
for(k = 0; s < nj; s++, k++) a[s] = arr[k];
delete [] arr;
}
void m_sort(int a[], int i, int j) {
if(i < j) {
m_sort(a, i, (i+j)/2);
m_sort(a, ((i+j)/2) + 1, j);
mergei(a, i, j);
}
}
int main() {
// vector<int> a = {2, 1, 3, 1, 2};
int a[] = {2, 1, 3, 1, 2};
// int n = a.size();
int n = sizeof(a)/sizeof(a[0]);
m_sort(a, 0, n - 1);
cout << ans << endl;
return 0;
}
I was not passing the Vector by reference, something I didn't have to worry about in case of array.
I try to implement the merge sort algorithm and I get a segmentation fault. Why? The error seems to be in the MergeSort function. The merge sort function (on the 2nd call) when should check only an array of 4 numbers (the length should be 4) shows the length = 27. Why? (tested on an array with 8 elements)
#include<iostream>
using namespace std;
int n, A[1000];
void citire(int lungime) {
for (int i = 0; i < lungime; i++) cin >> A[i];
}
void afisare(int lungime) {
for (int i = 0; i < lungime; i++)
cout << A[i] << " ";
cout << '\n';
}
int lungime(int A[]) {
int i = 0;
while (A[i]) i++;
return i;
}
void Merge(int L[], int R[], int A[]) {
int nL = lungime(L);
int nR = lungime(R);
int i = 0, j = 0, k = 0;
while (i < nL && j < nR) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < nL) {
A[k] = L[i];
i++;
k++;
}
while (j < nR) {
A[k] = R[j];
j++;
k++;
}
}
void MergeSort(int A[]) {
int n1 = lungime(A);
if (n1 < 2) return;
else
{
int mid = (int)n1 / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++)
L[i] = A[i];
for (int i = mid; i < n; i++)
R[i - mid] = A[i];
MergeSort(L);
MergeSort(R);
Merge(L, R, A);
}
}
int main() {
cin >> n;
citire(n);
MergeSort(A);
afisare(n);
return 0;
}
Changes made in this example. A[], L[], R[] are allocated using new. A[] is passed as a parameter. L[] and R[] are allocated in Merge(). Size and/or indices passed as parameters, and lungime() is no longer used to get size. Other changes noted in comments.
#include<iostream>
using namespace std;
void citire(int A[], int lungime) { // A is parameter
for (int i = 0; i < lungime; i++) cin >> A[i];
}
void afisare(int A[], int lungime) { // A is parameter
for (int i = 0; i < lungime; i++)
cout << A[i] << " ";
cout << '\n';
}
// A, low, mid, end are parameters
// L and R allocated here
void Merge(int A[], int low, int mid, int end) {
int sizeL = mid-low;
int sizeR = end-mid;
int *L = new int[sizeL];
int *R = new int[sizeR];
for(int i = 0; i < sizeL; i++)
L[i] = A[low+i]; // A[low+i]
for(int i = 0; i < sizeR; i++)
R[i] = A[mid+i]; // A[mid+i]
int i = 0, j = 0, k = low; // k = low
while (i < sizeL && j < sizeR) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < sizeL) {
A[k] = L[i];
i++;
k++;
}
while (j < sizeR) {
A[k] = R[j];
j++;
k++;
}
delete[] R;
delete[] L;
}
// A, low, end are parameters
void MergeSort(int A[], int low, int end) {
int sizeA = end - low;
if(sizeA < 2)
return;
int mid = low + (sizeA / 2); // mid = low + ...
MergeSort(A, low, mid);
MergeSort(A, mid, end);
Merge(A, low, mid, end);
}
int main() {
int n;
cin >> n;
int *A = new int[n]; // A is allocated
citire(A, n); // A, n are parameters
MergeSort(A, 0, n); // A, 0, n are parameters
afisare(A, n); // A, n are parameters
delete[] A;
return 0;
}
"The lungime function is the length of the string and this function works good. I've tested it on different arrays".
Well, this is purely accidental; uninitialized memory can contain zeros, and provide the array terminator by accident.
If you want to keep the current design, you should:
initialize A to zeros
make sure that there are no more than 999 elements in the input stream,
that no element has the value zero, as zero is reserved, and used as terminator, and
define L and R (in MergeSort) one element longer, and initialize the last element to zero.
Unless there are overwhelming reasons for a "roll your own" sort solution, you might have a look at prefab sort support. The vector class in C++ offers just that.
I am working on a quicksort algorithm implementation in c++ and I have not been able to get it to work as it should. I have researched several sources and my code looks flawless, but the array is not sorting as it should.
Here is my code:
#include <iostream>
using namespace std;
void quicksort(int[],int, int);
int partition(int[], int, int);
int main()
{
int a[] = {5, 1, 9, 3, 8, 4, 1, 2, 6, 7};
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
cout << endl;
quicksort(a, 0, 9);
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
return 0;
}
void quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r);
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
int partition(int a[], int p, int r)
{
int x = a[r];
int i = (p - 1);
for (int j = p; j <= r-1; j++)
{
if (a[j] <= x)
{
i++;
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
int tmp = a[i+1];
a[i+1] = a[r];
a[r] = a[tmp];
return (i + 1);
}
When I run this code the following is displayed:
5 1 9 3 8 4 1 2 6 7
1 1 2 4 4 4 6 7 7 7
I am not sure what I am doing wrong here. Thanks for your help.
In the second to last line of your partition function you should have:
a[r] = tmp;
instead of:
a[r] = a[tmp];
You are overwriting parts of your array with other members instead of completing the third step of your swap.
Here is code I have written for inversion count in c++. If you write some other recursion method. Please try to explain it to me.
I am storing inversion count in countI. I am getting 2 as output for array A[] i have declared in main function.
#include<iostream>
#include<math.h>
using namespace std;
int countI = 0;
void merge(int A[], int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int *L;
L = new int[n1];
int *R;
R = new int[n2];
for (int i = 1; i <= n1; i++)
{
L[i] = A[p + i - 1];
// cout << A[p + i - 1]<<endl;
//cout << L[i];
}
for (int j = 1; j <= n2; j++)
R[j] = A[q + j];
int i = 1, j = 1;
// cout << "li " << L[n1]<<"\t"<<R[n2];
for (int k = p; k <= r; k++)
{
if ((L[i] <= R[j] && i <= n1) || j>n2)
{
A[k] = L[i];
//cout << A[k];
i++;
}
else
{
A[k] = R[j];
j++;
if (i<n1)
countI += n1 - i+1; //here I am counting the inversion.
//cout <<endl<<"R"<< R[j];
}
}
}
void mergeSort(int A[], int p, int r)
{
if (p < r)
{
// cout << A[8];
int sum = p + r;
//int q = (sum) / 2 + (sum % 2);
int q = (sum) / 2;
mergeSort(A, p, q);
mergeSort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
//I am considering array from index 1
int A[] = { 0, 1, 3, 5,2,4,6 };
// int arr[100001];
int i = 1;
int n = 0;
//while (scanf("%d", &n) != EOF) { arr[i++] = n; }
mergeSort(A, 1, 6);
for (int i = 1; i <= 6; i++)
{
cout << A[i] << " ";
}
cout << "\n " << countI;
system("pause");
return 0;
}
You should note C++ uses 0 index based arrays.
The first element of L and R are 0, not 1.
The same thing when you call mergeSort in you main.
try mergeSort(A, 0, 5)
While your consistent with your mistake of indexing starting at 1. You run off the end of your arrays by 1. This can cause your program to crash; however, when it doesn't you often get weird answers (which are hard to debug) because you're improperly accessing and writing over memory.
Here is some pseudo code (for 0 indexed based arrays) that will count inversions while performing merge sort.
merge(A, p, m , q){
B = [] // array size of q - p + 1
i = p, j = m+1, k = 0, inv = 0
while (i <= m && j <= q){
if (A[i] < A[j])
B[k++] = A[i++]
else{
B[k++] = A[j++]
inv += m - i + 1
}
}
while (i <= m) // copy rest of left side to temp array
B[k++] = A[i++] // otherwise it may be overwritten
i = 0;
while (i < k){ // copy temp array elements back to A
A[p+i] = B[i]
++i
}
return inv
}
merge_sort(A, p, q){
if (p == q)
return 0;
m = floor((p + q)/2)
inv1 = merge_sort(A, p, m)
inv2 = merge_sort(A, m+1, q)
return inv1 + inv2 + merge(A, p, m, q)
}
// you can call it like this:
A = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 10 Elements
inversions = merge_sort(A, 0, 9) // sort and count inversions from index 0 to index 9