Having Segmentation Fault on the following code of counting inversions in an array.
#include <iostream>
#include <limits.h>
using namespace std;
int merge(int *a, int p, int q, int r);
int mergesort(int *a, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
//Dividing the array in two.
int l = mergesort(a, p, q);
int r = mergesort(a, q + 1, r);
int cross = merge(a, p, q, r);
return (l + r + cross);
} else
return 0;
}
This was the mergesort function supposed to divide the array. Doesn't seem to have an error here.
int merge(int *a, int p, int q, int r) {
int inv_count =0;
int n1 = q - p + 1, n2 = r - q;
int L[n1 + 1], R[n2 + 1];
//Two subarrays with last elements as inf.
L[n1] = INT_MAX; R[n2] = INT_MAX;
for (int i = p, j = 0; j < n1; i++, j++) L[j] = a[i];//copy left
for (int i = q + 1, j = 0; j < n2; i++, j++) R[j] = a[i];//copy right
int i = 0, j = 0, k = p;//merge and count
while (k <= r) {
if (L[i] <= R[j]) {
a[k++] = L[i];
i++;
} else {
a[k++] = R[j];
inv_count += n2 - j + 1;
j++;
}
}
return inv_count;
}
The problem maybe seems to have in the above function where I have declared the L and the R array.
int main() {
//code
int n; cin >> n;
int a[n];
for (int i = 0; i < n; i++) cin >> a[i];
cout << mergesort(a, 0, n - 1);
return 0;
}
Example input: 5 5 4 3 2 1 shows Seg Fault.
In mergesort, you have a shadowing problem:
int r = mergesort(a,q+1,r);
^
The r argument passed isn't the r declared in the function, it's the r you just declared. That's undefined behavior.
By "print debugging" merge with the code:
int merge(int *a, int p, int q, int r) {
int inv_count = 0;
int n1 = q - p + 1, n2 = r - q;
std::cout << "merge(a, " << p << ", " << q << ", " << r << ')'<< std::endl;
std::cout << "\tsize of L: " << (n1 + 1) << std::endl;
std::cout << "\tsize of R: " << (n2 + 1) << std::endl;
(...)
I got the output:
merge(a, 0, 0, 0)
size of L: 2
size of R: 1
merge(a, 0, 1, 0)
size of L: 3
size of R: 0
merge(a, 0, 2, 0)
size of L: 4
size of R: -1
The segfault happens when you try to create an array with negative size. Notice the r parameter passed to merge, it's because of that first problem.
There are multiple problems in the code:
int r = mergesort(a, q + 1, r); redefines r and passes an uninitialized value to mergesort instead of the argument r. Use a different variable name such as:
int nr = mergesort(a, q + 1, r);
L[n1] = INT_MAX; R[n2] = INT_MAX; using sentinel values to avoid testing the index values in the merge phase is a common but nefarious example in some textbooks. The algorithm will fail if the array contains entries with the value INT_MAX, which is possible with the main() function provided. Don't use this silly approach and test the index values.
cout << mergesort(a, 0, n - 1); Passing the index to the last element of the slice leads to cumbersome code with non-intuitive + 1 and - 1 adjustments. Furthermore it does not allow passing empty slices. Passing the index of the first excluded element is more idiomatic in C and C++ and simplifies the code.
int q = (p + r) / 2; This expression can overflow and produce an incorrect value for q. It should be written: int q = p + (r - p) / 2;
index values should have type size_t.
Here is a modified version for small values of n:
#include <iostream>
using namespace std;
size_t merge(int *a, size_t p, size_t q, size_t r) {
size_t inv_count = 0;
size_t n1 = q - p, n2 = r - q;
int L[n1], R[n2];
for (size_t i = 0; i < n1; i++) L[i] = a[p + i];
for (size_t i = 0; i < n2; i++) R[i] = a[q + i];
size_t i = 0, j = 0, k = p; //merge and count
while (k <= r) {
if (i < n1 && (j == n2 || L[i] <= R[j])) {
a[k++] = L[i];
i++;
} else {
a[k++] = R[j];
inv_count += n2 - j + 1;
j++;
}
}
return inv_count;
}
size_t mergesort(int *a, size_t p, size_t r) {
if (r - p > 1) {
size_t q = p + (r - p) / 2;
// Dividing the array in two.
size_t nl = mergesort(a, p, q);
size_t nr = mergesort(a, q, r);
size_t cross = merge(a, p, q, r);
return nl + nr + cross;
} else {
return 0;
}
}
int main() {
size_t n; cin >> n;
int a[n];
for (size_t i = 0; i < n; i++) cin >> a[i];
cout << mergesort(a, 0, n);
return 0;
}
Related
I was solving a problem and i was using the same recursive method as used in merge sort. But it didn't give the desired output so i decided to implement basic merge sort first, and i think i am missing something in my recursive algo
This is my merge sort, though i doubt there's anything wrong here but still if you need it for reference:
void mergeSort(int arr[], int l, int r)
{
if (l < r)
{
int m = l+(r-l)/2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
// merge both the sorted array
merge(arr, l, m, r);
}
}
Now the merge function which i believe is incomplete or incorrect:
void merge(int arr[], int l, int m, int r)
{
//these are going to be the iterators for our left, right and our final output array respectively
int i = 0, j = 0, k = 0;
// n1 is the size of the first array which is going to be one more than the differene of the mid index number and the first indexing number of the complete array
int n1 = m - l + 1;
// n2 is the size of the second array and the index of this array is starting from m + 1th element of the complete array
int n2 = r - m;
int L[n1];
int R[n2];
// populate the left array with elements upto n1 - 1th element of the array
for (int x = 0; x < n1; x++)
{
L[x] = arr[x];
}
//populate the right array
for (int x = 0; x < n2; x++)
{
R[x] = arr[x + n1];
}
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
k++;
}
else
{
arr[k] = R[j];
j++;
k++;
}
}
}
What am i doing wrong here?
Well you have some bug in your code.
you should take element starting from lower index in merge function, in left halve:
L[x] = arr[l+x];
you need to it same for right halve too:
R[x] = arr[m+x +1];
you should complete scanning in case of different length of array, when they are comparing in merge function:
while(i < n1){
arr[k++] = L[i++];
}
while(j <n2){
arr[k++] = R[j++];
}
and least but not the last, you should fill the array from the lower index, not always from 0:
int i = 0, j = 0, k = l;
Here is final code, after modifying:
#include <stdio.h>
void merge(int arr[], int l, int m, int r){
int i = 0, j = 0, k = l;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1];
int R[n2];
for (int x = 0; x < n1; x++)
{
L[x] = arr[l+x];
}
for (int x = 0; x < n2; x++)
{
R[x] = arr[m+x +1];
}
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
k++;
}
else
{
arr[k] = R[j];
j++;
k++;
}
}
while(i < n1){
arr[k++] = L[i++];
}
while(j <n2){
arr[k++] = R[j++];
}
}
void mergeSort(int arr[], int l, int r) {
if (l < r){
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void main(){
int arr[4] ={3, 1, 2, 5};
mergeSort(arr, 0, 3);
for(int i=0; i<4; i++){
printf("%i ", arr[i]);
}
}
I've been having problems trying to figure out how to fix this code I wrote for Mergesort.
The intended result was to output a sorted array of inputs, but the void merge function contains errors that result in either an unsorted array or an array of really large or small numbers.
I've tried many times to fix them, but the result still doesn't come out perfectly.
Can you look it over and tell me what I've been doing wrong?
#include "pch.h"
#include <iostream>
using namespace std;
void merge(int* arr, int p, int q, int r) {
//copy A[p.q] into L
//and A[q+1.r] into R
int i, j, k;
int n1 = q - p + 1;
int n2 = r - q;
int* L = new int[n1+1];
int* R = new int[n2+1];
for (i = 1; i <= n1; i++) {
L[i] = arr[p+i-1];
}
for (j = 1; j <= n2; j++){
R[j] = arr[q+j];
}
L[n1+1] = 99999;
R[n2+1] = 99999; //represents infinity
i = j = 1;
for (k = p; k <= r; k++)
{
if (L[i] <= R[j]) {
arr[k] = L[i];
i = i + 1;
}
else {
arr[k] = R[j];
j = j + 1;
}
return;
}
}
void mergesort(int* arr, int p, int r) {
if (p < r) {
int q = floor((p + r) / 2);
mergesort(arr, p, q);
mergesort(arr, q + 1, r);
merge(arr, p, q, r);
}
return;
}
int main() {
int r;
cin >> r;
int* arr = new int[r];
for (int i = 0; i < r; i++) {
int num;
cin >> num;
arr[i] = num;
}
int p = 0;
//sortint function
mergesort(arr,p,r);
for (int i = 0; i < r; i++) {
cout << arr[i] << ";";
}
return 0;
}
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;
}
Welcome, I have to code Quicksort Lomuto and Hoare variation in C++ using MinGW.
So, I have done it. Algorithms works fine for arrays[N] where N is small number like 5, 20, 100 but I need to do it on N = 200 000. And there is exception. I don't know why. Other algorithms(Insertion, Selection, Heapsort etc. works fine for N = 200 000).
Here is my code:
int PartitionLomuto(int A[], int p, int r)
{
int x = A[r],
i = p - 1,
temp;
for (int j = p; j <= r - 1; j++)
if (A[j] <= x) {
i++;
temp = A[i];
A[i] = A[j];
A[j] = temp;
}
temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
void Lomuto (int A[], int p, int r)
{
if (p < r) {
int q = PartitionLomuto(A, p, r);
Lomuto(A, p, q - 1);
Lomuto(A, q + 1, r);
}
}
//* **************************************************
int PartitionHoare(int A[], int p, int r)
{
int x = A[p],
i = p,
j = r,
temp;
while(true) {
while(A[j] > x)
j--;
while(A[i] < x)
i++;
if(i < j) {
temp = A[i];
A[i] = A[j];
A[j] = temp;
i++;
j--;
}
else
return j;
}
}
void Hoare(int A[], int p, int r)
{
if(p < r) {
int q = PartitionHoare(A, p, r);
Hoare(A, p, q);
Hoare(A, q + 1, r);
}
}
I'm creating arrays in that way:
int const arraySize = 200000;
int *ascending = new int[arraySize],
*descending = new int[arraySize],
*random = new int[arraySize];
And call function in that way:
Hoare(random,0, arraySize - 1);
Exception is in Partition function.
I really don't know what is going. I think algorithm is written right.
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