Related
I'm trying to implement a binary search in a slightly non-traditional way by using only 3 arguments int value (what I'm looking for), int values[] (the array), int n (the size of the array). The code below finds the number 2 and recognizes that 13 is not there, but cannot find numbers like 6 or 7. I think the problem is in the final recursive call. It could be a pointer issue. I'm certain the rest of the code works fine. Any thoughts on where I might be going wrong would be appreciated.
#include <stdio.h>
#include <stdbool.h>
bool search(int value, int values[], int n);
int main(void)
{
int value = 6;
int values[] = {1, 2, 3, 4, 5, 6, 7};
int n = 7;
bool x = search(value, values, n);
if (x == true)
printf("found\n");
else
printf("not found\n");
}
bool search(int value, int values[], int n)
{
int midpoint = n/2;
if (n/2 <= 0)
{
return false;
}
if (value == values[midpoint])
{
return true;
}
if (value < values[midpoint])
{
return search(value, values, n/2);
}
else if (value > values[midpoint])
{
return search(value, values, n/2);
}
return false;
}
Yes, the problem is that when you call search with the upper half of the array, you should pass it with the offset like
return search(value, values + (n + 1) / 2, n / 2);
Note that I also skipped the middle element that you have already compared for the cases when n is odd. You can of course optimize the recursive calls, always taking care that also the length is calculated correctly.
I have been cracking my head at achieving something very simple in C in order to make my one of the programs (not written by me) in our computational physics project more dynamic:
comparing two different arrays element by element in an if conditional.
#include <math.h>
#include <stdio.h>
#include "header.h"
const int nParam = 10;
double a[nParam], a_tmp[nParam];
double values[10000];
double FitParam(double x){
int xindex;
double value;
xindex=(int) x;
if (a_tmp[1]==a[1] && a_tmp[2]==a[2] && a_tmp[3]==a[3] && a_tmp[4]==a[4]){
value=values[xindex];
return(value);
}
// code continues... (very long subroutine and there is recursion for
// the subroutine so this if statement above is very important).
The array a[ ] has a varying number of significant elements every time we run our program; for example, right now, we are using this subroutine for only elements [1] through [4]. However, in other cases, we will want to have fewer or more elements, say, up to 3 elements or up to 5 elements, respectively.
So essentially, I want to be able to rewrite the if statement above so that it is dynamic... in other words, if there are N elements considered, then it will do:
if (a_tmp[1]==a[1] && ... && a_tmp[N]==a[N]){}
So this if conditional should vary whenever our number N of elements of interest is changed (N is defined as a #define in the header of this file, which I just named header.h).
I would greatly appreciate your support on this task. Thank you.
Your best bet is to rewrite it as a function that returns true or false (1 or 0):
int compareArrays(double a[], double b[], int n) {
int ii;
for(ii = 1; ii <= n; ii++) {
if (a[ii] != b[ii]) return 0;
// better:
// if(fabs(a[ii]-b[ii]) < 1e-10 * (fabs(a[ii]) + fabs(b[ii]))) {
// with the appropriate tolerance
}
return 1;
}
Note that it is usually bad practice to compare doubles for equality - you are better off comparing their difference, and making sure the absolute value is less than some tolerance.
Also note you are comparing elements 1 through n - C arrays start at 0 though.
You would use the above with
if (compareArrays(a, a_tmp, N)) {
where the value N is #define'd per your question.
If you want to be "clever" and avoid a loop, you can write the following - it will stop ("short-circuiting") as soon as you reach the right number of comparisons. It is still a Bad Idea to compare doubles for equality but I will leave that for another time (see comment in code above for a solution).
if(a[1]==a_temp[1] && (2 > N || (a[2]==a_temp[2] && (3 > N || (a[3]==a_temp[3]))))) {
This makes the "and the rest" true as soon as you have compared the right number of terms - so it will stop evaluating terms (as you need). I am not convinced this is either faster, or better code - but it is "dynamic"... You can obviously make this expression as long as you would like; I just wrote the first three terms so you get the idea. I DO NOT RECOMMEND IT.
As for the comparison of doubles, you might consider replacing
if(a == b)
with
if(closeEnough(a, b))
where you define the macro
#define closeEnough(a, b) (fabs((a)-(b)) < 1e-10 * (fabs(a) + fabs(b)))? 1 : 0
This will make sure that your doubles don't have to be "exactly equal" - depending on how you arrived at them, they will almost never be, and the relative tolerance of 1 part in 10^10 is usually plenty for most practical comparisons.
If it must be at compile time, there is nothing in the standard that provides for a repeating macro like that. As in another (question), for bounded N, you can prepare N macros that expand to your desired comparison.
While yet another alternative is memcmp
memcmp( data, data2, array_len_in_bytes );
reference
An implementation might be to loop over all the elements and set a flag when a difference is detected
int i, N;
int is_equal = 1;
for (i=1; i<N; ++i) {
if (a[i] != a_tmp[i]) {
is_equal = 0;
break;
}
}
if (is_equal)
printf("Arrays are equal");
A simple implementation is a linear comparison between both arrays, it just iterate over the array length and check if (a[i] != b[i]), if so return false & break out of the iteration.
See the example below:
#include <stdio.h>
int compareArrays(int a[], int b[], int n)
{
for (int i=0; i<n; ++i)
{
if (a[i] != b[i])
{
return -1;
}
}
return 0;
}
int main()
{
int arr1[4] = {3, 4, 5, 7};
int arr2[4] = {3, 4, 5, 7};
int arr3[4] = {1, 5, 3, 7};
int arr4[4] = {3, 4, 5, 19};
printf("Should be True %d\n", compareArrays(arr1, arr2, 4));
printf("Should be False %d\n", compareArrays(arr3, arr4, 4));
return 0;
}
You should get:
Should be True 0
Should be False -1
Run it online this example: https://repl.it/#abranhe/compare-arrays-in-c
This one, lets you compare two arrays of any type and will return the index of the first unequal elements found. If the arrays are identical the returned value will be the number of elements in the array.
int compareArrays(void* arrayA, void* arrayB, uint numElements, uint elementSizeBytes) {
//returns -1 on error, numElememts if the arrays are equal or the index
//of the first unequal elements
uint i;
uint8_t* byteArrayA;
uint8_t* byteArrayB;
if(elementSizeBytes < 1) {
return -1;
}
if(numElements < 1) {
return -1;
}
byteArrayA = (uint8_t*) arrayA;
byteArrayB = (uint8_t*) arrayB;
for(i = 0; i < (numElements*elementSizeBytes); i++) {
if(byteArrayA[i] != byteArrayB[i]) {
break;
}
}
return i / elementSizeBytes;
}
An example call:
uint16_t test1[6] = {12, 15, 24, 86, 92, 15};
uint16_t test2[6] = {12, 15, 24, 86, 93, 15};
int retVal = compareArrays(test1, test2, 6, 2);
Today i came across same kind of problem statement,i googled for solution for an hour and end up with no solution,the above all approaches are not correct solutions for the stated problem
The Better way to resolve above Problem is
Sort the two arrays either in ascending or descending order, Then compare both the arrays.
#include<stdio.h>
void sort_it(int a[], int size)
{
int i,j,temp=0;
for(i=0;i<size;++i)
{
for(j=i+1;j<size;++j)
{
if(a[i]>a[j])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
};
int compare(int size,int a[],int b[])
{
int i,j,is_equal;
for(i=0;i<size;i++)
{
for(j=0;j<size;j++)`enter code here`
{
if(a[i]!=b[j])
{
is_equal=0;
}
else
is_equal=1;
}
}
return is_equal;
};
int main()
{
int size=4,i,is_equal;
int a[]={1,2,5,4};
int b[]={1,7,4,2};
sort_it(a,size);
sort_it(b,size);
is_equal=compare(4,a,b);
if(is_equal)
printf("arrays are equal\n");
else
printf("arrays are not equal\n");
return (0);
}
#include <stdio.h>
int bsearch(int a[], int n, int lo, int hi) {
int mid;
mid = (hi + lo) / 2;
if(a[mid] == n)
return 1;
else if(a[mid] > n)
bsearch(a, n, lo, mid);
else
bsearch(a, n, mid, hi);
return 0;
}
int main(void) {
int n, a[7] = {2, 4, 5, 67, 70, 80, 81};
int hi = 6, lo = 0, j;
scanf("%d", &n);
j = bsearch(a, n, lo, hi);
if(j)
printf("Found");
else
printf("Not Found");
return 0;
}
input : 5 output: Not Found
Can anyone tell me why I'm getting this result?
You need to fix several big issues to make it work (see details in following code comments).
Change your binary search function to the following:
int bsearch(int a[], int n, int lo, int hi)
{
// add base case
if (high < low)
return 0; // not found
int mid;
mid=(hi+lo)/2;
if(a[mid]==n)
return 1;
else if(a[mid]>n)
return bsearch(a,n,lo,mid-1); // add return
else
return bsearch(a,n,mid+1,hi); // add return
}
P.S.: And based on your usage in the main() body, you actually only need to return 0/1 to indicate contains the value or not. I will suggest you to use bool return type to make it more clear.
Add "return" to the recursive calls, e.g.:
return bsearch(a,n,lo,mid);
Otherwise, when you return 1 in bsearch, it does not get returned all the way to main.
That will make it work for 5. You have other bugs, so try with many values and use an IDE and/or printf to see what's happening. Good luck and have fun!
That's because the return 0; statement in your bsearch function is always executed because you are simply discarding the values returned by the recursive calls. In a recursive function, you must first decide the base case. Here in your bsearch, the base case should be
low <= hi
This is the first condition which must be true to start the search for the sought value. If this condition is not fulfilled, then you must return false, i.e., 0.
Next, a value returning function call is an expression, i.e., it evaluates to a value. When you simply call the function and do nothing with the result, you will always fall down to the last return statement in your function. Here I list some points in comments alongside the statements in your bsearch function.
int bsearch(int a[], int n, int lo, int hi) {
// first check for the base condition here
// if(hi < low) return 0;
int mid;
// can cause integer overflow. should be
// mid = lo + (hi - lo) / 2;
mid = (hi + lo) / 2;
if(a[mid] == n)
return 1;
else if(a[mid] > n)
// you are doing nothing with the value returned
// think of the function call as an expression
// return the value of the expression
// should be
// return besearch(a, n, lo, hi);
bsearch(a, n, lo, mid);
else
// same follows here
// should be
// return bsearch(a, n, mid, hi);
bsearch(a, n, mid, hi);
// finally you will always return 0 because this statement is always executed
// all cases have been taken care of.
// no return statement needed here
return 0;
}
Consider this code, which computes the maximum element of an array.
#include <stdio.h>
int maximum(int arr[], int n)
{
if (n == 1) {
return arr[0];
} else {
int max = maximum(arr, n-1);
printf("Largest element : %d\n", max);
return 5; // return arr[n-1] > max ? arr[n-1] : max;
}
}
int main()
{
int array[5] = {5, 23, 28, 7, 1};
printf("Maximum element of the array is: %d", maximum(array, 5));
return 0;
}
Why is the else block called four (4) times?
The function is recursive, thus it will be called multiple times.
When you first start, n=5. It will take the else block (n is not 1).
Then, you call maximum again with n-1 (n=4). Again, the else block is taken.
All told, the function is called 4 times before n reaches 1, whereupon it takes the if block and returns ar[0].
As others have mentioned, the function as written will not return the maximum value of the list. Curiously, it seems to always return 5 unless the list array size is 1, in which case it returns the value of that element.
Instead, a recursive approach would typically involve splitting the list in half each time, then returning the max of each pair when the list finally broken into pairs of elements.
That is what it is coded to do...
Take a look:
from main we call maximum with 5, then in the else we call the function again with n-1.
maximum(array, 5) //first call from main, hit the else n=5, so recall with n-1
maximum(ar, 4) //second call from maximum, hit the else n=4, so recall with n-1
maximum(ar, 3) //third call from maximum, hit the else n=3, so recall with n-1
maximum(ar, 2) //fourth call from maximum, hit the else n=2, so recall with n-1
maximum(ar, 1) //fifth call from maximum, n==1 now so do the if and return 5
A possible recursive solution is to compare the previous and the current element.
#include <stddef.h>
static int max(int a, int b) {
return a > b ? a : b;
}
int max_array(int *p, size_t size)
{
if (size > 1) return max(p[size-1], max_array(p, size-1));
else return *p;
}
Actually it is called only 4 times.
The recursion rule, as you declared it is:
if n==1, return ar[0] else return the maximum of n-1 elements.
So, the else part is being called for 5, 4, 3 and 2.
However, this recursion is not good enough. As your function is called n-1 times, you only pay the overhead of recursion (stack for example) but you get no advantage over iteration.
If you really want recursion for this task, try to divide the array to 2 and pass each half to the recursive function.
simple pseudo code (not handling odd numbers correctly):
int max(int arr[], int n)
{
if (n<=1)
return arr[0];
return MAX(max(arr, n/2), max(arr+n/2, n/2));
}
int maximum(int ar[], int n)
{
int max;
if(!n)
return ar[n];
max =maximum(ar,n-1);
return ar[n]>max?ar[n]:max;
}
I'm trying to make a divide and conquer version of binary search, but one that divides the array to two subarrays and search similar to merging in merge sort, the reason I want to do that becuase I want to use it in cilk, but I have to make it that way.
Here is the code I wrote, which seems to have something wrong with it as its returning -1 to valid key values.
#include <stdio.h>
#include "BinarySearch.h"
int main () {
int a[] = {0,1,2,3,4,5,6,7,8,9};
int index = binarySearch(a, 0, 9, 7);
printf("%i", index);
return 0;
}
int binarySearch (int* A, int first, int last, int key) {
if (last < first)
return -1;
else {
int mid = (last + first) / 2;
if (A[mid] == key)
return mid;
int x, y;
x = binarySearch(A, first, mid - 1, key);
y = binarySearch(A, mid + 1, last, key);
if (x == -1 && y == -1)
return -1;
else if (x == -1 && y != -1)
return y;
else
return x;
}
}
It's simple, 99 doesn't exist in your array. The result is correct. You probably just messed up the parameters - the first one is the array, the next two represent the range of the search, the fourth one is what you're looking for. A correct call would be:
int index = binarySearch(A, 0, 10, 4);
Also, this
int* A = &a[0];
is useless, you can simply use a as arrays decay to pointers:
int index = binarySearch(a, 0, 7, 99); // a instead of A
Also - a binary search takes into account the fact that the array is sorted. If your key is lower than the middle value, why bother searching to the right - it's guaranteed you won't find it there.
What you're doing is O(n), as opposed to a O(log(n)) binary search solution.
For any one still looking for solutions, I found this made by ankzcode.
It finds the minimum value in an array without linear search, using divide and conquer.
#include <stdio.h>
int findMin(int a[], int l,int h)
{
int pivot = (l + h) / 2;
int minl=-1, minh = -1;
if ( (pivot - l ) > 1)
{
minl = findMin(a, l, pivot);
}
else
{
minl = (a[l] > a[pivot])?a[pivot]:a[l];
}
if ( (h - pivot ) > 1)
{
minh = findMin(a, pivot, h);
}
else
{
minh = (a[l] > a[pivot])?a[pivot]:a[l];
}
return (minl>minh)?minh:minl;
}
int main()
{
int a[]={5,2,9,10,3};
printf("%d\n",findMin(a, 0, 5));
return 0;
}
you gave the key 99,which is not in array,So its obvious the code return -1.