how to calculate complexity of a simple search - c++

I have an array with n elements. Now I need to search an element x. Here is the program
int x[100],i,s;
cout<<"Enter how many number of element you have";
cin>>n;
for(i=0;i<n;i++)
{
cin>>x[i];
}
cout<<"Enter element which you want to search";
cin>>s;
for(i=0;i<n;i++)
{
if(x[i]==s)
{
cout<<"Item found in position"<<i;
break;
}
}
what's the time and space complexity of this program?
Space:
x[100] = 200 bytes
n = 1 byte
s = 1 byte
==================
Total = 202 bytes
is it correct?
Time Complexity:
Please help me to figure out
Best case scenario(if x matches first element of n) complexity?
Worst case scenario(if x matches last element of n or doesn't match) complexity?

Time Complexity:
Time complexity is nothing but number of comparisons done by computer in your code.
So, when you search your array you actually do n comparisons. Comparing each element in the array with your input element. So, in this case:
Best case: O(1) - Element is found in the first comparison.
Worst case: O(n) - Means you had to search through all the elements and you found the element at the last place of the array.
Space complexity:
Normally, this is seen in terms of numbers of elements in the array rather
then the total size taken by these elements. This is done because size of data
types differ on various architectures but number of elements is dependent on the
problem and not the machine.
Hence, in your case:
Space complexity = "n"..Since n elements are present in the array.

Related

Is below sorting algorithm O(n)?

Algorithm:
insert element counts in a map
start from first element
if first is present in a map, insert in output array (total number of count), increment first
if first is not in a map, find next number which is present in a map
Complexity: O(max element in array) which is linear, so, O(n).
vector<int> sort(vector<int>& can) {
unordered_map<int,int> mp;
int first = INT_MAX;
int last = INT_MIN;
for(auto &n : can) {
first = min(first, n);
last = max(last, n);
mp[n]++;
}
vector<int> out;
while(first <= last) {
while(mp.find(first) == mp.end()) first ++;
int cnt = mp[first];
while(cnt--) out.push_back(first);
first++;
}
return out;
}
Complexity: O(max element in array) which is linear, so, O(n).
No, it's not O(n). The while loop iterates last - first + 1 times, and this quantity depends on the array's contents, not the array's length.
Usually we use n to mean the length of the array that the algorithm works on. To describe the range (i.e. the difference between the largest and smallest values in the array), we could introduce a different variable r, and then the time complexity is O(n + r), because the first loop populating the map iterates O(n) times, the second loop populating the vector iterates O(r) times, and its inner loop which counts down from cnt iterates O(n) times in total.
Another more formal way to define n is the "size of the input", typically measured in the number of bits that it takes to encode the algorithm's input. Suppose the input is an array of length 2, containing just the numbers 0 and M for some number M. In this case, if the number of bits used to encode the input is n, then the number M can be on the order of O(2n), and the second loop does that many iterations; so by this formal definition the time complexity is exponential.

How to convert a simple computer algorithm into a mathematical function in order to determine the big o notation?

In my University we are learning Big O Notation. However, one question that I have in light of big o notation is, how do you convert a simple computer algorithm, say for example, a linear searching algorithm, into a mathematical function, say for example 2n^2 + 1?
Here is a simple and non-robust linear searching algorithm that I have written in c++11. Note: I have disregarded all header files (iostream) and function parameters just for simplicity. I will just be using basic operators, loops, and data types in order to show the algorithm.
int array[5] = {1,2,3,4,5};
// Variable to hold the value we are searching for
int searchValue;
// Ask the user to enter a search value
cout << "Enter a search value: ";
cin >> searchValue;
// Create a loop to traverse through each element of the array and find
// the search value
for (int i = 0; i < 5; i++)
{
if (searchValue == array[i])
{
cout << "Search Value Found!" << endl;
}
else
// If S.V. not found then print out a message
cout << "Sorry... Search Value not found" << endl;
In conclusion, how do you translate an algorithm into a mathematical function so that we can analyze how efficient an algorithm really is using big o notation? Thanks world.
First, be aware that it's not always possible to analyze the time complexity of an algorithm, there are some where we do not know their complexity, so we have to rely on experimental data.
All of the methods imply to count the number of operations done. So first, we have to define the cost of basic operations like assignation, memory allocation, control structures (if, else, for, ...). Some values I will use (working with different models can provide different values):
Assignation takes constant time (ex: int i = 0;)
Basic operations take constant time (+ - * ∕)
Memory allocation is proportional to the memory allocated: allocating an array of n elements takes linear time.
Conditions take constant time (if, else, else if)
Loops take time proportional to the number of time the code is ran.
Basic analysis
The basic analysis of a piece of code is: count the number of operations for each line. Sum those cost. Done.
int i = 1;
i = i*2;
System.out.println(i);
For this, there is one operation on line 1, one on line 2 and one on line 3. Those operations are constant: This is O(1).
for(int i = 0; i < N; i++) {
System.out.println(i);
}
For a loop, count the number of operations inside the loop and multiply by the number of times the loop is ran. There is one operation on the inside which takes constant time. This is ran n times -> Complexity is n * 1 -> O(n).
for (int i = 0; i < N; i++) {
for (int j = i; j < N; j++) {
System.out.println(i+j);
}
}
This one is more tricky because the second loop starts its iteration based on i. Line 3 does 2 operations (addition + print) which take constant time, so it takes constant time. Now, how much time line 3 is ran depends on the value of i. Enumerate the cases:
When i = 0, j goes from 0 to N so line 3 is ran N times.
When i = 1, j goes from 1 to N so line 3 is ran N-1 times.
...
Now, summing all this we have to evaluate N + N-1 + N-2 + ... + 2 + 1. The result of the sum is N*(N+1)/2 which is quadratic, so complexity is O(n^2).
And that's how it works for many cases: count the number of operations, sum all of them, get the result.
Amortized time
An important notion in complexity theory is amortized time. Let's take this example: running operation() n times:
for (int i = 0; i < N; i++) {
operation();
}
If one says that operation takes amortized constant time, it means that running n operations took linear time, even though one particular operation may have taken linear time.
Imagine you have an empty array of 1000 elements. Now, insert 1000 elements into it. Easy as pie, every insertion took constant time. And now, insert another element. For that, you have to create a new array (bigger), copy the data from the old array into the new one, and insert the element 1001. The 1000 first insertions took constant time, the last one took linear time. In this case, we say that all insertions took amortized constant time because the cost of that last insertion was amortized by the others.
Make assumptions
In some other cases, getting the number of operations require to make hypothesises. A perfect example for this is insertion sort, because it is simple and it's running time depends of how is the data ordered.
First, we have to make some more assumptions. Sorting involves two elementary operations, that is comparing two elements and swapping two elements. Here I will consider both of them to take constant time. Here is the algorithm where we want to sort array a:
for (int i = 0; i < a.length; i++) {
int j = i;
while (j > 0 && a[j] < a[j-1]) {
swap(a, i, j);
j--;
}
}
First loop is easy. No matter what happens inside, it will run n times. So the running time of the algorithm is at least linear. Now, to evaluate the second loop we have to make assumptions about how the array is ordered. Usually, we try to define the best-case, worst-case and average case running time.
Best-case: We do never enter the while loop. Is this possible ? Yes. If a is a sorted array, then a[j] > a[j-1] no matter what j is. Thus, we never enter the second loop. So, what operations are done in this case is the assignation on line 2 and the evaluation of the condition on line 3. Both take constant time. Because of the first loop, those operations are ran n times. Then in the best case, insertion sort is linear.
Worst-case: We leave the while loop only when we reach the beginning of the array. That is, we swap every element all the way to the 0 index, for every element in the array. It corresponds to an array sorted in reverse order. In this case, we end up with the first element being swapped 0 times, element 2 is swapped 1 times, element 3 is swapped 2 times, etc up to element n being swapped n-1 times. We already know the result of this: worst-case insertion is quadratic.
Average case: For the average case, we assume the items are randomly distributed inside the array. If you're interested in the maths, it involves probabilities and you can find the proof in many places. Result is quadratic.
Conclusion
Those were basics about analyzing the time complexity of an algorithm. The cases were easy, but there are some algorithms which aren't as nice. For example, you can look at the complexity of the pairing heap data structure which is much more complex.

Big 0 notation for duplicate function, C++

What is the Big 0 notation for the function description in the screenshot.
It would take O(n) to go through all the numbers but once it finds the numbers and removes them what would that be? Would the removed parts be a constant A? and then would the function have to iterate through the numbers again?
This is what I am thinking for Big O
T(n) = n + a + (n-a) or something involving having to iterate through (n-a) number of steps after the first duplicate is found, then would big O be O(n)?
Big O notation is considering the worst case. Let's say we need to remove all duplicates from the array A=[1..n]. The algorithm will start with the first element and check every remaining element - there are n-1 of them. Since all values happen to be different it won't remove any from the array.
Next, the algorithm selects the second element and checks the remaining n-2 elements in the array. And so on.
When the algorithm arrives at the final element it is done. The total number of comparisions is the sum of (n-1) + (n-2) + ... + 2 + 1 + 0. Through the power of maths, this sum becomes (n-1)*n/2 and the dominating term is n^2 so the algorithm is O(n^2).
This algorithm is O(n^2). Because for each element in the array you are iterating over the array and counting the occurrences of that element.
foreach item in array
count = 0
foreach other in array
if item == other
count += 1
if count > 1
remove item
As you see there are two nested loops in this algorithm which results in O(n*n).
Removed items doesn't affect the worst case. Consider an array containing unique elements. No elements is being removed in this array.
Note: A naive implementation of this algorithm could result in O(n^3) complexity.
You started with first element you will go through all elements in the vector thats n-1 you will do that for n time its (n * n-1)/2 for worst case n time is the best case (all elements are 4)

What is the time complexity of traversing a 2d array

What is the time complexity of traversing (rows ,columns) a two dimensional array?
bool check(int array [9][9])
{
int num=0;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (array [i][j] == 0) {
num++;
}
}
}
return num;
}
I think each for loop will take square root of n so that nested loops totally take O(n) as traversing all elements, where I am defining n as the total size of the input (in this case 81 elements in array). Is that correct?
As you define n to be the total size of the input, yes the running time of the algorithm you propose will be O(n): you are performing one single operation on each element of the input, for n total operations.
Where the confusion is arising from this question is that by convention, multi-dimensional arrays are not referred to by their total size but rather by each of their dimensions separately. So rather than viewing array as being of size n (81) it would be considered to be an array of size p x q (9 x 9). That would give you a running time of O(pq). Or, if we limit it to square arrays with both dimensions r, O(r^2).
All are correct, which is why it's important to give a clear definition of your variables up front when talking about time complexity. Otherwise, when you use n to mean the total size when most people would assume that n would be a single dimension, you are inviting a lot of confusion.
The time complexity will be O (n*m) where n the number of arrays which is the 1st dimension and m the max size of each internal array ie, the 2nd dimension.
For any algorithm of the form
for (1..n) {
for (1..m) {
doSomething();
}
}
The average, best and worst case time complexity is O(n x m). In your case if n=m, it becomes O(n^2)
The time complexity is O(N), which means its time complexity is linear.
Let's look at the concept of time complexity. When we define any time complexity in Big O notation what we mean is how does the graph of N versus run time must look like in the worst execution case.
For given nested loop size of the data is 9*9 = 81.No matter what operation you perform in the inside for loop. The loops will not execute more than 9*9 = 81 times. If the size of the array was [10][10] the loops will execute not more than 100 times.
If you make graph of execution time of the code with number of inputs or data it will be linear.
The Time complexity is derived by how many times your code is going to do lookup of an element in the data structure to deduce the result. It does not matter whether it is 1-D, 2-D or n-D array. If you access an element not more than once for an n-D array to deduce the solution, the complexity is linear O(N), where N = N1 * N2 * ... *Nn
Let's understand this by taking real world example of two different hotels having N rooms each. You need to search your friend in the hotel.
In first scenario let's say first hotel has 100 rooms on single(ground) floor, you need to visit 100 rooms in worst case to find your friend, so here complexity is linear i.e. 0(N) or O(100).
In second scenario the hotel has 4 floors having 25 rooms each. In the worst case you have to visit 25*4=100 rooms (ignore the accessing time/process between floors), hence complexity is again linear.
A 2-d array arr[i][j] can be traversed by a single loop also, where the loop will run for (i × j) times.
Consider n = (i×j), then the time complexity for traversing a 2-d array is O(n).
Thanks to coder2design.com

Efficient way to find the max number in an array

This is an interview question
There is an array of integers. The elements in the array can follow the following patterns.
numbers are in ascending order
numbers are in descending order
numbers increases in the beginning and decreases in the end
numbers decreases in the beginning and increases in the end
What is the efficient way to find the max number in the array?
In that case, all you need to do is to determine whether it's (3). If not, the answer is max(first, last).
In the case that all elements are equal, you'll need to exhaustively search the array to show that there's not one high number somewhere in the middle. So I think it's O(n) to determine whether you're in (3).
Well, case by case you have
The last number.
The first number.
Move from beginning to end, stopping at first descent and printing previous number.
Compare first and last numbers.
If you don't know which case you're in, then you can test this while finding the max by doing the following (in C-like pseudocode):
for (int i=0; i<end; ++i) {
if (array[i] < array[i+1]) {
// CASE 1 or 3
for (int j=i+1; j<end; ++j) {
if (array[j] > array[j+1]) {
// CASE 3
return array[j];
}
}
// CASE 1
return array[end];
}
}
// CASE 2 or 4
return max(array[0],array[end]);
You will be able to determine with type of array it is by inspecting the first two and last two elements
It is the last element
It is the first element
see below
It is the larger of the first and last elements
For 3, start by looking at two elements at the middle of the array, if they are still increasing the max is higher in the array, if they are decreasing, the max is lower in the array. Repeat in a binary search fashion
Since cases 1-3 all have one peak (value surrounded on both sides by values lower than itself or the edge of the array), and case 4 has two peaks both on the ends of the array, this problem can be solved rather simply in O(log n) time for all cases:
First, apply the 1D peak finding algorithm to find a peak in the array.
If the peak occurs in the middle of the array (not the first or last position), then this is case #3, and the peak is also the maximum.
If the peak is either the first or last element of the array, then this is one of cases 1, 2, or 4, and the array max is max(first, last).
Python-esque pseudo code:
def find-peak(list):
mid=len(list)/2
if (list[mid-1] > list[mid]:
return find-peak(list[:mid-1])
else if (list[mid+1] > list[mid]:
return find-peak(list[mid+1:])
else:
return mid
def find-max(list):
peak = find-peak(list)
if peak==0 or peak==len(list)-1:
return max(list[0], list[-1])
else:
return list[peak]
1.the last number
2.the first number
3.do binary-like search, pick a pivot,calculate the slope, just to decide next to go left or right
4.first or last number
The way to identify the four cases is straight forward if we assume the sequence do not have repeating number:
case 1: arr[0] < arr[1] && arr[end-1] < arr[end]
case 2: arr[0] > arr[1] && arr[end-1] > arr[end]
case 3: arr[0] < arr[1] && arr[end-1] > arr[end]
case 4: arr[0] > arr[1] && arr[end-1] < arr[end]
As mentioned in other answers, the way to find the max is straight forward too:
case 1: arr[end]
case 2: arr[0]
case 3: binary search, until found n that arr[n-1] < arr[n] > arr[n+1]
case 4: max(arr[0],arr[end])
The answer depends on what is meant by "efficiency." If you want fast code, look at someone else's answer. If you want to be efficient as a programmer you should probably just use a library call (like max_element() in C++.)
This problem reminds me of the Golden section algoritm for finding the minimum of an unimodular (ie.: decreasing then increasing) function. It is kind of a souped-up version of binary search that calculates the value of the function (ie.: inspects the array) in as few points as possible.
All you need to do now is translate it into a discrete version and add nome extra whistles to determine wether the function is concave or convex.