Hey im trying to refresh my mind with a bit of recursion.
I want to add all numbers from 'start' to 'end' inclusive.
I.e if start was 1, and end was 5. Then the answer would be 1+2+3+4+5 = 15
So far I've got this
int calc(int start, int end){
if(start > end)
return total;
else{
total = total + start;
return sum1(start++, end);
}
}
Its not working (i get seg fault). What am i doing wrong?
EDIT: Sorry i am using the same variables in my actual code, when i wrote this i ended up reffering to them as start/end and forgot to change all the code.
What are from and to variables inside your function? Maybe you use some globals instead of using start and end and that's why you have the problem? Also why are you using sum1 inside the calc function instead of calc?
Try this instead:
int calc(int start, int end){
if(start > end)
return 0;
else
return start + calc(start + 1, end);
}
For starters, you aren't using your function parameters (start, end), you are using (from, to) instead. I assume from and to are either global variables or your code wouldn't compile. Furthermore, where is total declared?
This should work better:
int calc(int start, int end){
if(start > end)
return 0;
else{
return start + calc(start+1, end);
}
}
By the way, here's a more efficient solution:
int calc(int from, int to)
{
if (from == 0)
return to * (to+1) / 2;
else
return calc(0, to) - calc(0, from);
}
It's even recursive! Well, until you simplify it further to
int calc(int from, int to)
{
return ( to * (to+1) - from * (from+1) ) / 2;
}
That's because f(n) = n+...+3+2+1 = n(n+1)/2
This works fine for.
int calc(int from, int to)
{
if (from >= to) return to;
return from + calc(from + 1, to);
}
Related
This is my binary search function. I can't seem to find the error but every time I try to run the code it gives me a segmentation fault 11. I feel like my mistake has to do with my last else if statement.
void binary(struct list *A[], char search[15], int start, int
end) {
if(start <= end) {
int middle = (start + end)/2;
if(strcmp(search, A[middle]->name) == 0){
printf("found");
exit(0);
} else if (strcmp(search, A[middle]->name) > 0){
int start = middle + 1;
int end = end;
binary(A, search, start, end);
} else if (strcmp(search, A[middle]->name) < 0){
int start = start;
int end = middle - 1;
binary(A, search, start, end);
} else if (start == (end - 1)) {
printf("%s was not found in the list", search);
exit(0);
}
}
}
These statements
int end = end;
int start = start;
do not make sense because the variables are initialized by themselves while they have indeterminate values.
There is no need to declare local variables end and start. Use the parameters.
This statement
} else if (start == (end - 1)) {
printf("%s was not found in the list", search);
exit(0);
}
also does not make sense because initially the variables start and end satisfy the condition of enclosing if statement
if(start <= end) {
And at last it does not make sense to use standard function exit instead of the return statement..
First, as others already pointed out, the assignment like int end = end is asking for troubles. Do a simple test and print the start and end values at the beginning of the function to see what happens as your program works...
Next, you do not need recursion here! Shrinking the search area can be easily done in a simple loop:
void binary(struct list *A[], char search[15], int start, int end) {
while(start <= end) {
int middle = start + (end - start)/2;
int cmpresult = strcmp(search, A[middle]->name);
if (cmpresult > 0) {
start = middle + 1;
} else if (cmpresult < 0) {
end = middle - 1;
} else { // cmpresult == 0
printf("found at %d", middle);
return;
}
}
printf("%s was not found in the list", search);
}
Finally, please note the middle calculation – adding (start + end) is a common step to do that, however it may lead to error if the array is too long; specifically, if the array length exceeds a half of the maximum value representable by int type.
I am trying to get this divide and conquer to work, but the compiler is giving me:
control may reach end of non-void function
I have read through similar scenarios, and understand the error implies the program might run forever without a return. I have reviewed some scenarios, which were resolved by using "else" instead of "if else" (as you should to begin with). However, that didn't help.
I am aware that using a do while loop and return in this scenario is redundant, I was fiddling with it in hopes to trick the compiler.
Where is the error?
bool search(int value, int values[], int n)
{
int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2;
do
{
//mid is value
if (value == values[mid])
{
printf("value found!");
sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max - mid) / 2 ;
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max - mid) / 2;
}
// DNE
else
{
printf("value not found");
sorted = 1;
return 0;
}
}
while(sorted == 0);
}
Every branch of code should have a return if function suppose to return a value.
In your case after while you have to put a return. How ever, Your logic is also slightly wrong. In your code there is not any need of sorted variable and the terminating condition is also wrong as well as the way of calculating mid is also wrong. Don't worry here is your updated code:
bool search(int value, int values[], int n)
{
//int sorted = 0;
int min = 0;
int max = n;
int mid = n / 2; // S1
do
{
//mid=(max+min)/2; // S2
//mid is value
if (value == values[mid])
{
//printf("value found!");
//sorted = 1;
return 1;
}
//search right
else if (values[mid] < value)
{
min = mid + 1;
mid = (max + min) / 2 ; // S3
}
//search left
else if (values[mid] > value)
{
max = mid - 1;
mid = (max + min) / 2; //S4
}
// DNE
else
{
//printf("value not found");
//sorted = 1;
return 0;
}
}
while(min!=max);
return 0;
}
So if your function is returning 1 it mean value found otherwise value doesn't found.
you also can comment S1, S3 and S4 and uncomment S2 for minimum line of code.
And the way of finding mid will be mid=(max+min)/2.
Ignoring other problems in your code (the loop will never terminate under certain conditions although I didn't study it too closely), let's just look at why the compiler complains, because it's quite interesting.
Your compiler complains about that you don't have a return at the end of the function (pretty much what we can read from the warning message) after the while loop. You loop runs:
while(sorted == 0);
And everywhere you change sorted, you do this:
sorted = 1;
return X;
So it is pretty obvious to you and me that the while condition will always be true and you won't fall out of the while loop and need a return after it. Every time you make the while condition not true, you also return immediately. But the compiler doesn't know that. It probably could figure it out with a little bit more effort, but it can never be written to know in all cases and you wouldn't accept a compiler that slow anyway. The problem of fully analyzing any arbitrary bit of code to know what you and I know (that we'll never fall out of the loop) is pretty much the halting problem (if you don't know what it is, you should, google it).
In situations like this we need to work with the compiler and help it understand. I would add a return sorted; at the end of the function, change the loop condition to while (1) and replace sorted = 1; return X; with sorted = X; break; to break out of the loop and have the function return from just one place (it is much easier to read functions that have just one or very few return statements). Or just remove the sorted variable, do the returns properly and loop forever.
I think your compiler doesn't like your understanding of Control Flow. As a beginner this is one of the most cringing problems.
Your error explained: Control may reach end of non-void function. Whenever you branch your code (i.e. use loops, if, switch etc) you have to explicitly write what each branch will do. So in your code, you must return a bool by any means necessary.
I am unable to discern where the error might be, it would be great if someone can show me.
See we have two return x; statements, one in if block and second in else block. Now we think that control should return from either of these blocks conveniently. But your compiler is "concerned" about what will happen if control didn't enter either of these blocks and loop ends. Moreover, what will happen after the loop, how can control ever return to main? Hence the error.
Now what we can do to fix the problem is add a return 0; just before the end of the function. That will surely make the error disappear. However, there are better ways to solve this problem:
bool search(int value, int values[], int n) {
int min = 0, max = n;
int mid = n / 2;
bool is_found = 0;
while (min != max) {
if (value == values[mid]) {
is_found = 1;
break;
}
else if (value > values[mid]) {
min = mid + 1;
mid = (max + min) / 2;
}
else if (value < values[mid]) {
max = mid - 1;
mid = (max + min) / 2;
}
else break;
}
return is_found;
}
I found code for a heapsort from: http://rosettacode.org/wiki/Sorting_algorithms/Heapsort#C
The way I understand it (which is wrong somewhere along the lines) is that the heapsort() function has two loops. The first loop is to create the heap structure (either min or max) and the second loop is to actually sort the doubles. But I think I have the first loop wrong.
The entire code goes like this
#include <stdio.h>
#include <stdlib.h>
#define ValType double
#define IS_LESS(v1, v2) (v1 < v2)
void siftDown( ValType *a, int start, int count);
#define SWAP(r,s) do{ValType t=r; r=s; s=t; } while(0)
void heapsort( ValType *a, int count)
{
int start, end;
/* heapify */
for (start = (count-2)/2; start >=0; start--) {
siftDown( a, start, count);
}
for (end=count-1; end > 0; end--) {
SWAP(a[end],a[0]);
siftDown(a, 0, end);
}
}
void siftDown( ValType *a, int start, int end)
{
int root = start;
while ( root*2+1 < end ) {
int child = 2*root + 1;
if ((child + 1 < end) && IS_LESS(a[child],a[child+1])) {
child += 1;
}
if (IS_LESS(a[root], a[child])) {
SWAP( a[child], a[root] );
root = child;
}
else
return;
}
}
int main()
{
int ix;
double valsToSort[] = {
1.4, 50.2, 5.11, -1.55, 301.521, 0.3301, 40.17,
-18.0, 88.1, 30.44, -37.2, 3012.0, 49.2};
#define VSIZE (sizeof(valsToSort)/sizeof(valsToSort[0]))
heapsort(valsToSort, VSIZE);
printf("{");
for (ix=0; ix<VSIZE; ix++) printf(" %.3f ", valsToSort[ix]);
printf("}\n");
return 0;
}
My question is, why does the /heapify/ loop start at (count-2)/2?
the snippet from heapsort() here:
/* heapify */
for (start = (count-2)/2; start >=0; start--) {
siftDown( a, start, count);
}
UPDATE
I think I may have just answered my own question, but is it because we have to establish a heap structure, where the loop's partial focus is on creating a balanced tree? That is, heaps have to have every level filled except for the last one. Is this correct thinking?
For odd count, the first child pair for heapify is a[((count-2)/2)*2 + 1] and a[((count-2)/2)*2 + 2], the last two elements of the array. For even count, the solo child is at a[((count-2)/2)*2 + 1], the last element of the array. This is the starting point to heapify the entire array. The second loop only has to re-heapify a mostly heapfied array[0 to end] as end decreses.
Wiki article:
http://en.wikipedia.org/wiki/Heapsort
So I'm trying to write a binary search function that uses recursion and keep getting a segmentation fault if I go past two values in the array. I've looked at a bunch of other code doing what I'm trying to do and as far as I can see they appear to do the same thing. I'm a very novice programmer and feel like I'm banging my head against the wall with this. Any help would be appreciated.
int search(int value, int array[], int start, int end)
{
//Define new variables for use in recursion
int sizeArray, middleOfArray;
//Get size of array
sizeArray = (end - start) + 1;
//Find midpoint of array based off size
middleOfArray = sizeArray / 2;
//Base Case 1, if array unscannable, return -1
if (start > end) {
return -1;
}
//Recursive Cases
else
{
//If midpoint in array is > target value,
//Search from beginning of array->one below midpoint
if (array[middleOfArray] > value){
return search(value, array, start, middleOfArray - 1);
}
//If midpoint in array is < target value,
//search from one above midpoint->end of array
else if (array[middleOfArray] < value) {
return search(value, array, middleOfArray + 1, end);
}
//If none of the other cases are satisfied, value=midpoint
//Return midpoint
else {
return middleOfArray;
}
}
}
The problem is here:
middleOfArray = sizeArray / 2;
It should be like this:
middleOfArray = start + sizeArray / 2;
You can also get middle of array like this. Which will save you from one extra variable sizeofArray.
middleofArray=(start+end)/2;
The code should take an array of coordinates from the user, then sort that array, putting the coordinates in order of their distance from the origin. I believe my problem lies in the sorting function (I have used a quicksort).
I am trying to write the function myself to get a better understanding of it, which is why I'm not using qsort().
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_SIZE 64
typedef struct
{
double x, y;
}POINT;
double distance(POINT p1, POINT p2);
void sortpoints(double distances[MAX_SIZE], int firstindex, int lastindex, POINT data[MAX_SIZE]);
void printpoints(POINT data[], int n_points);
int main()
{
int n_points, i;
POINT data[MAX_SIZE], origin = { 0, 0 };
double distances[MAX_SIZE];
printf("How many values would you like to enter?\n");
scanf("%d", &n_points);
printf("enter your coordinates\n");
for (i = 0; i < n_points; i++)
{
scanf("%lf %lf", &data[i].x, &data[i].y);
distances[i] = distance(data[i], origin); //data and distances is linked by their index number in both arrays
}
sortpoints(distances, 0, i, data);
return 0;
}
double distance(POINT p1, POINT p2)
{
return sqrt(pow((p1.x - p2.x), 2) + pow((p1.y - p2.y), 2));
}
void printpoints(POINT *data, int n_points)
{
int i;
printf("Sorted points (according to distance from the origin):\n");
for (i = 0; i < n_points; i++)
{
printf("%.2lf %.2lf\n", data[i].x, data[i].y);
}
}
//quicksort
void sortpoints(double distances[MAX_SIZE], int firstindex, int lastindex, POINT data[MAX_SIZE])
{
int indexleft = firstindex;
int indexright = lastindex;
int indexpivot = (int)((lastindex + 1) / 2);
int n_points = lastindex + 1;
double left = distances[indexleft];
double right = distances[indexright];
double pivot = distances[indexpivot];
POINT temp;
if (firstindex < lastindex) //this will halt the recursion of the sorting function once all the arrays are 1-size
{
while (indexleft < indexpivot || indexright > indexpivot) //this will stop the sorting once both selectors reach the pivot position
{
//reset the values of left and right for the iterations of this loop
left = distances[indexleft];
right = distances[indexright];
while (left < pivot)
{
indexleft++;
left = distances[indexleft];
}
while (right > pivot)
{
indexright--;
right = distances[indexright];
}
distances[indexright] = left;
distances[indexleft] = right;
temp = data[indexleft];
data[indexleft] = data[indexright];
data[indexright] = temp;
}
//recursive sorting to sort the sublists
sortpoints(distances, firstindex, indexpivot - 1, data);
sortpoints(distances, indexpivot + 1, lastindex, data);
}
printpoints(data, n_points);
}
Thanks for your help, I have been trying to debug this for hours, even using a debugger.
Ouch! You call sortpoints() with i as argument. That argument, according to your prototype and code, should be the last index, and i is not the last index, but the last index + 1.
int indexleft = firstindex;
int indexright = lastindex; // indexright is pointing to a non-existent element.
int indexpivot = (int)((lastindex + 1) / 2);
int n_points = lastindex + 1;
double left = distances[indexleft];
double right = distances[indexright]; // now right is an undefined value, or segfault.
To fix that, call your sortpoints() function as:
sortpoints (0, n_points-1, data);
The problem is in your sortpoints function. The first while loop is looping infinitely. To test that is it an infinite loop or not place a printf statement
printf("Testing first while loop\n");
in your first while loop. You have to fix that.
There are quite a number of problems, but one of them is:
int indexpivot = (int)((lastindex + 1) / 2);
The cast is unnecessary, but that's trivia. Much more fundamental is that if you are sorting a segment from, say, 48..63, you will be pivoting on element 32, which is not in the range you are supposed to be working on. You need to use:
int indexpivot = (lastindex + firstindex) / 2;
or perhaps:
int indexpivot = (lastindex + firstindex + 1) / 2;
For the example range, these will pivot on element 55 or 56, which is at least within the range.
I strongly recommend:
Creating a print function similar to printpoints() but with the following differences:
Takes a 'tag' string to identify what it is printing.
Takes and prints the distance array too.
Takes the arrays and a pair of offsets.
Use this function inside the sort function before recursing.
Use this function inside the sort function before returning.
Use this function in the main function after you've read the data.
Use this function in the main function after the data is sorted.
Print key values — the pivot distance, the pivot index, at appropriate points.
This allows you to check that your partitioning is working correctly (it isn't at the moment).
Then, when you've got the code working, you can remove or disable (comment out) the printing code in the sort function.