I'm trying to run this implementation of binary search. I don't know why but it keeps giving me segfault error. I'm thinking the problem might be either the way I'm passing the array or there's something wrong with the recursive calls.
#include <stdio.h>
int hasBinarySearch(int *array, int low, int high, int element)
{
int mid = (low + (high-low)) / 2;
if (high>=low)
{
if (array[mid] == element)
{
return mid;
}
else if(array[mid]<element)
{
return hasBinarySearch(array, low, mid-1, element);
}
else
{
return hasBinarySearch(array, mid+1, high, element);
}
}
return 0;
}
int main(void)
{
int array[10] = {1,2,3,4,5,6,6,6,7,8};
hasBinarySearch(array, 0, 9, 2);
return 0;
}
I think that you have some misunderstanding about binary search. Read some article or book about it.
As #Claies commented, calculation of middle index is wrong.
It should be low + (high - low) / 2. Just think about the internal division of two points in mathematics.
Also, you have to fix the parameters on recursive calls like the code below.
#include <stdio.h>
int hasBinarySearch(int *array, int low, int high, int element)
{
int mid = low + (high - low) / 2; // changed
printf("%d %d\n", high, low);
if (high >= low)
{
if (array[mid] == element)
{
return mid;
}
else if (array[mid] < element)
{
return hasBinarySearch(array, mid + 1, high, element); // changed
}
else
{
return hasBinarySearch(array, low, mid - 1, element); // changed
}
}
return 0;
}
int main(void)
{
int array[10] = { 1,2,3,4,5,6,6,6,7,8 };
hasBinarySearch(array, 0, 9, 2);
return 0;
}
int mid = (low + (high-low)) / 2; // wrong formula
#paganinist good answer points out the flaws in OP's search method and with a fix.
Yet to dig deeper.
Even though some compilers might be able to "un-recurse" code (Example), recursion is not needed here. A simple loop will suffice.
Array sizes can approach near maximum or exceed the range of int in extreme cases.
For sizes in the high int range, the following is better. #Jonathan Leffler
// int mid = (low + high)/2; // could overflow
int mid = low + (high-low)/2; // better, will not overflow when low >= 0
To accommodate all array sizes, use size_t instead on int. This also handles sizes including those near and above INT_MAX.
Candidate solution that returns the address of the matching element or NULL if not found.
#include <stdlib.h>
#include <stdio.h>
int *BinarySearch_int(const int *array, size_t count, int key) {
while (count > 0) {
size_t mid = count / 2;
if (key > array[mid]) {
array += mid + 1;
count -= mid + 1;
} else if (key < array[mid]) {
count = mid;
} else {
return (int *) &array[mid];
}
}
return NULL;
}
Test code
bool BinarySearch_int_test(const int *array, size_t count, int key, bool target){
int *p = BinarySearch_int(array, count, key);
bool success = (p != NULL) == target && (p == NULL || *p == key);
printf("f(Array:%p count:%zu, key:%2d) --> ptr:%p value:%2d success:%d\n",
(void*) array, count, key, (void*) p, p ? *p : 0, success);
return success;
}
int main(void) {
int array[] = {10, 20, 30, 40, 50, 60};
size_t n = sizeof array / sizeof array[0];
for (size_t i = 0; i < n; i++) {
BinarySearch_int_test(array, n, array[i], 1);
}
BinarySearch_int_test(array, n, 0, 0);
for (size_t i = 0; i < n; i++) {
BinarySearch_int_test(array, n, array[i] + 1, 0);
}
}
Output
f(Array:0xffffcb90 count:6, key:10) --> ptr:0xffffcb90 value:10 success:1
...
f(Array:0xffffcb90 count:6, key:60) --> ptr:0xffffcba4 value:60 success:1
f(Array:0xffffcb90 count:6, key: 0) --> ptr:0x0 value: 0 success:1
...
f(Array:0xffffcb90 count:6, key:61) --> ptr:0x0 value: 0 success:1
mid's calculation simplifies to high / 2 because you've added and then subtracted the lower bound out again. It looks like you meant to add half the difference to the lower bound, but the division occurs too late. It should be low + (high-low) / 2. (This is a bit more complicated than (low + high) / 2 but avoids the integer-math problem mentioned elsewhere.)
I think that segfault is happening when high goes below low and gets too small and you fall off the beginning of the array.
And #paganinist is right about the upper and lower cases being backwards.
Related
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;
}
I have implemented a beginner recursive version of binary search in C. However, it doesn't seem to work when the element to be found is in the last position of the array. Is there any way to fix this without changing the prototype of the function?
#include <stdio.h>
int search(int value, int values[], int n);
int main() {
int a[] = { 26, 27, 28 };
if (search(28, a, 3) == 0)
printf("Found.\n");
else
printf("Not found.\n");
}
int search(int value, int values[], int n)
{
if (n <= 0)
return 1;
if (value < values[n/2])
// Search the left half
return search(value, values, n/2);
else if (value > values[n/2])
// Search the right half, excluding the middle term
return search(value, values + n/2 + 1, n/2 - 1);
else
return 0;
return 1;
}
Your search function is incorrect:
The slice size you pass when you recurse on the right part is computed incorrectly: it should be n - n/2 - 1 instead of n/2 - 1.
Here is a corrected version:
#include <stdio.h>
int search(int value, int values[], int n);
int main(void) {
int a[] = { 26, 27, 28 };
if (search(28, a, 3) == 0)
printf("Found.\n");
else
printf("Not found.\n");
return 0;
}
int search(int value, int values[], int n) {
if (n > 0) {
int mid = n / 2;
if (value < values[mid]) {
// Search the left half
return search(value, values, mid);
} else
if (value > values[mid]) {
// Search the right half, excluding the middle term
return search(value, values + mid + 1, n - mid - 1);
} else {
// Found the value
return 0;
}
}
return 1;
}
Here is a simpler iterative version:
int search(int value, int values[], int n) {
while (n > 0) {
int mid = n / 2;
if (value < values[mid]) {
// Search the left half
n = mid;
} else
if (value > values[mid]) {
// Search the right half, excluding the middle term
values += mid + 1;
n -= mid + 1;
} else {
// Found the value
return 0;
}
}
return 1;
}
It seems to be your return statement in your else if clause. The length of the array n should be n-n/2-1 and not n/2-1 or else the last element will be clipped off. You can see this to be more prevalent as the length of the array increases and as you're searching for elements coming from the right side.
return search(value, values + n/2 + 1, n - n/2 - 1);
Note:
As chqrlie pointed out
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);
}
About the question how to convert a string to palindrome with minimum number of removals of characters of the string? . I write the program to test the answer accepted. But recursion takes too much time. How can this problem be solved or improved?Below is the answer accepted:
Let dp[i, j] = minimum number of removals needed to convert the substring [i, j] to a palindrome. We have:
dp[i, i] = 0 for all i (every single character is a palindrome)
To
find dp[i, j], let's consider a random string. We have two
possibilities:
The first and last characters are equal: a[i] == a[j]. In this case,
we can reduce the problem to finding the minimum number of characters
that need to be deleted in order to make the substring [i+1, j-1] a
palindrome.
The first and last characters are not equal: a[i] != a[j].
In this case, we need to remove one of them. We'll remove that which
leads us to a better solution.
/* remvoe the least characters to make a string be palindrome */
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
int func(char *p, int low, int high);
int min(int m, int n); // get the minimal value
int main(void)
{
char str[MAXLINE];
int ret;
while (scanf("%s", str) != EOF) { // input in a loop
ret = func(str, 0, strlen(str) - 1); // call func
printf("%d\n", ret);
}
return 0;
}
/* find the minimal number of characters in a string,
* which are needed removed to make the string be palindrome
*/
int func(char *p, int low, int high)
{
int n;
int l;
int r;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
}
else {
l = func(p, low + 1, high);
r = func(p, low, high - 1);
n = min(l, r) + 1;
}
return n;
}
/* return the minimal variable */
int min(int m, int n)
{
return (m < n ? m : n);
}
A key improvement is to recognize that when only one side of the string is eliminated, the other side must have a match (with a character on the other side, even if it is itself), else why not eliminate both sides?
When a character from one side is removed, seek from that side toward the other for a match of the other side's character. (A match is always be found.) This eliminates many unnecessary recursion paths.
A secondary improvement "short-circuits" as below. No need to test other combinations as they cannot improve the result.
if (left == 1) return 1;
int func(const char *p, int low, int high) {
int n;
int left;
int right;
count++;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
} else {
#if 0
left = func(p, low + 1, high);
// if (left == 0) return 1;
right = func(p, low, high - 1);
n = min(left, right) + 1;
#else
int delta;
// remove low, keep high as part of palindrome
delta = 1;
while (p[low + delta] != p[high])
delta++;
left = func(p, low + delta, high) + delta;
if (left == 1) return 1;
// remove high, keep low as part of palindrome
delta = 1;
while (p[low] != p[high - delta])
delta++;
right = func(p, low, high - delta) + delta;
if (right <= 2) return right;
n = min(left, right);
// remove first and last
//int both = func(p, low + 1, high-1) + 1 + (high > (low + 1));
int both = func(p, low + 1, high - 1) + 2;
n = min(n, both);
#endif
}
return n;
}
Mouse over for final result of OP's test string (Hidden in case OP does not want to see it right away.)
count = 13090 ret = 45 str = 'jfdasflkjddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj'
A minor improvement uses const. Some compliers will generate more efficient code knowing the buffer is unchanging. Better compilers may detect this anyways.
// int func(char *p, int low, int high)
int func(const char *p, int low, int high)
Some test driver code
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
unsigned long long count = 0;
int func(const char *p, int low, int high);
int min(int m, int n); // get the minimal value
void testfunc(const char *str) {
count = 0;
int ret = func(str, 0, (int) strlen(str) - 1); // call func
printf(" count = %llu", count);
printf(" ret = %d", ret);
printf(" str = '%s' ++", str);
puts("");
fflush(stdout);
}
int main(void) {
char str[MAXLINE];
int ret;
char t[] =
"jfdasflkjdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"ddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
for (size_t i = 0; t[i]; i++) {
strncpy(str, t, i);
str[i] = 0;
testfunc(str);
}
return 0;
}
int min(int m, int n) {
return (m < n ? m : n);
}
int func(const char *p, int low, int high) {
...
you shouldn't call it recursively, because that leads to multiple execution of the same check (some range will be checked many times, when in reality only one check is required). Instead u should use a "dynamic programming" method, build from bottom to top. What that means is u need to create a two-dimensional array, dp[i][j], i<j, which stores the length of a maximum palindrome in range i to j. So if j=i+k first u proceed to build for k=0, then for k=1 and so on.
Based on the following definition found here
Returns an iterator pointing to the
first element in the sorted range
[first,last) which does not compare
less than value. The comparison is
done using either operator< for the
first version, or comp for the second.
What would be the C equivalent implementation of lower_bound(). I understand that it would be a modification of binary search, but can't seem to quite pinpoint to exact implementation.
int lower_bound(int a[], int lowIndex, int upperIndex, int e);
Sample Case:
int a[]= {2,2, 2, 7 };
lower_bound(a, 0, 1,2) would return 0 --> upperIndex is one beyond the last inclusive index as is the case with C++ signature.
lower_bound(a, 0, 2,1) would return 0.
lower_bound(a, 0, 3,6) would return 3;
lower_bound(a, 0, 4,6) would return 3;
My attempted code is given below:
int low_bound(int low, int high, int e)
{
if ( low < 0) return 0;
if (low>=high )
{
if ( e <= a[low] ) return low;
return low+1;
}
int mid=(low+high)/2;
if ( e> a[mid])
return low_bound(mid+1,high,e);
return low_bound(low,mid,e);
}
Here are the equivalent implementations of upper_bound and lower_bound. This algorithm is O(log(n)) in the worst case, unlike the accepted answer which gets to O(n) in the worst case.
Note that here high index is set to n instead of n - 1. These functions can return an index which is one beyond the bounds of the array. I.e., it will return the size of the array if the search key is not found and it is greater than all the array elements.
int bs_upper_bound(int a[], int n, int x) {
int l = 0;
int h = n; // Not n - 1
while (l < h) {
int mid = l + (h - l) / 2;
if (x >= a[mid]) {
l = mid + 1;
} else {
h = mid;
}
}
return l;
}
int bs_lower_bound(int a[], int n, int x) {
int l = 0;
int h = n; // Not n - 1
while (l < h) {
int mid = l + (h - l) / 2;
if (x <= a[mid]) {
h = mid;
} else {
l = mid + 1;
}
}
return l;
}
The actual C++ implementation works for all containers. You can find it here.
lower_bound is almost like doing a usual binary search, except:
If the element isn't found, you return your current place in the search, rather than returning some null value.
If the element is found, you search leftward until you find a non-matching element. Then you return a pointer/iterator to the first matching element.
Yes, it's really that simple. :-)
I know that this is a very old post. However, I was working on a problem and I came across this post. I would like to add my iterative version for the problem which is an extension of the last answer. I checked this with the test cases I could think of. I've attached my code in C#.
This code was working for all ranges. However, the range should be within the first index to the last index+1. If the array is of size N and considering range as [0,N] the search space will be within [0,N). I know that's pretty obvious but it helped me checking some edge cases.
static int lower_bound(int[] a, int lo,int hi, int x)
{
while (lo < hi)
{
int mid = lo + (hi-lo) / 2;
if(a[mid]==x)
{
/*when there is a match, we should keep on searching
for the next same element. If the same element is not
found, mid is considered as the answer and added to 'hi'
Finally 'hi' is returned*/
if(a[mid-1]!=x)
{
hi=mid;
break;
}
else
hi=mid-1;
}
else if(a[mid]>x)
hi=mid-1;
else
lo=mid+1;
}
//if element is not found, -1 will be returned
if(a[hi]!=x)
return -1;
return hi;
}
static int upper_bound(int[] a, int lo,int hi, int x)
{
int temp=hi;
while (lo < hi)
{
int mid = lo + (hi-lo) / 2;
if(a[mid]==x)
{
/*this section make sure that program runs within
range [start,end)*/
if(mid+1==hi)
{
lo=mid;
break;
}
/*when there is a match, we should keep on searching
for the next same element. If the same element is not
found, mid is considered as the answer and added to
'lo'. Finally 'lo' is returned*/
if(a[mid+1]!=x)
{
lo=mid;
break;
}
else
lo=mid+1;
}
else if(a[mid]>x)
hi=mid-1;
else
lo=mid+1;
}
//if element is not found, -1 will be returned
if(a[lo]!=x)
return -1;
return lo;
}
Here is a test case that I used:
Array(a) : 1 2 2 2 2 5 5 5 5
size of the array(a) : 9
Considering search element as 2:
upper_bound(a,0,9,2)=4, lower_bound(a,0,9,2)=1
Considering search element as 5:
upper_bound(a,0,9,2)=8, lower_bound(a,0,9,2)=5
Considering search element as 1:
upper_bound(a,0,9,2)=0, lower_bound(a,0,9,2)=0
Considering search element as 5:
upper_bound(a,5,9,2)=8, lower_bound(a,5,9,2)=5
The lower_bound and upper_bound functions in python would be implemented as follows:
def binLowerBound(a, lo, hi, x):
if (lo > hi):
return hi
mid = (lo + hi) / 2;
if (a[mid] == x):
return binLowerBound(a, lo, mid-1, x)
elif (a[mid] > x):
return binLowerBound(a, lo, mid-1, x)
else:
return binLowerBound(a, mid+1, hi, x)
def binHigherBound(a, lo, hi, x):
if (lo > hi):
return lo
mid = (lo + hi) / 2;
if (a[mid] == x):
return binHigherBound(a, mid+1, hi, x)
elif (a[mid] > x):
return binHigherBound(a, lo, mid-1, x)
else:
return binHigherBound(a, mid+1, hi, x)
C++ Implementation
int binary_search_lower_bound(vector<int>& array, int target) {
int lo = 0, hi = (int)array.size();
int mid;
while(lo < hi) {
mid = lo + ((hi - lo) >> 1);
int val = array[mid];
if (target <= val)//array[mid])
hi = mid;
else
lo = mid + 1;
}
return lo;
}
Edit: Fixed bug for non-existing value.
int lowerBound (int *a, int size, int val) {
int lo = 0, hi = size - 1;
while (lo < hi) {
int mid = lo + (hi - lo)/2;
if (a[mid] < val)
lo = mid + 1;
else
hi = mid;
}
return lo;
}
Example if this is the given array
1 2 3 3 4
and different values of x is
3 then firstOccurance will be 2 and lastOccurance will be 3
2 then firstOccurance will be 1 and lastOccurance will be 1
10 then firstOccurance will be -1 and lastOccurance will be -1
int firstOccurance(vector<int>& arr, int x){
int low = 0;
int high = arr.size();
int ans=-1;
while(low<=high){
int mid = (low+high)/2;
if(arr[mid]==x) ans=mid;
if(arr[mid]>=x) high=mid-1;
else low = mid+1;
}
return ans;
}
int lastOccurance(vector<int>& arr, int x){
int low = 0;
int high = arr.size();
int ans=-1;
while(low<=high){
int mid = (low+high)/2;
if(arr[mid]==x) ans=mid;
if(arr[mid]<=x) low=mid+1;
else high = mid-1;
}
return ans;
}
I know this is a very old post with a lot of answers already but I came across this problem as well and needed a generic solution so I used manish_s answer to adapt the gnu stdlib bsearch function. In case anyone needs it:
size_t myBsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
__compar_fn_t __compar)
{
size_t __l, __u, __idx;
const void *__p;
int __comparison;
__l = 0;
__u = __nmemb;
while (__l < __u)
{
__idx = (__l + __u) / 2;
__p = (void *)(((const char *)__base) + (__idx * __size));
__comparison = (*__compar)(__key, __p);
if (__comparison <= 0)
__u = __idx;
else if (__comparison > 0)
__l = __idx + 1;
}
return __l;
}