Merge Sort Error : Segmentation Fault - c

I'm getting an error Segmentation Fault:11, please help.
variable info:(s:start, e:end, m:mid, n:array), testing for a sample array n[] = {4,3,2,1}. a1 and a2 are temporary arrays. I am guessing there's something with the calculation of m:mid and passing it.
#include <stdio.h>
void merge(int s, int e, int m, int n[]) {
int l1 = m - s;
int l2 = e - m + 1;
int a1[l1];
int a2[l2];
for (int i = 0; i < l1; i++) {
a1[i] = n[s + i];
}
for (int j = 0; j < l2; j++) {
a2[j] = n[s + m + j];
}
int i = 0, j = 0;
for (int k = 0; k < l1 + l2; k++) {
if (a1[i] <= a2[j] && i != l1 && j != l2) {
n[k] = a1[i];
i++;
} else if (a2[j] <= a1[i] && i != l1 && j != l2) {
n[k] = a2[j];
j++;
} else if (j == l2 && i != l1) {
n[k] = a1[i];
i++;
} else if(i == l1 && j != l2) {
n[k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]) {
if (s < e) {
int m = (e - s) / 2;
mergeSort(s, m - 1, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
int main(void) {
int n[] = { 4, 3, 2, 1 };
int r = 4;
mergeSort(0, r - 1, n);
for(int i = 0; i < r; i++) {
printf("%i\n", n[i]);
}
}

The computation of m for the middle element is bogus: you get the offset of m from s, not its index into the array.
Here is a corrected version:
void mergeSort(int s, int e, int n[]) {
if (s < e) {
int m = s + (e - s + 1) / 2;
mergeSort(s, m - 1, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
There are other issues in your code, notably:
you should check the offsets i and j beforedereferencinga1[i]anda2[j]`.
the offset k should not be used directly in the merge phase, you should store to n[s + k].
in the initialization loop for a2, you should use a2[j] = n[m + j]; instead of a2[j] = n[s + m + j];
Note also that it is idiomatic to pass ranges in C with the first index included and the last index excluded. This allows for passing empty ranges, which your current method does not. It also makes the code much simpler and easier to read.
Here is a modified version:
#include <stdio.h>
void merge(int s, int e, int m, int n[]) {
int l1 = m - s;
int l2 = e - m;
int a1[l1];
int a2[l2];
for (int i = 0; i < l1; i++) {
a1[i] = n[s + i];
}
for (int j = 0; j < l2; j++) {
a2[j] = n[m + j];
}
for (int i = 0, j = 0, k = 0; k < l1 + l2; k++) {
if (i < l1 && (j >= l2 || a1[i] <= a2[j])) {
n[s + k] = a1[i];
i++;
} else {
n[s + k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]) {
if (e > s + 1) {
int m = s + (e - s) / 2;
mergeSort(s, m, n);
mergeSort(m, e, n);
merge(s, e, m, n);
}
}
int main(void) {
int n[] = { 4, 3, 2, 1 };
int r = sizeof(n) / sizeof(n[0]);
mergeSort(0, r, n);
for(int i = 0; i < r; i++) {
printf("%i\n", n[i]);
}
return 0;
}

I've modified your code in several places. Try to use your debugger or pen & paper to understand what's going on under the hood.
void merge(int s, int e, int m, int n[]){
int l1 = m-s + 1;
int l2 = e - m;
int a1[l1];
int a2[l2];
for(int i = 0; i < l1; i++){
a1[i] = n[s+i];
}
for(int j = 0; j < l2; j++){
a2[j] = n[m+j + 1];
}
int i = 0, j = 0;
for(int k = 0; k < l1+l2; k++){
if(a1[i] <= a2[j] && i != l1 && j != l2){
n[k] = a1[i];
i++;
}else if(a2[j] <= a1[i] && i != l1 && j != l2){
n[k] = a2[j];
j++;
}else if(j == l2 && i != l1){
n[k] = a1[i];
i++;
}else if(i == l1 && j != l2){
n[k] = a2[j];
j++;
}
}
}
void mergeSort(int s, int e, int n[]){
if(s<e){
int m = s + (e-s)/2;
mergeSort(s, m, n);
mergeSort(m + 1, e, n);
merge(s,e,m, n);
}
You will be fine I guess.

I think you have a stack overflow problem because of infinite recursive calls. Look
void mergeSort(int s, int e, int n[]){
if(s<e){
int m = (e-s)/2;
mergeSort(s, m-1, n);
mergeSort(m, e, n);
merge(s,e,m, n);
}
}
You pass these values of s and e:
s e function
-------------
0 3 mergeSort
0 0 mergeSort -> end
1 3 mergeSort
0 0 mergeSort -> end
1 3 mergeSort
... (infinite calls)
Then the stack grows and grows while new functions called until in the end it exceeds the maximum possible size, which leads to SEGFAULT.

Related

Recursive function to dynamic programming

So ive got this recursive function:
int solution(int i, int j, int n, int m, int **A, int c, int **B, int **C, int *D, int *E) {
int a, b, k, w;
if (i < n && j < m) {
B[i + j][0] = i;
B[i + j][1] = j;
D[i + j] = c;
}
else if (i == n && j == m) {
B[i + j - 1][0] = i;
B[i + j - 1][1] = j;
D[i + j - 1] = c;
}
if (A[i][j] == 'C') {
c++;
}
if (i == n - 1 && j == m - 1) {
if (c > maxcoins) {
for (w = 0; w < n + m; w++) {
C[w][0] = B[w][0];
C[w][1] = B[w][1];
E[w] = D[w];
}
maxcoins = c;
}
}
if (i < n - 1) {
a = i + 1;
k = solution(a, j, n, m, A, c, B, C, D, E);
}
if (j < m - 1) {
b = j + 1;
k = solution(i, b, n, m, A, c, B, C, D, E);
}
}
and i want to convert it to a dynamic programming solution but i cant figure out how to do it. Basically given a 2D array of C and . ,C representing coins and . blank spots it has to figure out the maximum number of coins one can collect only by moving down and right(maxcoins is an external variable). I would appreciate it if you got any answears that might help, thanks!

Invalid results in merge sort application

Hello I am working on an application of the merge sort algorithm however after a few hours I am unable to find a solution. Any help or hint would be appreciated. I have tried to debug my code but after many attempts I have not been successful in seeing what the mistake is.
The problem is that the algorithm gives back a wrong result. Example:
input: (10, 5, 16, 2)
output: (2, 5, 5, 10)
#include <stdio.h>
void mergesort(int A[], int l, int r);
void merge(int A[], int l, int q, int r);
int main() {
int n;
scanf("%d", &n);
int tablica[n];
for (int i = 0; i < n; i++)
scanf("%d", &tablica[i]);
mergesort(tablica, 0, n - 1);
for (int i = 0; i < n; i++)
printf("%d ", tablica[i]);
return 0;
}
void mergesort(int A[], int l, int r) {
if (l < r) {
int q = (l + r) / 2;
mergesort(A, l, q);
mergesort(A, q + 1, r);
merge(A, l, q, r);
}
}
void merge(int A[], int l, int q, int r) {
int n = q - l + 1;
int m = r - q;
int B[n];
int C[m];
for (int i = 0; i < n; i++)
B[i] = A[i];
for (int i = 0; i < m; i++)
C[i] = A[q + 1 + i];
int i = 0;
int j = 0;
for (int k = l; k <= r; k++) {
if (B[i] <= C[j] || j >= m) {
A[k] = B[i];
i++;
} else {
A[k] = C[j];
j++;
}
}
}
Without knowing what exactly doesn't work (Does it not compile? Do you get wrong output for some inputs?) it's hard to help. At least one error is here:
if(B[i] <= C[j] || j >= m)
Should be
if(j >= m || i < n && B[i] <= C[j])
It is both important to check j >= m before you check the inequality, and add the i < n check.
Without the latter once you fully consume the B array, B[i] will go beyond the array boundaries, and you will get undefined behavior.
Without the former once j >= m the condition B[i] <= C[j] will be checked before j >= m, also triggering undefined behavior.
UPDATE: with the actual example you provided, the second error narrows down to replacing B[i] = A[i] with B[i] = A[l + i]. With these two changes the example you provided works.
The function merge has several bugs.
For example the size of the array C shall be calculated like
int m = r - q + 1;
instead of
int m = r - q;
Instead of this for loop
for(int i = 0; i < n; i++)
B[i] = A[i];
you have to write
for(int i = 0; i < n; i++)
B[i] = A[l + i];
This if statement
if(B[i] <= C[j] || j >= m)
can result in undefined behavior because there is no check of the validity of the used indices i and j whether they belong to the valid ranges.
The functions can be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
void merge( int a[], size_t left, size_t middle, size_t right )
{
size_t n1 = middle - left;
size_t n2 = right - middle;
int a1[n1];
int a2[n2];
for ( size_t i = 0; i < n1; i++ )
{
a1[i] = a[left + i];
}
for ( size_t i = 0; i < n2; i++ )
{
a2[i] = a[middle + i];
}
size_t i = left, i1 = 0, i2 = 0;
while ( i1 < n1 && i2 < n2 )
{
a[i++] = a2[i2] < a1[i1] ? a2[i2++] : a1[i1++];
}
while ( i1 < n1 ) a[i++] = a1[i1++];
while ( i2 < n2 ) a[i++] = a2[i2++];
}
void mergesort( int a[], size_t left, size_t right )
{
if ( left + 1 < right )
{
size_t middle = ( left + right ) / 2;
mergesort( a, left, middle );
mergesort( a, middle, right );
merge( a, left, middle, right );
}
}
int main(void)
{
size_t n;
if ( scanf( "%zu", &n ) == 1 && n != 0 )
{
int a[n];
for ( size_t i = 0; i < n; i++ ) scanf( "%d", a + i );
mergesort( a, 0, n );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
return 0;
}
If the input is
4
10 5 16 2
then the output will be
2 5 10 16
There is a bug in the merge function:
if (B[i] <= C[j] || j >= m) accesses B[i] and C[j] before testing if i and j are below their respective boundaries. The test should be:
if (i < n && (j >= m || B[i] <= C[j])) {
A[k] = B[i++];
} else {
A[k] = C[j++];
}
Note also these remarks:
you do not need to save the second half of the array because its elements are copied before they get overwritten.
in void mergesort(int A[], int l, int r) r should be excluded, to avoid confusing and error prone +1/-1 adjustments.
similarly, in void merge(int A[], int l, int q, int r), q should be the start of the second half and r the index of the element after the end of the slice.
l looks confusingly similar to 1
Here is a modified version:
#include <stdio.h>
void mergesort(int A[], int low, int high);
void merge(int A[], int low, int mid, int high);
int main() {
int n;
if (scanf("%d", &n) != 1 || n <= 0)
return 1;
int tablica[n];
for (int i = 0; i < n; i++) {
if (scanf("%d", &tablica[i]) != 1)
return 1;
}
mergesort(tablica, 0, n);
for (int i = 0; i < n; i++)
printf("%d ", tablica[i]);
printf("\n");
return 0;
}
void mergesort(int A[], int low, int high) {
if (high - low >= 2) {
int mid = low + (high - low) / 2;
mergesort(A, low, mid);
mergesort(A, mid, high);
merge(A, low, mid, high);
}
}
void merge(int A[], int low, int mid, int high) {
int n = mid - low;
int B[n];
for (int i = 0; i < n; i++)
B[i] = A[low + i];
int i = 0;
int j = mid;
int k = low;
while (i < n) {
if (j >= high || B[i] <= A[j]) {
A[k++] = B[i++];
} else {
A[k++] = C[j++];
}
}
}

Time efficiency of Introduction to Database

I have a code that requires me to do this thing :
Input size of array and testcases.
A character of Operatiion such as (I,A,D,Q) and elements of array.
I : Adding an element into the array.
A : Will change data in the database to a new data that is not exist in
the database.
D : Delete data which has value X from database.
Q : Show all data that less than equal X from database.
Input :
<size of Array> <operations/testcase>
<I/A/D/Q> <elements of array with X value>
The example of input :
Input :
6 4
3 2 3 1 5 6
I 7
D 6
A 3 5
Q 7
Output :
6 (because only 1 Q operation)
I already created the program, but I think this is not efficient enough because it take a longer time to execute. My question is what should I do to make my program more efficient?
#include "stdio.h"
#define MAXSIZE 99999
void swap(int *a,int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void printArr(int arr[]){
for(int i = 0; arr[i] != NULL; i++){
printf("%d ",arr[i]);
}
printf("\n");
}
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
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);
}
}
int binarySearch(int arr[], int left, int right,int num){
if(right >= left){
int mid = (left + right) / 2;
if(num == arr[mid]) return mid;
if(arr[mid] > num) return binarySearch(arr, left, mid-1, num);
else return binarySearch(arr,mid+1,right, num);
}
return -1;
}
int main(int argc, char const *argv[])
{
int operations, sizeArr, numX, numY, arr[MAXSIZE];
char type;
scanf("%d %d",&sizeArr,&operations); getchar();
int index = 0, counter = 0;
for(index = 0; index < sizeArr; index++){
scanf("%d",&arr[index]); getchar();
}
mergeSort(arr, 0, sizeArr - 1);
int left = 0, deleted = 0;
for(int j = 0; j < operations; j++){
scanf("%c",&type); getchar();
if(type == 'I'){
scanf("%d",&numX); getchar();
arr[index++] = numX;
sizeArr++;
}
else if(type == 'A'){
scanf("%d %d",&numX, &numY); getchar();
mergeSort(arr, 0, sizeArr - 1);
for(int i = deleted; arr[i] != NULL ; i++){
if(arr[i] == numX){
int old = arr[i];
arr[i] = numY;
if(arr[i + 1] != old) break;
}
}
}
else if(type == 'D'){
scanf("%d",&numX); getchar();
for(int i = 0; arr[i] != NULL ; i++){
if(arr[i] == numX){
int old = arr[i];
arr[i] = -1;
deleted++;
if(arr[i + 1] != old) break;
// sizeArr--;
}
}
mergeSort(arr, 0, sizeArr - 1);
}
else if(type == 'Q'){
scanf("%d",&numX); getchar();
mergeSort(arr, 0, sizeArr - 1);
// printArr(arr);
for(int i = deleted; i < sizeArr ; i++){
if(arr[i] <= numX && arr[i] > -1){
counter++;
// printf("%d\n",arr[i]);
}
else break;
}
printf("%d\n",counter);
counter = 0;
}
// printf("Size Arr : %d\n", sizeArr);
// printf("Deleted : %d\n",deleted);
// printArr(arr);
}
return 0;
}
Could you please tell me my mistake to my program more efficient on time limit?
They didn't mention the time limit duration. It only gives 5/10 testcase that correct. So I need to find another efficient way to make my code goes faster.

Write code into pseudocode

I need help to write this code into pseudocode
public void quickSort(int[] A, int p, int r) {
if (p < r) {
int q = partition(A, p, r);
quickSort(A, p, q);
quickSort(A, q + 1, r);
}
}
private int partition(int[] A, int p, int r) {
int x = A[p]; // pivot element x
int i = p - 1;
int j = r + 1;
// partition
while (true) {
do {
j--;
} while (A[j] > x);
do {
i++;
} while (A[i] < x);
if (i < j)
swap(A, i, j);
else
return j;
}
}
private void swap(int[] A, int i, int j) {
int tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
for each (unsorted) partition
set first element as pivot
storeIndex = pivotIndex + 1
for i = pivotIndex + 1 to rightmostIndex
if element[i] < element[pivot]
swap(i, storeIndex); storeIndex++
swap(pivot, storeIndex - 1)

Debugging a merge sort implementation in c

I am debugging a c implementation of merge sort. For some reason, the value of r (in merge) is nan. Yet, n2 (defined as (int) (r - q)) is well defined. Why is r == nan ?
#include <stdio.h>
#include <limits.h>
#include <math.h>
void merge(int *A,float p,float q,float r)
{
float n = r - p + 1; /* number of elements in array A */
int n1 = (int) (q - p + 1);
int n2 = (int) (r - q);
printf("n2 = %d\n",n2);
int i, j;
float k;
int *L, *R;
for (i = 1; i <= n1; i++){
L[i] = A[(int) (p + i - 1)];
}
for (j = 1; j < n2; j++){
R[j] = A[(int) (q + j)];
}
L[n1+1] = INT_MAX;
R[n2+1] = INT_MAX;
i = 1;
j = 1;
printf("p = %f\n",p);
printf("r = %f\n",r);
for (k = p; k <= r; k++){
printf("k=%f\n",k);
if (L[i] <= R[j]){
A[(int) k] = L[i];
i += 1;
}
else{
A[(int) k] = R[j];
j += 1;
}
}
}
void merge_sort(int *A, float p, float r)
{
int i;
/* for (i=0; i<=r-p;i++){
printf("%d\n",A[i]);
}*/
float q;
if (p < r){
/* printf("merge_sort p = %d\n",p);
printf("merge_sort r = %d\n",r);*/
q = floor((p + r)/2);
/* printf("q = %f\n",q);*/
merge_sort(A, p, q);
merge_sort(A, q+1, r);
/* printf("done\n");*/
merge(A, p, q, r);
}
}
int main()
{
int x, c, *array;
int n;
printf("Enter number of elements\n");
scanf("%d",&n);
printf("Enter %d elements\n",n);
for (c = 0; c < n; c++){
scanf("%d", &array[c]);
}
merge_sort(array, 0, n-1);
for (c = 0; c < n; c++){
printf("%d\n", array[c]);
}
}
int *L, *R;
for (i = 1; i <= n1; i++){
L[i] = A[(int) (p + i - 1)];
}
L and R are used uninitialized
Same for array:
int x, c, *array;
...
for (c = 0; c < n; c++){
scanf("%d", &array[c]);

Resources