Merge sort in C giving wrong results - c

I wrote a merge sort program but I got wrong results.
I've seen other programs like this, but they don't help me solve my problem. I think the problem is in the merge function.
#include <stdio.h>
#include "stdafx.h"
#define Size 5
//this is the array
int arr[Size] = { 5, 4, 3, 2, 1 };
int sr[10];
void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);
int main(void) {
mergesort(arr, 0, 4, 5);
for (int i = 0; i < Size; i++) {
printf_s("%i", sr[i]);
}
printf_s("\n");
return 0;
}
void mergesort(int a[], int start, int end, int size) {
if (size < 2)
return;
int s = size / 2;
mergesort(a, start, (start + end) / 2, s);
mergesort(a, (start + end) / 2, end, s);
merge( a, start, end, s);
}
void merge(int a[], int start, int end, int size) {
int left = start;
int right = ((start + end) / 2) + 1;
for (int i = 0; i < size; i++) {
if (left < (start + end)/2) {
if (right >= end) {
sr[i] = arr[left];
left++;
} else
if (arr[left] < arr[right]) {
sr[i] = arr[left];
left++;
} else {
sr[i] = arr[right];
right++;
}
} else {
sr[i] = arr[right];
right++;
}
}
}

(1)
printf_s("%i",sr[i]); should be printf_s("%i ", arr[i]);
(2)
mergesort(a, start, (start + end) / 2, s);//E.g index:{0,1,2,3,4}, start:0, (start + end) / 2 : 2, s: 2, but 0(start),1,2(new end), this length is 3, not 2
mergesort(a, (start + end) / 2, end, s);//Duplicate start position and length should be size - s. E.g size:5, s:2, rest size is 3, not 2.
merge( a, start, end, s);//s should be size
should be like
mergesort(a, start, start + s - 1, s);
mergesort(a, start + s, end, size - s);
merge(a, start, end, size);
(3)
Change according to (2)
Change int right = ((start + end) / 2) +1; to int right = start + size / 2;.
(4)
Add int sr[size]; //Avoid using global variables. It is better to use malloc. E.g int *sr = malloc(size*sizeof(int));...free(sr);
(5)
if (left < (start+end)/2)
{
if (right >= end)
should be
if (left < start + size / 2)
{
if (right > end){//Should be >, not >=
(6) Write back to arr form sr is necessary
Whole code:
#include <stdio.h>
#include <stdlib.h>
void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);
int main(void){
int arr[] = {5,4,3,2,1};
int size = sizeof(arr)/sizeof(*arr);
mergesort(arr, 0, size - 1, size);
for (int i = 0; i < size; i++){
printf_s("%i ", arr[i]);
}
printf_s("\n");
return 0;
}
void mergesort(int a[], int start, int end, int size){
if (size < 2)
return;
int s = size / 2;
mergesort(a, start, start + s - 1, s);
mergesort(a, start + s, end, size - s);
merge(a, start, end, size);
}
void merge(int a[], int start, int end, int size){
int left = start;
int right = start + size / 2;
int right_start = right;
int *sr = (int*)malloc(size*sizeof(*sr));//Cast(int*) is not necessary in C.
for (int i = 0; i < size; i++){
if (left < right_start){
if (right > end){
sr[i] = a[left++];
} else if (a[left] < a[right]) {
sr[i] = a[left++];
} else {
sr[i] = a[right++];
}
} else {
sr[i] = a[right++];
}
}
for(int i = 0; i < size; ++i)//write back.
a[start + i] = sr[i];
free(sr);
}

Your code is invalid for multiple reasons:
mergesort splits the range into 2 halves of size size / 2, which is incorrect if size is not even.
the arguments to mergesort are incorrect, only the pointer and the size are needed.
the merge function gets values from the global array arr instead of the argument array and stores values into the global temporary array sr, but does not copy it back into the a array.
Here is a corrected and simplified version:
#include <stdio.h>
void mergesort(int a[], int size);
int main(void) {
int arr[] = { 5, 4, 3, 2, 1 };
int size = sizeof(arr) / sizeof(arr[0]);
mergesort(arr, size);
for (int i = 0; i < size; i++) {
printf_s("%i ", arr[i]);
}
printf_s("\n");
return 0;
}
void merge(int a[], int mid, int size) {
int sr[mid]; // temporary array for the left part
if (a[mid - 1] <= a[mid]) { // quick check for sorted case
return;
}
for (int i = 0; i < mid; i++) { // save left part
sr[i] = a[i];
}
// merge into array `a`.
for (int i = 0, left = 0, right = mid; left < mid; i++) {
if (right == size || sr[left] <= a[right]) {
a[i] = sr[left++];
} else {
a[i] = a[right++];
}
}
}
void mergesort(int a[], int size) {
if (size >= 2) {
int mid = (size + 1) / 2; // make left part no smaller than right part
mergesort(a, mid);
mergesort(a + mid, size - mid);
merge(a, mid, size);
}
}

Related

My Quick Sort follows N^2 time complexity with random data

SOLVED: the answer was - the range of inputs was too small :) Thanks #sagi !
I've implemented a Quicksort algorithm for my classes and had to time the results for random data inputs (from -100 to 100).
Turns out, it follows N^2 time complexity almost to the dot and I have no idea why.
Here's the results of timing:
Time results
My time calculating function.
void Timing (void(*f)(int*, int), int *tab, int n, char *wiadomosc) {
clock_t start = clock();
f(tab, n); //losowe dane
clock_t end = clock();
printf("%s %lf \n", wiadomosc, (double)(end - start) / (CLOCKS_PER_SEC));
}
void QUICK_SORT_F(int *tab, int n) { //pivot as last element
quick_sort(tab, 0, n-1);
}
void quick_sort(int *tab, int first_indx, int last_indx) { //pivot as last element
while (first_indx < last_indx) {
int P = Part(tab, first_indx, last_indx);
if (P - first_indx > last_indx - P) {
quick_sort(tab, first_indx, P-1);
first_indx = P + 1;
} else {
quick_sort(tab, P + 1, last_indx);
last_indx = P - 1;
}
}
}
int Part(int* tab, int minIndx, int maxIndx) {
int pivot = tab[maxIndx];
int P = minIndx - 1;
for (int i = minIndx; i < maxIndx; ++i) {
if (tab[i] < pivot) {
++P;
SWAP(tab, i, P);
}
}
SWAP(tab, P + 1, maxIndx);
return P + 1;
} //for quicksort
void SWAP(int *tab, int x, int y) { //swaps tab[x] with tab[y]
int hld = tab[x];
tab[x] = tab[y];
tab[y] = hld;
}
As for popular request, here's the code to generate data:
int generuj(int min, int max) {
return (rand() % (max - min) + min);
}
void TESTY(void(*f)(int*, int),int n, char* metoda) {
FILE* FWB = fopen(PLIK_Z_DANYMI, "wb");
for (int i = 0; i < n; ++i) {
int r = generuj(-100, 100);
fwrite(&r, sizeof(r), 1, FWB);
}
fclose(FWB);
testowanko(f, n,metoda);
}
void testowanko(void(*f)(int*, int), int n, char* metoda) {
printf("\t %s \t \n",metoda);
FILE* RF = fopen(PLIK_Z_DANYMI, "rb");
int* tab = malloc(sizeof(int) * n);
fread(tab, sizeof(int), n, RF);
Timowanie(f, tab, n, "czas sortowania przy losowych danych = ");
}

Counting swaps in Quicksort in C

I am trying to count the number of swaps that occur in my quicksort in C. However, I am getting values that are incorrect and not sure where I went wrong. I am using a structures as my arrays to be sorted.
struct anArray{
int numbers[maxSize];
int swaps;
};
/* Partition function */
int partition(struct anArray *array, int start, int end){
if(start == end){
return start;
}
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for(;;){
do{
low++;
} while(array->numbers[low] < pivot);
do{
high--;
} while(array->numbers[high] > pivot);
/* Detector for when the cells meet */
if(low >= high){
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
This is my partition function used to "separate" the arrays.
void quickSort(struct anArray *array, int start, int end){
if(end - start <= 0){ return; }
else{
int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
}
This is my quicksorting function. It's a recursive function.
My swap function increments counter by 1 every time it's called.
In my main, I set
myArray->swaps = counter;
But the number of times the swaps occurs isn't right. For example, if I sort an array that goes from 1 to 9, the number of swaps should be 0 but I get 9. I've tried incrementing counter when it's in the partition function only but it gives me the same result.
Is there something wrong with my partition function?
Thank you very much
Edit 1:
Here's my swap function.
void swap(struct anArray *array, int first, int second){
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
counter++;
}
I've tried using
void swap(struct anArray *array, int first, int second, int swapCount)
and then have swapCount be array->swaps when calling the swap function, and incrementing it by 1 but it gives me the same answer.
Here's a part of my main.
int main(){
struct anArray *ascending = (struct anArray*)malloc(10 * sizeof(struct anArray));
int ascend[maxSize] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
initArray(ascending, ascend);
quickSort(ascending, 0, maxSize - 1);
ascending->swaps = counter;
printf("Test: Unique random values\nSorted: [ ");
for(int i = 0; i < maxSize; i++){
printf("%i ", ascending->numbers[i]);
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
The other parts of my main are just other arrays to be sorted. The initArray is used to set the values of array->numbers and also reset array->swaps to 0.
Your quicksort code seems pretty good. I didn't examine it rigorously, but it passed a simple test, so I didn't investigate further. (Edit: Based on your feedback, I created a third version in my second update that shows that the sort has an issue for larger data inputs).
The main bug was the malloc at the top of main. We do not want an array of the struct anArray:
struct anArray *ascending = malloc(10 * sizeof(struct anArray));
That is, we do not want (e.g.) 10 structs, we want a single struct and to fill in 10 ints that go into the numbers field that is in that single struct.
The initArray function was not posted, so I had to guess/deduce what it might be. Based on the above bug, I'm not sure that numbers would have been initialized correctly.
From the code fragments posted, I was able to piece together a whole program. I've created two versions:
One with the bugs annotated [but not fixed] that compiles cleanly.
And, a second that is fully cleaned up, working, and generalized for arbitrary array sizes [please pardon the gratuitous style cleanup]
Here is [something close to] your original code with the bugs annotated:
#include <stdio.h>
#include <stdlib.h>
// NOTE/BUG: this was not defined and _fixed_ defines should be all caps
#define maxSize 10
struct anArray {
int numbers[maxSize];
int swaps;
};
int counter;
void
initArray(struct anArray *array,const int *src)
{
for (int idx = 0; idx < maxSize; ++idx)
array->numbers[idx] = src[idx];
array->swaps = 0;
}
void
swap(struct anArray *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
counter++;
}
/* Partition function */
int
partition(struct anArray *array, int start, int end)
{
if (start == end) {
return start;
}
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(struct anArray *array, int start, int end)
{
if (end - start <= 0) {
return;
}
else {
// NOTE/BUG: pivot is _not_ used
int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
}
int
main(void)
{
// NOTE/BUG: we do _not_ want an array of the struct, but an array of int
// that is allocated for "number" _inside_ the struct
struct anArray *ascending = malloc(10 * sizeof(struct anArray));
int ascend[maxSize] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// NOTE/BUG: this was not defined
initArray(ascending, ascend);
quickSort(ascending, 0, maxSize - 1);
ascending->swaps = counter;
printf("Test: Unique random values\nSorted: [ ");
for (int i = 0; i < maxSize; i++) {
printf("%i ", ascending->numbers[i]);
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
return 0;
}
Here is a cleaned up and working version. I've generalized it so it can take an arbitrarily long array. I've also done a bit of style and code cleanup:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *numbers;
int size;
int swaps;
} Array;
Array *
initArray(const int *src,int size)
{
Array *array = malloc(sizeof(Array));
array->numbers = malloc(size * sizeof(int));
array->size = size;
// store in reverse order so the sort will actually do something
for (int idx = 0; idx < size; ++idx)
array->numbers[size - 1 - idx] = src[idx];
array->swaps = 0;
return array;
}
void
freeArray(Array *array)
{
free(array->numbers);
free(array);
}
void
swap(Array *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
array->swaps += 1;
}
/* Partition function */
int
partition(Array *array, int start, int end)
{
if (start == end)
return start;
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(Array *array, int start, int end)
{
if (end - start <= 0)
return;
//int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
int
main(void)
{
// NOTE/BUG: we do _not_ want an array of the struct, but an array of int
// that is allocated for "number" _inside_ the struct
int original[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int size = sizeof(original) / sizeof(original[0]);
Array *ascending = initArray(original, size);
quickSort(ascending, 0, ascending->size - 1);
printf("Test: Unique random values\nSorted: [ ");
for (int i = 0; i < ascending->size; i++) {
int expected = original[i];
int actual = ascending->numbers[i];
printf("%d%s ", actual, (actual == expected) ? "" : "???");
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);
freeArray(ascending);
return 0;
}
UPDATE:
What does the line int size = sizeof(original) / sizeof(original[0]); do exactly?
Does it give me an integer for size which I set to be the size of how many numbers I can hold in an array?
Yes, that is common/idiomatic trick to get the count of the number of elements of a fixed size array:
int array[] = { 1, 2, 3 };
size_t count = sizeof(array) / sizeof(array[0]);
Here, sizeof(array) is 3 times the size [in bytes] of the individual elements [which are int, which is 4 bytes], so we have 3 * 4 or 12.
sizeof(array[0]) is the size of the single, first element of the array, which is [again] an int, so this is 4.
So, when we divide the two, we have 12 / 4 or 3, which is the number of elements.
If so, wouldn't the amount of numbers I can hold be really small if sizeof(original[0]) happens to be very large?
No, because of the division. It doesn't care how large the element size [in bytes] is, because the ratio always produces the number of elements.
The sizeof(arr) / sizeof(arr[0]) trick is useful to get the count when we do: int arr[] = { ... };
If we do:
#define ARRCOUNT 3
int arr[ARRCOUNT] = { 1, 2, 3 };
We already know the count (i.e. it is ARRCOUNT).
The [slight] advantage to the sizeof/sizeof trick is that if we had incorrectly defined ARRCOUNT as 4 by mistake, it would still compile, link, and run, but would produce incorrect results [because there were only 3 elements].
This is a common enough trick that we can define a generic macro [that we can reuse by putting it a .h file]:
#define ARRAY_COUNT(arr_) (sizeof(arr_) / sizeof(arr_))
UPDATE #2:
I've tried your code (even tried copying and pasting it) but my swaps is still showing 9 despite my array to be sorted is just going from { 1 to 10}. Not sure why this keeps occurring.
I believe [now] you have a bug in the sort itself.
I've produced another version that has much more extensive test data generation and comparison.
At a minimum, because of the way the tests are structured, the first element of the sorted array should always have a value of 1.
The test that fails is the one that does a random shuffle of the original array before sending it in to be sorted.
You can add other tests as needed. The array needn't be so large to show the problem. For example, the following single test is enough to produce the error:
bigtest(100,237,1);
Anyway, here is the enhanced diagnostic code:
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 60
typedef struct {
int *numbers;
int size;
int swaps;
} Array;
Array *
initArray(const int *src,int size,int randshuf)
{
int idx;
Array *array = malloc(sizeof(Array));
array->numbers = malloc(size * sizeof(int));
array->size = size;
array->swaps = 0;
// store in reverse order so the sort will actually do something
switch (randshuf) {
case 0: // reverse the numbers
for (idx = 0; idx < size; ++idx)
array->numbers[size - 1 - idx] = src[idx];
break;
default: // do _crude_ random shuffle
for (idx = 0; idx < size; ++idx)
array->numbers[idx] = 0;
for (idx = 0; idx < size; ++idx) {
while (1) {
int ridx = rand() % size;
if (array->numbers[ridx] == 0) {
array->numbers[ridx] = src[idx];
break;
}
}
}
break;
}
return array;
}
void
freeArray(Array *array)
{
free(array->numbers);
free(array);
}
void
swap(Array *array, int first, int second)
{
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
array->swaps += 1;
}
/* Partition function */
int
partition(Array *array, int start, int end)
{
if (start == end)
return start;
int pivot = array->numbers[end];
int low = start - 1;
int high = end;
for (;;) {
do {
low++;
} while (array->numbers[low] < pivot);
do {
high--;
} while (array->numbers[high] > pivot);
/* Detector for when the cells meet */
if (low >= high) {
swap(array, low, end);
return low;
}
}
/* Swapping the values */
swap(array, low, high);
}
void
quickSort(Array *array, int start, int end)
{
if (end - start <= 0)
return;
//int pivot = array->numbers[end];
int partitionPoint = partition(array, start, end);
quickSort(array, start, partitionPoint - 1);
quickSort(array, partitionPoint + 1, end);
}
void
print_orig(const int *orig,int count)
{
int len = 0;
printf("Test: Original numbers (%d):\n",count);
for (int idx = 0; idx < count; ++idx) {
len += printf(" %10d ", orig[idx]);
if (len >= MAXLEN) {
printf("\n");
len = 0;
}
}
if (len > 0)
printf("\n");
}
int
print_array(Array *array,const int *orig,const char *reason)
{
int len = 0;
int cmp;
int err = -1;
printf("Test: Array Values (%s):\n",reason);
for (int idx = 0; idx < array->size; ++idx) {
int actual = array->numbers[idx];
if (orig != NULL) {
int expected = orig[idx];
cmp = (actual == expected);
}
else
cmp = 1;
len += printf(" %10d%c", actual, cmp ? ' ' : '?');
if (len >= MAXLEN) {
printf("\n");
len = 0;
}
if (cmp)
continue;
if (err < 0)
err = idx;
}
if (orig != NULL)
printf("\nSwaps: %i\nComps: \n\n", array->swaps);
else {
if (len > 0)
printf("\n");
}
return err;
}
void
bigtest(int count,int randgap,int randshuf)
// count -- number of elements (negative means random)
// randgap -- gap between element values (negative means random)
// randshuf -- 0=simple reverse, 1=random shuffle
{
int *orig;
Array *array;
printf("\n");
for (int idx = 1; idx <= 80; ++idx)
printf("-");
printf("\n");
printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);
// get number of elements
if (count < 0)
count = (rand() % count) + 1;
// get element gap (e.g. 1 --> {1, 2, 3}, 2 --> { 1, 3, 5 }
if (randgap < 0)
randgap = (rand() % randgap) + 1;
printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);
// get original array
orig = malloc(sizeof(int) * count);
// fill in original array
do {
int val = 1;
// simple gap
if (randgap >= 0) {
if (randgap == 0)
randgap = 1;
for (int idx = 0; idx < count; ++idx, val += randgap)
orig[idx] = val;
break;
}
// random gap
int gap;
for (int idx = 0; idx < count; ++idx, val += gap) {
orig[idx] = val;
gap = (rand() % randgap) + 1;
}
} while (0);
print_orig(orig,count);
array = initArray(orig,count,randshuf);
print_array(array,NULL,"Shuffled");
quickSort(array, 0, array->size - 1);
print_array(array,orig,"Sorted");
freeArray(array);
free(orig);
}
int
main(void)
{
bigtest(10,0,0);
bigtest(-100,23,0);
bigtest(-1000,-2337,0);
bigtest(-1000,-2337,1);
return 0;
}

Binary search implementation in C

First time posting here. I recently implemented Binary Search but sometimes my outputs will return a giant negative number instead. Now my first thought is that I'm printing a number where my pointer is pointing at a random memory location. Can someone help me with the logic and how I can improve my code?
#include <stdio.h>
#include <stdlib.h>
int binarysearch(int *array, int size, int target);
int main() {
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, 8, 15));
return 0;
}
int binarysearch(int *array, int size, int target) {
int mid;
mid = size / 2;
if (size < 1) {
return -1;
}
if (size == 1) {
return array[0];
}
if (target == array[mid]) {
return target;
} else
if (target < array[mid]) {
binarysearch(array, mid, target);
} else{
binarysearch(array + mid, size - mid, target);
}
}
For starters you call the function with an invalid number of elements in the array that has only 6 elements.
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, 8, 15));
^^^
Also this snippet
if (size == 1) {
return array[0];
}
is incorrect. It is not necessary that the first element is equal to target.
This statement
binarysearch(array + mid, size - mid, target);
has to be written like
binarysearch(array + mid + 1, size - mid - 1, target);
And at last the function has undefined behavior because it returns nothing in these cases
if (target < array[mid]) {
binarysearch(array, mid, target);
} else{
binarysearch(array + mid, size - mid, target);
}
You need to write
if (target < array[mid]) {
return binarysearch(array, mid, target);
} else{
return binarysearch(array + mid, size - mid, target);
}
And two words about the programming style. It is better to name the function either like binary_search or like binarySearch or at last like BinarySearchthan like binarysearch.
In general it is not a good design of the function. Imagine that the array has an element with the value -1. How will you determine whether this element is present in the array or is absent?
Usually such functions return pointer to the target element in case if it is found or NULL pointer otherwise.
Here is a demonstrative program that shows how this approach can be implemented.
#include <stdio.h>
int * binary_search( const int *a, size_t n, int target )
{
if ( n == 0 ) return NULL;
size_t middle = n / 2;
if ( a[middle] < target )
{
return binary_search( a + middle + 1, n - middle - 1, target );
}
else if ( target < a[middle] )
{
return binary_search( a, middle, target );
}
return a + middle;
}
int main(void)
{
int array[] = { 1, 2, 3, 4, 5, 6 };
const size_t N = sizeof( array ) / sizeof( *array );
for ( int i = 0; i < 8; i++ )
{
int *target = binary_search( array, N, i );
if ( target )
{
printf( "%d is found at position %d\n", *target, ( int )(target - array ) );
}
else
{
printf( "%d is not found\n", i );
}
}
return 0;
}
The program output is
0 is not found
1 is found at position 0
2 is found at position 1
3 is found at position 2
4 is found at position 3
5 is found at position 4
6 is found at position 5
7 is not found
By the way according to the C Standard function main without parameters shall be declared like
int main( void )
You call binarysearch(array, 8, 15)) but your array has only 6 entries.
Here is how to compute the proper size automatically:
int main(void) {
int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, sizeof(array) / sizeof(array[0]), 15));
return 0;
}
Note that your function binarysearch has problems too:
Returning the array entry is bogus, what do you return if the target is less than the first entry? -1 is not necessarily less than the first entry.
You are supposed to return the index into the array with the entry if found and -1 if not found.
When you recurse, you do not return the value from these recursive calls: you should compile with warnings enabled (for example: gcc -Wall -W) and look at all the helpful diagnostic messages the compiler produces.
Here is a modified version:
int binarysearch(const int *array, int size, int target) {
int a, b;
for (a = 0, b = size; a < b;) {
int mid = a + (b - a) / 2;
if (target <= array[mid]) {
b = mid;
} else {
a = mid + 1;
}
}
// a is the offset where target is or should be inserted
if (a < size && target == array[a])
return a;
else
return -1;
}
Notes:
Computing mid = (a + b) / 2; would be potentially incorrect for large sizes as there may be an arithmetic overflow. mid = a + (b - a) / 2; does not have this problem since a < b.
The time-complexity is O(Log N), and for a given size, the function performs the same number of steps for all target values.
If the array contains multiple identical values equal to target, the index returned by binarysearch is that of the matching entry with the lowest index.
You could make this problem easier by using the bsearch function offered by the <stdlib.h> library.
Something like this:
#include <stdio.h>
#include <stdlib.h>
int cmpfunc(const void * a, const void * b);
int
main(void) {
int array[] = {1, 2, 3, 4, 5, 6};
size_t n = sizeof(array)/sizeof(*array);
int *item;
int key = 15;
item = bsearch(&key, array, n, sizeof(*array), cmpfunc);
if (item != NULL) {
printf("Found item = %d\n", *item);
} else {
printf("Item = %d could not be found\n", key);
}
return 0;
}
int
cmpfunc(const void * a, const void * b) {
return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}
If you don't want to use bsearch, then this method will be fine also:
#include <stdio.h>
#include <stdlib.h>
#define BSFOUND 1
#define BS_NOT_FOUND 0
int cmpfunc(const void * a, const void * b);
int binary_search(int A[], int lo, int hi, int *key, int *locn);
int
main(void) {
int array[] = {1, 2, 3, 4, 5, 6};
size_t n = sizeof(array)/sizeof(*array);
int key = 4, locn;
if ((binary_search(array, 0, n, &key, &locn)) == BSFOUND) {
printf("Found item = %d\n", array[locn]);
} else {
printf("Item = %d cound not be found\n", key);
}
return 0;
}
int
binary_search(int A[], int lo, int hi, int *key, int *locn) {
int mid, outcome;
if (lo >= hi) {
return BS_NOT_FOUND;
}
mid = lo + (hi - lo) / 2;
if ((outcome = cmpfunc(key, A+mid)) < 0) {
return binary_search(A, lo, mid, key, locn);
} else if(outcome > 0) {
return binary_search(A, mid+1, hi, key, locn);
} else {
*locn = mid;
return BSFOUND;
}
}
int
cmpfunc(const void * a, const void * b) {
return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}

Merge sort of characters in string C

I have this working merge-sort algorithm in C. But it works only for integers. When I tried to change int to char, i'm getting segfault.
Can you please help me, what should I change in this code, so I could use MergeSort like this:
char*str = "test_string";
MergeSort(str, 0, strlen(str)-1);
void Merge(int *array, int left, int mid, int right){
int tempArray[right-left+1];
int pos=0,lpos = left,rpos = mid + 1;
while(lpos <= mid && rpos <= right){
if(array[lpos] <= array[rpos]){
tempArray[pos++] = array[lpos++];
}
else{
tempArray[pos++] = array[rpos++];
}
}
while(lpos <= mid) tempArray[pos++] = array[lpos++];
while(rpos <= right)tempArray[pos++] = array[rpos++];
int iter;
for(iter = 0;iter < pos; iter++){
array[iter+left] = tempArray[iter];
}
return;
}
void MergeSort(int *array, int left, int right){
int mid = (left+right)/2;
if(left<right){
MergeSort(array,left,mid);
MergeSort(array,mid+1,right);
Merge(array,left,mid,right);
}
return;
}
I'm lost. Thanks!
Change your declaration of array from int * to char * in both functions. Make tempArray a char[] instead of an int[]. You are trying to read memory that is 4x (or 8x) out of bounds at the end of the array, hence the seg-fault. Put another way, char is 1 byte (usually) while int is 4 or 8, so you are looking at items of a different size stacked next to each other. Also, do not pass in a const * for your string. Declaring a string as char*str = "test_string"; implies read-only memory on some systems. Use char str[] = "test_string"; instead. If you are not using strictly C, you can use C++ templates to make a function that works for int and char: http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1
#include <stdio.h>
#include<ctype.h>
#include<string.h>
int Run_count=-1;
int main ( int argc , char *argv[] )
{
/* if you dont want to use argv, put the elements in A yourself,
size being the number of string*/
/*L --> left side, R --> right side*/
int i = 0;
int size = argc-1;
char *A[argc-1];
for(i=1;i<=argc;i++){*(A+i-1) = argv[i];}
Caller(A,size);
for(i=0;i<size;i++){
printf("%s\n", A[i]);
}
printf("%d",Run_count);
}
int Caller(char* A[] , int n){
Run_count++;
int sizeL, sizeR ,i;
char *L[n/2+1] , *R[n-n/2+1];
if (n < 2){return 1;}
sizeL = n/2;
sizeR = n - sizeL;
for(i=0;i<sizeL;i++) {L[i] = *(A+i);}
for(i=0;i<n - n/2;i++) {R[i] = *(A+i+n/2);}
Caller( L, sizeL);
Caller( R, sizeR);
merger( L,sizeL, R,sizeR, A);
}
void merger(char* L[], int lengthL , char* R[] , int lengthR , char *A[]){
int i, j, k ,t =0 ;
for(k = 0 , j = 0; k < lengthL && j < lengthR ;t++){
if(compare(*(L+k),*(R+j))){
*(A+t) = *(L+k);
k++;}
else{*(A+t) = *(R+j);j++;}
}
while(k < lengthL ){
*(A+t) = *(L+k);
k++;t++;
}
while(j < lengthR ){
*(A+t) = *(R+j);
j++;t++;}
}
int compare(char *line1 , char *line2 )
{
int i;
for(i = 0;*(line1 + i) != '\0' && *(line2 + i) != '\0' ;){
if(isdigit(*(line1+i)) && isalpha(*(line2+i))){return 0;}
else if(isdigit(*(line2+i)) && isalpha(*(line1+i))){return 1;}
else if(*(line1 + i) > *(line2 + i)){return 0;}
else if(*(line1 + i) == *(line2 + i)){i++;}
else{return 1;}
}
}

C: reverse array in subrange

I am trying to implement left array rotation using the method described here: http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf (under section Reversal algorithm)
I am having trouble reversing the array when the start index isn't 0.
Here is what I have so far:
void reverse_arr(int *a, int start, int end)
{
int i;
int len = end - start;
//printf("Len pre loop: %d\n", len);
int swap;
for(i = start; i < --len; i++)
{
//printf("start: %d\tlen: %d\n", start, len);
swap = a[i];
a[i] = a[len];
a[len] = swap;
}
}
This works great when the start index is 0, but when it is anything else it never reverses all of the elements.
ex:
int test[] = {1,2,3,4,5,6};
reverse_arr(test, 0, 2); //reverse the first 2 elements of the array
results in: {2,1,3,4,5,6} which is expected
int test[] = {1,2,3,4,5,6};
reverse_arr(test, 2, 6); //reverse the last 4 elements of the array
results in: {2,1,4,3,5,6} which is not expected, only the 3 and 4 were reversed.
Any help would be appreciated.
You need to adjust the other subscript in the swap:
void reverse_arr(int *a, int start, int end)
{
int len = end - start;
for (int i = start; i < --len; i++)
{
int swap = a[i];
a[i] = a[i+len];
a[i+len] = swap;
}
}
You could probably also use:
void reverse_arr(int *a, int start, int end)
{
int len = end - start;
end--;
for (int i = start; i < --len; i++, end--)
{
int swap = a[i];
a[i] = a[end];
a[end] = swap;
}
}
Working test code
#if defined(VERSION1)
static void reverse_arr(int *a, int start, int end)
{
int i;
int len = end - start;
int swap;
for (i = start; i < --len; i++)
{
swap = a[i];
a[i] = a[i+len];
a[i+len] = swap;
}
}
#else
static void reverse_arr(int *a, int start, int end)
{
int i;
int len = end - start;
end--;
for (i = start; i < --len; i++, end--)
{
int swap = a[i];
a[i] = a[end];
a[end] = swap;
}
}
#endif
#define DIM(x) (sizeof(x)/sizeof(x[0]))
#include <stdio.h>
static void print_array(int *array, size_t size)
{
for (size_t i = 0; i < size; i++)
printf(" %d", array[i]);
putchar('\n');
}
static void tester(int lo, int hi)
{
int test[] = {1,2,3,4,5,6};
printf("Before: (%d, %d)\n", lo, hi);
print_array(test, DIM(test));
reverse_arr(test, lo, hi); //reverse the first 2 elements of the array
printf("After: (%d, %d)\n", lo, hi);
print_array(test, DIM(test));
putchar('\n');
}
int main(void)
{
tester(0, 2);
tester(2, 6);
return(0);
}
And the results from compiling with -DVERSION1 or not are the same:
Before: (0, 2)
1 2 3 4 5 6
After: (0, 2)
2 1 3 4 5 6
Before: (2, 6)
1 2 3 4 5 6
After: (2, 6)
1 2 6 4 5 3
You should drop len altogether, and use end instead. While you are at it, you can also drop i, and use start. Your code would become a lot more readable that way:
void reverse_arr(int *a, int start, int end)
{
int swap;
while(start < end)
{
swap = a[start];
a[start++] = a[--end];
a[end] = swap;
}
}
It's because you're comparing i against len which is fine if it starts at 0 but not if it starts at anything else (the base values are different).
For example if you want to rotate three characters starting at offset 12, nothing will happen since the for loop begins in a exit state.
A quick fix is to simply adjust a before beginning the loop so that it effectively thinks the (local value) a is the start of the array:
a += start;
for (i = start; i < --len; i++) // No change on this line.

Resources