I have two arrays, namely a[] and b[]. I would like to search if any element of a is present in b. Note that I do not want to find all duplicate occurrences, if any one element from a[] exists in b[], I would like to report it and break out without checking the rest of a[] or b[]
I'm a bit confused about how 'break' operates. Can 'break' break out of any kind of loop - for/while, but it breaks out of only the 'innermost loop' around where it's placed in code ?
This is my solution and please suggest if there is a better implementation for this O(n^2) approach
#include <stdio.h>
int main(void)
{
int a[] = {1,2,3,4,5,6};
int b[] = {11,2,3,7,8,9,6,10,11};
int i = 0, j = 0;
int duplicate = 0;
for(i=0;i<sizeof(a)/sizeof(int);i++)
{
for(j=0;j<sizeof(b)/sizeof(int);j++)
{
if(a[i] == b[j])
{
printf("Duplicates found for [%d]\n",a[i]);
duplicate = 1;
break;
}
}
if(duplicate == 1)
{
break;
}
}
return 0;
}
break only breaks the innermost loop in which it is used. If you want to avoid the ugly syntax then you have multiple solutions:
ignore this optimization until you prove it's relevant
move the code inside a function that accepts the two arrays as arguments so that you can directly return from the function without having to break.
adjust indices i and j after that you found a duplicate to make both loops return gracefully
use a goto instruction (which is not advisable in any case)
Other solutions, with complexity lower than O(n^2) could require some additional data structure, like a hashset or sorting of data.
breaks generally break out of the most inner loop in c. You have used it correctly.
if u want to just report a duplicate, then u can put this code into a fuction and whenever a duplicate is found, you just return. The function would look like this:
//Here a and b are pointers to array
//n1 and n2 are number of elements in array a,b
chk_dup(int *a,int *b,int n1,,int n2){
for(i=0;i<n1;i++)
{
for(j=0;j<n2;j++)
{
if(a[i] == b[j])
{
printf("Duplicates found for [%d]\n",a[i]);
//duplicate = 1;
//break;
return;
}
}
}
}
You cannot use sizeof(a) here becoz its just a pointer to array.Same goes for sizeof(b).
You can make this algorithm more efficient by sorting the arrays using quicksort(that would take O(nlgn)) and then for each element in a do binary search in b.
pseudo code for that is something like this:
//Here a and b are pointers to sorted arrays
//n1 and n2 are number of elements in array a,b
chk_dup(int *a,int *b,int n1,,int n2){
for(i=0;i<n1;i++)
{
//find a[i] in b using binary search.
int found=binary_search(a[i],b);
if(found){
printf("Found Duplicate");
return;
}
}
printf("No duplicate found");
}
So, the whole algorithm works in O(nlgn). While the algorithm you are using can take O(n^2).
Otherwise your code is perfectly fine and the use of break is correct
You could use goto as noted here How to break out of nested loops? it's the last remaining valid use of this...
And maybe there is a better solution using xor, not sure if you can reduce the
complexity though...
Related
I am looking for help regarding the implementation of a counting sort function in the CS50 Course in week 3.
An int Array has to be sorted.
I tested various unsorted arrays and my counting sort function seems to sort the array just correctly, yet my search functions won't work on the sorted array after.
Could someone give me a hint?
void countsort( int array[], int size) {
int count=0;
int zahl=0;
int max=65536;
int countarr [max];
int finalarr [size];
memset (countarr, 0, sizeof(countarr));
for(int i=0;i<size;i++) {
zahl=array[i];
countarr[zahl]++;
}
for(int i=0;i<max;i++) {
while(countarr[i]>0) {
finalarr[count]=i;
countarr[i]--;
count++;
}
}
array=finalarr;
for(int i=0;i<size;i++){
printf(" %i ",array[i]);
}
}
This is my search algorithm used after the array is sorted, it works with sort algorithms from other people.
bool binarysearch(int value, int values[], int n){
int start=0,
end=n,
mid=0,
midpos=0;
while(end>0) {
midpos=(start+end)/2;
mid=values[midpos];
if(mid==value) return true;
if(mid<value) start=++midpos;
if(mid>value) end=--midpos;
}
return false;
}
In binarysearch, the loop condition while(end>0) is wrong.
If we search for a value which is greater than at least one of the elements of the array, end will never be zero.
Try changing it to while(end>=start), which literally means that the considered interval is non-empty.
In countsort, the line array=finalarr; does not copy the whole array.
Instead, the local variable array becomes a pointer to finalarr.
The contents of the original array remain unchanged, and the sorted array is gone when you exit the function.
This explains why your binary search works (better) with other sort functions.
Try changing finalarr[count]=i; to array[count]=i; and get rid of finalarr completely, putting the values into array right away.
Alternatively, you can use memmove instead of that line.
I need to write code that sorts in 'n' run time and I don't know how to calculate it. I need to simply sort an array so that left side is odd and right side is even. This is what I wrote and I wonder how do I to find the run time.
for (i=0;i<size-1;i++)
{
if(ptr[i]%2==0 || ptr[i]==0)
{
for (j=i;j<size;j++)
{
if(ptr[j]%2!=0)
{
temp=ptr[i];
ptr[i]=ptr[j];
ptr[j]=temp;
break;
}
}
}
}
Thanks in advance.
Your runtime for this Code is O(N^2)
You can use Counting Sort to sort an array in linear time
For reference Counting Sort
As #VenuKant Sahu answered, OP's code is O(n*n)
That is due to its double nested for loops
for (i=0;i<size-1;i++)
...
for (j=i;j<size;j++)
...
I need to write code that sorts in 'n' run time
O(n) algorithm (did not want to just give the code)
The number of loop iterations below can not exceed n/2.
The increment even_side happens at most n times.
The decrement odd_side happens at most n times.
// set up indexes
int even_side = left-most valid index
int odd_side = right-most valid index
loop {
while (the_even_index_is_not_at_the_right_end && is_even(a[even_side]) increment even_side;
while (the_odd_index_is_not_at_the_left_end && !is_even(a[odd_side]) decrement odd_side
compare the indexes
if (done) exit the loop;
a[even_side] <==> a[odd_side]
}
Some helper code to set up a random array.
#define N 10
srand(time(NULL));
int a[N];
for (int i = 0; i<N; i++) {
a[i] = rand()%100;
printf(" %d", a[i]);
}
puts("");
My goal is to understand why adopting linear search with sentinel is preferred than using a standard linear search.
#include <stdio.h>
int linearSearch(int array[], int length) {
int elementToSearch;
printf("Insert the element to be searched: ");
scanf("%d", &elementToSearch);
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
return -1; // The element to be searched is not in the array
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10};
int myArrayLength = 6;
linearSearch(myArray, myArrayLength);
return 0;
}
Wikipedia mentions:
Another way to reduce the overhead is to eliminate all checking of the loop index. This can be done by inserting the desired item itself as a sentinel value at the far end of the list.
If I implement linear search with sentinel, I have to
array[length + 1] = elementToSearch;
Though, the loop stops checking the elements of the array once the element to be searched is found. What's the point of using linear search with sentinel?
A standard linear search would go through all the elements checking the array index every time to check when it has reached the last element. Like the way your code does.
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
But, the idea is sentinel search is to keep the element to be searched in the end, and to skip the array index searching, this will reduce one comparison in each iteration.
while(a[i] != element)
i++;
First, lets turn your example into a solution that uses sentinels.
#include <stdio.h>
int linearSearch(int array[], int length, int elementToSearch) {
int i = 0;
array[length] = elementToSearch;
while (array[i] != elementToSearch) {
i++;
}
return i;
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10, -1};
int myArrayLength = 6;
int mySearch = 9;
printf("result is %d\n", linearSearch(myArray, myArrayLength, mySearch));
return 0;
}
Notice that the array now has an extra slot at the end to hold the sentinel value. (If we don't do that, the behavior of writing to array[length] is undefined.)
The purpose of the sentinel approach is to reduce the number of tests performed for each loop iteration. Compare:
// Original
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i;
}
}
return -1;
// New
while (array[i] != elementToSearch) {
i++;
}
return i;
In the first version, the code is testing both i and array[i] for each loop iteration. In the second version, i is not tested.
For a large array, the performance difference could be significant.
But what are the downsides?
The result when the value is not found is different; -1 versus length.
We have to make the array bigger to hold the sentinel value. (And if we don't get it right we risk clobbering something on the stack or heap. Ouch!)
The array cannot be read-only. We have to be able to update it.
This won't work if multiple threads are searching the same array for different elements.
Using the sentinel value allows to remove variable i and correspondingly its checking and increasing.
In your linear search the loop looks the following way
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
So variable i is introduced, initialized, compared in each iteration of the loop, increased and used to calculate the next element in the array.
Also the function has in fact three parameters if to pass to the function the searched value
int linearSearch(int array[], int length, int value) {
//...
Using the sentinel value the function can be rewritten the following way
int * linearSearch( int array[], int value )
{
while ( *array != value ) ++array;
return array;
}
And inside the caller you can check whether the array has the value the following way
int *target = linearSearch( array, value );
int index = target == array + size - 1 ? -1 : target - array;
If you add the value to search for, you can reduce one comparison in every loop, so that the running time is reduced.
It may look like for(i = 0;;i++) if(array[i] == elementToSearch) return i;.
If you append the value to search for at the end of the array, when instead of using a for loop with initialization, condition and increment you can a simpler loop like
while (array[i++] != elementToSearch)
;
Then the loop condition is the check for the value you search for, which means less code to execute inside the loop.
The point is that you can convert the for loop into a while/repeat loop. Notice how you are checking i < length each time. If you covert it,
do {
} while (array[i++] != elementToSearch);
Then you don't have to do that extra checking. (in this case, array.length is now one bigger)
Although the sentinel approach seems to shave off a few cycles per iteration in the loop, this approach is not a good idea:
the array must be defined with an extra slot and passing its length as 1 less than the defined length is confusing and error prone;
the array must be modifiable;
if the search function modifies the array to set the sentinel value, this constitutes a side effect that can be confusing and unexpected;
the search function with a sentinel cannot be used for a portion of the array;
the sentinel approach is inherently not thread safe: seaching the same array for 2 different values in 2 different threads would not work whereas searching a constant read only array from multiple threads would be fine;
the benefits are small and only for large arrays. If this search becomes a performance bottleneck, you should probably not use linear scanning. You could sort the array and use a binary search or you could use a hash table.
optimizing compilers for modern CPUs can generate code where both comparisons will be performed in parallel, hence incur no overhead;
As a rule of thumb, a search function should not have side effects. A good example of the Principe of least surprise.
Can we modify this nested loop to recursive function?
Target: Find two indice in an int array whose sum equal to given target value. Here's the working iterative code, how can I consider this function in a different way as a recursive?
#include<stdio.h>
#define SIZE 15
int find_indice(const int arr[],int size,int target,int *ind_1,int *ind_2);
int main(){
int arr[SIZE]={0,1,3,4,5,6,7,8,9,15,-5,0,9,10,23};
int target=-2;
int ind1,ind2;
find_indice(arr,SIZE,target,&ind1,&ind2);
if(ind1!=-1 && ind2!=-1){
printf("array[%d]=>%d,array[%d]=>%d \n",ind2,arr[ind2],ind1,arr[ind1]);
}
else{
printf("Not found! \n");
printf("array[%d]=>%d,array[%d]=>%d \n",ind2,0,ind1,0);
}
return 0;
}
int find_indice(const int arr[],int size,int target,int *ind_1,int *ind_2){
int i,j,found=0;
for(i=0;i<size-1;i++){
for(j=0;j<size;j++){
if((arr[i]+arr[j])==target){
*ind_1=i;
*ind_2=j;
found=1;
}
}
}
if(found==0){
*ind_1=-1;
*ind_2=-1;
}
return 0;
}
I don't know how to turn your loops into a recursive call of the same function, but here are a few remarks on your code:
the printf statement is meaningless in case you do not find the indices.
Why do you stop at i<size-1 in the outer loop? The test should be i < size, unless you want indices to be different, but your code does not implement this constraint.
find_indice() should return the found status, it would be much simpler than storing bogus indices in *ind_1 and *ind_2, and would allow you to use the proper type for array indices: size_t.
You should return from find_indice() immediately when you find a match, no need to try all possibilities.
You can halve the running time by starting the inner loop at j=i instead of j=0. Note that for a different target, say -10, find_indice() could return the same index in both *ind_1 and *ind_2. This may not be what is expected. You would start the inner loop at j=i+1 if it is not wanted.
I've got a c study which it must print all the numbers in an array then how many times they repeated.
int lottery(int a,int b,int c,int d,int e,int f,int i,int count)
{
printf("Enter the loop count:");
scanf("%d",&d);
a=time(NULL);
srand(a);
int genel[100][100];
int hepsi[50]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49};
count=0;
for(e=0;e<=d-1;e++)
{
for(b=0;b<=5;b++)
{
genel[e][b]=(rand()%49+1);
while(i>=0 && i<=49)
{
if(genel[e][b]==hepsi[i])
{
count=count+1;
}
else{
count=count;
}
}
printf("%d->%d\t",genel[e][b],count);
}
}
}
This doesnt work obviously. the output must be something like that
1-->0 2-->3 3-->15 etc
TY for your help, cheers :)
It is important that you understand what you are doing, naming is therefore very important. Nesting loops is okay if you know what you are doing. An easier to understand approach would be:
void lottery() {
int i, j //forloop counters
int randArray[100][100]; //array for random values
srand(Time(NULL)); //set random seed based on system time
//set random values
for(i = 0; i < 100; i++) {
for(j = 0; j < 100; j++) {
randArray[i][j] = rand()%49 + 1; //sets random ranging from 1 to 49 (49 incl)
}
}
//here you can start the counting procedure, which I won't spoil but ill give some hints below
}
There are a few options, first the easy lazy approach:
use a loop over all the values, 'int number' from 1 up to 49, inside that forloop use two forloops to search through the whole array, incrementing int x everytime you encounter the value 'number'. After youve searched through the whole array, you can use printf("%d -> %d", number, x); to print the value, set x to zero and count another number.
Another approach is as u tried,
create an array with for each number a location where you can increment a counter. Loop through the whole array now using two for-loops, increment the arraylocation corresponding to the value which youve found at randArray[i][j]. Afterwards print the array with counts using another forloop.
I suggest you try to clean up your code and approach, try again and come back with problems you encounter. Good luck!
sorry if this wasn't helpful to you, I tried to spoil not too much because according to my own experience programming should be learned by making mistakes.