Error in merge sort program - c

I am doing a merge sort program in C but I'm getting some unexpected output.
Can anyone find out error in the program?
#include<stdio.h>
int array[100],n;
void merge(int l,int m,int h);
void mergesort(int start,int end);
main(){
int i;
printf("Enter Size: ");
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&array[i]);
}
mergesort(0, n-1);
for(i=0;i<n;i++){
printf("%d\n",array[i]);
}
}
void mergesort(int start,int end){
int mid;
if(start<end){
mid=(start+end)/2;
mergesort(start,mid);
mergesort(mid+1,end);
merge(start,mid,end);
}
}
void merge(int start,int mid,int end){
int i,j,k;
int a1[100],a2[100];
for(k=0,i=start;i<=mid;i++,k++){
a1[k]=array[i];
}
for(k=0,j=i;j<=end;j++,k++){
a2[k]=array[j];
}
a1[mid]=999;
a2[j]=999;
i=0;j=0;
for(k=start; k <=end; k++)
{
if(a1[i]<=a2[j])
array[k]=a1[i++];
else
array[k]=a2[j++];
}
}
Output:
Enter Size: 5
1 2 3 2 3
2
2
3
3
-1818025592
For larger arrays, the output is more scrambled. I think there is an error in merge() function.

You are terminating your a1 and a2 arrays at the wrong location.
Try changing:
for(k=0,i=start;i<=mid;i++,k++){
a1[k]=array[i];
}
for(k=0,j=i;j<=end;j++,k++){
a2[k]=array[j];
}
a1[mid]=999;
a2[j]=999;
to
for(k=0,i=start;i<=mid;i++,k++){
a1[k]=array[i];
}
a1[k]=999;
for(k=0,j=i;j<=end;j++,k++){
a2[k]=array[j];
}
a2[k]=999;

When you create your temporary arrays:
for (k = 0, i = start; i <= mid; i++, k++) {
a1[k] = array[i];
}
a1[i] = 999;
you put a sentinel value with a high value at the end. But i is the index into the original array. You must use k, the index of the temporary array a1:
for (k = 0, i = start; i <= mid; i++, k++) {
a1[k] = array[i];
}
a1[k] = 999;
Even so, the double control structure with k and i is clumsy. And there's no need to guess a high number; <limits.h> has constants defined for the min and max values of most types:
k = 0;
for (i = start; i <= mid; i++) {
a1[k++] = array[i];
}
a1[k] = INT_MAX;
Here, you increment k when an item is appended. This works even when the assignment happens conditionally, i.e. not in all iterations.
Finally, I would recommend to use exclusive upper bounds. That's the natural way to express ranges in C. mid would then be both the exclusive upper bound of the left array and the inclusive lower bound of the right array.

I have solved it
a[mid + 1]=999
a[k]=999

Related

Quick sort recursive function in C - doesn't work with big number of elements

Has this function been written correctly?
It seems that something is wrong when I try to run the function with a large number of elements in the array (eg 1000).
Then its appears to stop.
int quick_sort(int n, int tablica[],int b, int a)
{
if(a==n-1 || n==0) return;
if(b==n-1)
{
b=0;
a++;
}
if(tablica[b]>tablica[b+1])
{
bufor=tablica[b];
tablica[b]=tablica[b+1];
tablica[b+1]=bufor;
}
b++;
return quick_sort(n,tablica,b,a);
}
Above code will not work even for a small array, unless the small array is unsorted in a particular way. It compares one element with the next element. If the array is say {4,3,8,7,1} the sort will fail, because it has no mechanism to push 1 to the start of the array.
For larger arrays there are too many recursion and the program hits the stack limit and simply fails.
You can use recursion in quicksort but the number of recursions has to be kept in check. For example for array of size 1000 you don't want to have to more than 1000 recursion. Example:
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void quicksort(int arr[], int low, int high)
{
if(low < high)
{
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++)
{
if(arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
int pi = i + 1;
quicksort(arr, low, pi - 1);
quicksort(arr, pi + 1, high);
}
}
int main()
{
int arr[] = { 7,3,6,1,4,8,9,2 };
int arrsize = sizeof(arr) / sizeof(*arr);
quicksort(arr, 0, arrsize - 1);
for(int i = 0; i < arrsize; i++)
printf("%d\n", arr[i]);
return 0;
}

C - using to pointer to function yield no result

I am creating a program which uses a pointer to function to allow the user to select from 2 options to perform on an array of integers: reverse or randomise. However, the program yield no output when executed. Where did I go wrong?
void reverseArray(int arraySize, int a[]);
void randomiseArray(int arraySize, int a[]);
void printArray(int arraySize, int a[], void (*arrayFunction)(int arraySize, int a[]));
int main ()
{
srand(time(NULL));
int selection;
int myArray[] = {2,4,6,8,10,12,14,16,18,20};
printf("Enter 0 for reverse, 1 for randomise.\n");
scanf("%d",&selection);
if (selection == 0)
printArray(sizeof(myArray)/sizeof(myArray[0]),myArray,reverseArray);
else if (selection == 1)
printArray(sizeof(myArray)/sizeof(myArray[0]),myArray,randomiseArray);
else
printf("Please make a valid selection\n");
return 0;
}
void reverseArray(int arraySize, int a[])
{
int i,j=arraySize,swap=0;
for (i=0;i<arraySize/2;i++)
{
swap = a[i];
a[i] = a[j];
a[j] = swap;
--j;
}
}
void randomiseArray(int arraySize, int a[])
{
int i,j,swap;
for (i=0;i<arraySize;i++)
{
j = rand()%(i+1);
if (j!=i)
{
swap = a[i];
a[i] = a[j];
a[i] = swap;
}
}
}
void printArray(int arraySize, int a[], void (*arrayFunction)(int arraySize, int a[]))
{
arrayFunction(arraySize, a);
for (int i = 0; i < arraySize; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
The user selects when function they want to perform by typing either 0 for reverse or 1 for randomise. Based on the decision, a printArray function is called with the respective choice.
reverseArray is just a generic swap function, and randomiseArray uses a Fisher-Yates shuffling algorithm.
I am assuming that the source of my error lies in the printArray fucntion, yet I cannot correct it.
Two errors
in reverseArray, j should start at arraysize - 1 or you will be writing one element past the end of the array
void reverseArray(int arraySize, int a[])
{
int i, j = arraySize - 1, swap = 0;
for (i = 0; i<arraySize / 2; i++)
{
swap = a[i];
a[i] = a[j];
a[j] = swap;
--j;
}
}
And in randomizearray(), you assign to a[i] twice, instead of using a[j] for the final assignment.
void randomiseArray(int arraySize, int a[])
{
int i, j, swap;
for (i = 0; i<arraySize; i++)
{
j = rand() % (i + 1);
printf("%d %d\n", i, j);
if (j != i)
{
swap = a[i];
a[i] = a[j];
a[j] = swap;
}
}
}
The first error causes undefined behavior when reversing, the second causes the array to stay the same. Other than that, the function pointers are setup fine and work correctly.
In reverseArray() your index j is out of range, it should he j=arraySize-1
Other than that it works for me.
You are accessing outside the bounds of your array, causing UB and in this case "no output":
In reverseArray, you must initialize j=arraySize-1. Without the -1 you go out of bounds.

Writing merge sort in C without pointers

I am trying to write code for homework in C that will take 10 integers from user input into an array and sort it using a recursive merge sort. We have not gone over pointers yet so I wanted to avoid using that in my code (many online examples use pointers).
Here is my code:
/* This code will take input for 10 integers given by the user
into an array, sort them with a recursive merge function
and print the updated array in ascending order. */
#include <stdio.h>
#define ARRSIZE 10
void merge_sort (int arr[], int temp[], int left, int right);
void merge (int arr[], int temp[], int left, int mid, int right);
int main (void){
int arr[ARRSIZE], temp[ARRSIZE], left, right, i;
printf("Enter 10 integers for an array:");
for(i=0;i<ARRSIZE;i++){
printf("\narray value %d:", i+1);
scanf("%d", &arr[i]);
}
left = 0;
right = ARRSIZE-1;
merge_sort(arr, temp, left, right);
printf("\nHere is your updated array:");
printf("\n{");
for(i=0;i<ARRSIZE;i++){
printf("%d,", arr[i]);
}
printf("}");
return 0;
}
void merge_sort (int arr[], int temp[], int left, int right){
if(left<right){
int mid = (right-left)/2;
merge_sort(arr, temp, left, mid);
merge_sort(arr, temp, mid+1, right);
merge(arr, temp, left, mid, right);
}
}
void merge (int arr[], int temp[], int left, int mid, int right){
int i, j, tempi = 0;
for(i=left, j=mid+1; i<=mid && j<=right ;){
// mid+1 is the start of the right array
if(arr[i]<arr[j] && i<=mid){
temp[tempi] = arr[i];
tempi++;
i++;
}
else if(arr[i]>arr[j] && j<=right){
temp[tempi] = arr[j];
tempi++;
j++;
}
}
for(i=0,j=right; i<=j; i++){
arr[i] = temp[i];
}
}
I keep getting a segmentation fault when I run this in my linux shell. Any suggestions?
Well, I've found one subtle bug already: int mid = (right-left)/2; should be int mid = (left+right)/2;
Also, what flows I've found:
You should use tempi = left for simplicity. Simply copy incoming part of array to corresponding part of temporary array.
In your merge cycle, you can place incrementing tempi inside for definition:
for( ...; ...; ++tempi)
Inside that loop you check boundaries AFTER you have read values from that place. This is very bad. VERY. Although, You haven't encounter any problems here just because you are checking boundaries inside for definition :) simply remove them:
for (i = left, j = 1 + mid; i <= mid && j <= right; ++tempi)
{
if (arr[i] < arr[j]) temp[tempi] = arr[i++];
else /* arr[j] <= arr[i] */ temp[tempi] = arr[j++];
}
Cause this loop exits when either subarray has reached end, you have to copy rest of items from another subarray to temp[]:
if (i > mid) i = j; /* if we need to copy right subarray */
for (; tempi <= right; ++tempi, ++i) temp[tempi] = arr[i];
So, your copying back from temporary array will look like
for (i = left; i <= right; ++i) arr[i] = temp[i];

QuickSort doesn't work for large inputs

Can anyone spot a problem with my quick sort implementation below? It seems to fail on arrays with more than 10 or so elements.
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void generateRandom(int arr[], int size)
{
srand(time(NULL));
int i;
for (i = 0; i < size; i++)
{
arr[i] = rand() % 100;
}
}
int partition(int arr[], int start, int end)
{
int i = start, j = end;
int pivot = arr[start];
for (;;)
{
for (; arr[i] < pivot; i++);
for (; arr[j] > pivot; j--);
if (i < j)
{
swap(&arr[i], &arr[j]);
}
else
{
return j;
}
}
}
void quickSort(int arr[], int start, int end)
{
int part;
if (start < end)
{
part = partition(arr, start, end);
quickSort(arr, start, part);
quickSort(arr, part + 1, end);
}
}
int main()
{
generateRandom(arr, 100);
for (i = 0; i < 100; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
quickSort(arr, 0, 99);
for (i = 0; i < 100; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
return 0;
}
First, you code doesn't compile. When I made the corrections to make it compile (adding stdio.h, and definitions for arr and i in main) it infinite looped, which it will do if the partition starts and ends with the pivot. You need to increment and decrement before the comparisons rather than after. You can do that by starting with i = start-1 and j = end+1 and changing your inner loops to increment or decrement first, or you can leave them as is and just do an i++ and j-- after the swap -- I did that and the sort works.
Note that your pivot choice is poor for already sorted arrays; you really should be picking the median of 3 or even 9 values.
P.S. Other desirable optimizations: 1) Switch to an insertion sort for small partitions -- the optimal cutoff point is machine-dependent. Another approach is to not sort partitions below a certain size, and then do an insertion sort on the whole array after quicksort is done. It's also possible to use heapsort instead of insertion sort if done carefully; google introsort. 2) quicksort does two recursive calls; eliminate the second one by setting start = part + 1 and looping. 3) Avoid the possibility of stack overflow by quicksorting the larger partition first. 4) Eliminate the first recursive call by using an explicit stack. 5) Inline swap() and partition(). 6) Don't bother with any of that and just call the qsort library routine. :-)
I had the same problem,
but I changed my while loop to do..while and it worked.
This is my new code now.
int partition(int a[], int lo, int hi) {
int v = a[lo], i = lo, j = hi;
do {
do {
i++;
} while(a[i] < v) ;
do {
j--;
}while(a[j] > v) ;
if(i < j) interchange(&a[i], &a[j]);
}while(i < j);
interchange(&a[lo], &a[j]);
return j;
}

mergesort C implementation

i wrote this code in C language on Xcode following the algorithm of mergesort.
The problem is that sometimes i get EXC_BAD_ACCESS and i can't manage where the error is!
The merge algorithm should work (i tried it outside the mergesort function and works!). Thank you for your help and patience!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DIM 6
void mymerge (int v[], int i1,int i2, int last); //mergesort core: merge two ordinated arrays in one bigger ordinated array
void mymergesort (int v[], int lower, int upper);//mergesort
void printv (int v[],int lower, int upper);
int main () {
int i;
srand((unsigned int)time(NULL));
int v[DIM];
for (i=0; i<DIM; i++)
v[i]=rand()%15;
printv(v, 0, DIM-1);
getc(stdin);
mymergesort(v, 0, DIM-1);
printv(v, 0, DIM-1);
}
void printv (int v[],int lower, int upper){
int i;
for (i=lower; i<=upper; i++)
printf("%d\t",v[i]);
}
void mymergesort (int v[], int lower, int upper){
int mid=(upper+lower)/2;
if (upper<lower) {
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
void mymerge (int v[], int i1,int i2, int last){
int i=i1,j=i2,k=i1,*vout;
vout=(int*)malloc((last-i1+1)*sizeof(int));
while (i<i2 && j<=last) {
if (v[i]<=v[j]) {
vout[k++]=v[i++];
}else {
vout[k++]=v[j++];
}
}
for (;i<i2;i++) vout[k++]=v[i];
for (;j<=last;j++) vout[k++]=v[j];
for (k=i1; k<=last; k++) v[k]=vout[k];
free(vout);
}
EDIT:
thank you very much! but i think think there is another problem, when I try to sort a bigger array (200 elements), the program doesn't work (i get a malloc error: incorrect checksum for freed object - object was probably modified after being freed). But if I run it from the xCode debugger everything works fine
This: vout=(int*)malloc((last-i1)*sizeof(int)); is wrong.
First, the number of elements you want is last-i1+1, not last-i1 - classic off-by-1. This kind of error is one of the reasons why the convention in C code is to make lower bounds inclusive and upper bounds exclusive - less +1 and -1 you need to do, less opportunity to screw up.
The more serious error is that you index vout starting from i1. If you do it this way, you need to allocate last+1 element for vout, and you never use the first i1 (index 0 .. i1-1).
Fix: First, allocate last-i1+1 elements. Second, initialize k to 0 at the beginning, not i1. Third, change the final copy to be
for (k=i1; k<=last; k++) v[k] = vout[k-i1];
You have two problems. The first is that your calculation of the midpoint is incorrect - you use (upper - lower)/ 2, but this is not guaranteed to lie between lower and upper. What you actually want is lower + (upper - lower) / 2. It's also not necessary to do any work if there's only 1 number in the interval to be sorted - so the mymergesort() function should look like:
void mymergesort (int v[], int lower, int upper)
{
if (upper > lower) {
int mid = lower + (upper - lower)/2;
mymergesort(v, lower, mid);
mymergesort(v, mid+1, upper);
mymerge(v,lower,mid+1,upper);
}
}
The second problem is the one in the mymerge() function already pointed out by Fabian Giesen.
#include<stdio.h>
#include<stdlib.h>
void merge(int *a, int n1, int *b, int n2, int *arr)
{
int i=0, j=0, n=0;
while(i<n1 && j<n2)
{
if (a[i] < b[j])
{
arr[n++] = a[i];
i++;
}
else
{
arr[n++] = b[j];
j++;
}
}
while( i < n1)
arr[n++] = a[i++];
while( j < n2)
arr[n++] = b[j++];
}
void merge_sort(int *a, int n)
{
int left[n/2], right[n-n/2],i=0;
if (n<=1)
return ;
while(i<n/2)
left[i] = a[i++];
while(i<n)
right[i - n/2] = a[i++];
merge_sort( left, n/2 );
merge_sort( right, n-n/2);
merge(left, n/2, right, n-n/2, a);
}
void main()
{
int a[] = { 6, 5, 3, 1,9, 8, 7, 2, 4},i;
merge_sort(a,sizeof(a)/sizeof(a[0]));
for(i=0;i<9;i++)
printf("--%d",a[i]);
printf("\n");
}
-- s.k
#include<stdio.h>
#include<conio.h>
#define max 20
/*** function for merging the adjecent subarrays in sorted order ***/
void merge(int A[max],int n,int low,int high, int mid)
{
int i=low,j=mid+1,k,temp;
while((i<=j)&&(j<=high))
{
if(A[i]>A[j]) /** if element of the second half is greater then exchg and shift **/
{
temp=A[j];
for(k=j;k>i;k--) /** shifting the elements **/
{
A[k]=A[k-1];
}
A[i]=temp;
j++;
}
i++;
}
}
/******* iterative function for merge sort ********/
void merge_sort(int A[max],int n,int low,int high)
{
int mid;
if(low<high) /** terminating condition **/
{
mid=(high+low)/2; /** calculating the mid point ***/
merge_sort(A,n,low,mid); /*** recursive call for left half of the array ***/
merge_sort(A,n,mid+1,high); /*** recursive call for right half of the array ***/
merge(A,n,low,high,mid); /** merging the both parts of the array **/
}
}
/******* begening of the main function **********/
int main()
{
int A[max],n,i;
/** reading the inputs fro users **/
printf("\n enter the size of the array\n");
scanf("%d",&n);
printf("\n enter the array \n");
for(i=0;i<n;i++)
{
scanf("%d",&A[i]);
}
/*** calling merge sort ***/
merge_sort(A,n,0,n-1);
/** printing the sorted array **/
for(i=0;i<10;i++)
{
printf("\n\t%d",A[i]);
}
getch();
return 0;
}

Resources