time complexity of Method - c#
I want to learn about big-o, I hope someone can help me count operators in Method and tell me what the time complexity of this method is and teach me how to count. I tried to study on Youtube and I was a bit confused.
static void SelectionSort(int[] data)
{
int temp, min;
for (int i = 0; i < data.Length - 1 ; i++)
{
min = i;
for (int j = 0; j < data.Length; j++)
{
if (data[j] < data[min])
{
min = j;
}
temp = data[min];
data[min] = data[i];
data[i] = temp;
}
}
}
first of all this is a function not a method because a method is simply a function inside a class.
the time complexity of this algorithm is O(n^2) because of the double for loop that means that this algorithm will take around n^2 operations to be done.
for example if you input an array of length 10 it will make 100 steps that's not an exact number but it means a lot if you try an array of length 100 it will make 10000 steps that means that if would take 100 more time to finish.
so the less the time complexity the faster the algorithm is.
to learn about time complexity check this video it will help a lot-->
https://www.youtube.com/watch?v=6aDHWSNKlVw&t=6s
Time Complexity will be O(n^2) for this one. Reason is you have nested loop inside another loop.
The outer loop iterates n times giving an element to the inner loop which again loops n times, per one loop of the outer array.
https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/#Bubble-sort
Related
What sorting method is this being applied and what is the algorithmic complexity of the method
I came across the code below for implementing sorting array. I have applied to a very long array and it was able to do so in under a sec may be 20 millisec or less. I have been reading about Algorithm complexity and the Big O notation and would like to know: Which is the sorting method (of the existing ones) that is implemented in this code. What is the complexity of the algorithm used here. If you were to improve the algorithm/ code below what would you alter. using System; using System.Text; //This program sorts an array public class SortArray { static void Main(String []args) { // declaring and initializing the array //int[] arr = new int[] {3,1,4,5,7,2,6,1, 9,11, 7, 2,5,8,4}; int[] arr = new int[] {489,491,493,495,497,529,531,533,535,369,507,509,511,513,515,203,205,207,209,211,213,107,109,111,113,115,117,11913,415,417,419,421,423,425,427,15,17,19,21,4,517,519,521,523,525,527,4,39,441,443,445,447,449,451,453,455,457,459,461,537,539,541,543,545,547,1,3,5,7,9,11,13,463,465,467,23,399,401,403,405,407,409,411,499,501,503,505,333,335,337,339,341,343,345,347,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,9,171,173,175,177,179,181,183,185,187,269,271,273,275,277,279,281,283,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,133,135,137,139,141,143,145,285,287,289,291,121,123,125,127,129,131,297,299,373,375,377,379,381,383,385,387,389,97,99,101,103,105,147,149,151,153,155,157,159,161,163,165,167,16,391,393,395,397,399,401,403,189,191,193,195,197,199,201,247,249,251,253,255,257,259,261,263,265,267,343,345,347,349,501,503,505,333,335,337,339,341,417,419,421,423,425,561,563,565,567,569,571,573,587,589,591,593,595,597,599,427,429,431,433,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,371,359,361,363,365,367,369,507,509,511,513,515,351,353,355,57,517,519,521,523,525,527,413,415,405,407,409,411,499,435,437,469,471,473,475,477,479,481,483,485,487,545,547,549,551,553,555,575,577,579,581,583,585,557,559,489,491,493,495,497,529,531,533,535,537,539,541,543,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,293,295}; int temp; // traverse 0 to array length for (int i = 0; i < arr.Length ; i++) { // traverse i+1 to array length //for (int j = i + 1; j < arr.Length; j++) for (int j = i+1; j < arr.Length; j++) { // compare array element with // all next element if (arr[i] > arr[j]) { ///Console.WriteLine(i+"i before"+arr[i]); temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; //Console.WriteLine("i After"+arr[i]); } } } // print all element of array foreach(int value in arr) { Console.Write(value + " "); } } }
This is selection sort. It's time complexity is O(𝑛²). It has nested loops over i and j, and you can see these produce every possible set of two indices in the range {0,...,𝑛-1}, where 𝑛 is arr.Length. The number of pairs is a triangular number, and is equal to: 𝑛(𝑛-1)/2 ...which is O(𝑛²) If we stick to selection sort, we can still find some improvements. We can see that the role of the outer loop is to store in arr[i] the value that belongs there in the final sorted array, and never touch that entry again. It does so by searching the minimum value in the right part of the array that starts at this index 𝑖. Now during that search, which takes place in the inner loop, it keeps swapping lesser values into arr[i]. This may happen a few times, as it might find even lesser values as j walks to the right. That is a waste of operations, as we would prefer to only perform one swap. And this is possible: instead of swapping immediately, delay this operation. Instead keep track of where the minimum value is located (initially at i, but this may become some j index). Only when the inner loop completes, perform the swap. There is less important improvement: i does not have to get equal to arr.Length - 1, as then there are no iterations of the inner loop. So the ending condition for the outer loop can exclude that iteration from happening. Here is how that looks: for (int i = 0, last = arr.Length - 1; i < last; i++) { int k = i; // index that has the least value in the range arr[i..n-1] so far for (int j = i+1; j < arr.Length; j++) { if (arr[k] > arr[j]) { k = j; // don't swap yet -- just track where the minimum is located } } if (k > i) { // now perform the swap int temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } } A further improvement can be to use the inner loop to not only locate the minimum value, but also the maximum value, and to move the found maximum to the right end of the array. This way both ends of the array get sorted gradually, and the inner loop will shorten twice as fast. Still, the number of comparisons remains the same, and the average number of swaps as well. So the gain is only in the iteration overhead.
This is "Bubble sort" with O(n^2). You can use "Mergesort" or "Quicksort" to improve your algorithm to O(n*log(n)). If you always know the minimum and maximum of your numbers, you can use "Digit sort" or "Radix Sort" with O(n) See: Sorting alrogithms in c#
Can Someone please explain me the logic of calculating big-O in my example
It is said the complexity of selection sort is O(N^2) but i don't get the logic since i'm reducing the number of times the loop executed. I understand for Code block 2 but not for code block 1 public int[] Sorting(int[] array) { for (i = 0; i <= array.Length - 1; i++) { minimum=i; for (j = i; j < array.Length-1; j++) { if (array[minimum] > array[j+1]) minimum = j + 1; } int temp = array[minimum]; array[minimum] = array[i]; array[i] = temp; } return array; } for(i=0;i<=n;i++) //Code 2 { for(j=0;j<=n;j++)
Let n be the array size. And look at the number of comparison (calls to if (array[minimum] > array[j+1])). For i=0 it's called n-1 times. For i=1 it's called n-2 times. ... For i=n-1 it's called 0 times. Finally, it's called 0+1+...+(n-1) times. It's the sum of consecutive integers. And, in your case, it's (n-1)*n/2 which is O(n²) Edit: So the exact number of comparison is (n-1)*n/2, it's not exactly n², it's look better than n², but it's really not. For n=10 you have 45 comparisons. For n=100 you have 4950 comparisons. That it, for 10 times more entry, you take > 100 times more times to complete your algorithm. For n=10 you have 45 comparisons. For n=1000 you have 499500 comparisons. That it, for 100 times more entry, you take > 10 000 times more times to complete your algorithm. As you can see, when you multiply by k the number of entry, you multiply roughly by k² the computation time.
2D Array vs Array of Arrays in tight loop performance C#
I had a look and couldn't see anything quite answering my question. I'm not exactly the best at creating accurate 'real life' tests, so i'm not sure if that's the problem here. Basically I want to create a few simple neural networks to create something to the effect of Gridworld. Performance of these neural networks will be critical and i dont want the hidden layer to be a bottleneck as much as possible. I would rather use more memory and be faster, so I opted to use arrays instead of lists (due to lists having an extra bounds check over arrays). The arrays aren't always full, but because the if statement (check if the element is null) is the same until the end, it can be predicted and there is no performance drop from that at all. My question comes from how I store the data for the network to process. I figured due to 2D arrays storing all the data together it would be better cache wise and would run faster. But from my mock up test that an array of arrays performs much better in this scenario. Some Code: private void RunArrayOfArrayTest(float[][] testArray, Data[] data) { for (int i = 0; i < testArray.Length; i++) { for (int j = 0; j < testArray[i].Length; j++) { var inputTotal = data[i].bias; for (int k = 0; k < data[i].weights.Length; k++) { inputTotal += testArray[i][k]; } } } } private void Run2DArrayTest(float[,] testArray, Data[] data, int maxI, int maxJ) { for (int i = 0; i < maxI; i++) { for (int j = 0; j < maxJ; j++) { var inputTotal = data[i].bias; for (int k = 0; k < maxJ; k++) { inputTotal += testArray[i, k]; } } } } These are the two functions that are timed. Each 'creature' has its own network (The first for loop), each network has hidden nodes (The second for loop) and i need to find the sum of the weights for each input (The third loop). In my test i stripped it so that it's not really what i am doing in my actual code, but the same amount of loops happen (The data variable would have it's own 2D array, but i didn't want to possibly skew the results). From this i was trying to get a feel for which one is faster, and to my surprise the array of arrays was. Code to start the tests: // Array of Array test Stopwatch timer = Stopwatch.StartNew(); RunArrayOfArrayTest(arrayOfArrays, dataArrays); timer.Stop(); Console.WriteLine("Array of Arrays finished in: " + timer.ElapsedTicks); // 2D Array test timer = Stopwatch.StartNew(); Run2DArrayTest(array2D, dataArrays, NumberOfNetworks, NumberOfInputNeurons); timer.Stop(); Console.WriteLine("2D Array finished in: " + timer.ElapsedTicks); Just wanted to show how i was testing it. The results from this in release mode give me values like: Array of Arrays finished in: 8972 2D Array finished in: 16376 Can someone explain to me what i'm doing wrong? Why is an array of arrays faster in this situation by so much? Isn't a 2D array all stored together, meaning it would be more cache friendly? Note i really do need this to be fast as it needs to sum up hundreds of thousands - millions of numbers per frame, and like i said i don't want this is be a problem. I know this can be multi threaded in the future quite easily because each network is completely separate and even each node is completely separate. Last question i suppose, would something like this be possible to run on the GPU instead? I figure a GPU would not struggle to have much larger amounts of networks with much larger numbers of input/hidden neurons.
In the CLR, there are two different types of array: Vectors, which are zero-based, single-dimensional arrays Arrays, which can have non-zero bases and multiple dimensions Your "array of arrays" is a "vector of vectors" in CLR terms. Vectors are significantly faster than arrays, basically. It's possible that arrays could be optimized further in later CLR versions, but I doubt that there'll get the same amount of love as vectors, as they're so relatively rarely used. There's not a lot you can do to make CLR arrays faster. As you say, they'll be more cache friendly, but they have this CLR penalty. You can improve your array-of-arrays code already, however, by only performing the first indexing operation once per row: private void RunArrayOfArrayTest(float[][] testArray, Data[] data) { for (int i = 0; i < testArray.Length; i++) { // These don't change in the loop below, so extract them var row = testArray[i]; var inputTotal = data[i].bias; var weightLength = data[i].weights.Length; for (int j = 0; j < row.Length; j++) { for (int k = 0; k < weightLength; k++) { inputTotal += row[k]; } } } } If you want to get the cache friendliness and still use a vector, you could have a single float[] and perform the indexing yourself... but I'd probably start off with the array-of-arrays approach.
Computing the most frequent element
I have recently come across this line of code and what it does is that it goes through an array and returns the value that is seen most often. For example 1,1,2,1,3 so it will return 1 because it appears more than 2 and 3. What I am trying to do is understand how it works so what I did was I went through it with visual studio step by step but it is not ringing any bells. Can anyone help me understand what is going on here? It would be a total plus if someone can tell me what does c do and what is the logic behind the arguments in the if statements. int[] arr = a; int c = 1, maxcount = 1, maxvalue = 0; int result = 0; for (int i = 0; i < arr.Length; i++) { maxvalue = arr[i]; for (int j = 0; j <arr.Length; j++) { if (maxvalue == arr[j] && j != i) { c++; if (c > maxcount) { maxcount = c; result = arr[i]; } } else { c=1; } } } return result;
EDIT: On closer examination, the code snippet has a nested loop and is conventionally counting the maximum seen element by simply keeping track of the maximum seen times and the element that was seen and keeping them in sync. That looks like an implementation of the Boyer-Moore majority vote counting algorithm. They have a nice illustration here. The logic is simple, and is to compute the majority in a single pass, taking O(n) time. Note that majority here means that more than 50% of the array must be filled with that element. If there is no majority element, you get an "incorrect" result. Verifying if the element is actually forming a majority is done in a separate pass usually.
It is not computing the most frequent element - what it is computing is the longest run of elements. Also, it is not doing it very efficiently, the inner loop only needs to compute upto i-1, not upto arr.Length. c is keeping track of the current run length. The first "if" is to check if this is a "continouous run". The second "if" (after reaching the last element in the run) will check if this run is longer than any run you have seen so far. In the above input sample, you are getting 1 as answer because it is the longest run. Try with an input where the element with the longest run is not the same as the most frequent element. (e.g., 2,1,1,1,3,2,3,2,3,2,3,2 - here 2 is the most frequent element, but 1,1,1 is the longest run).
Copy an array backwards? Array.Copy?
I have a List<T> that I want to be able to copy to an array backwards, meaning start from List.Count and copy maybe 5 items starting at the end of the list and working its way backwards. I could do this with a simple reverse for loop; however there is probably a faster/more efficient way of doing this so I thought I should ask. Can I use Array.Copy somehow? Originally I was using a Queue as that pops it off in the correct order I need, but I now need to pop off multiple items at once into an array and I thought a list would be faster.
Looks like Array.Reverse has native code for reversing an array which sometimes doesn't apply and would fall back to using a simple for loop. In my testing Array.Reverse is very slightly faster than a simple for loop. In this test of reversing a 1,000,000 element array 1,000 times, Array.Reverse is about 600ms whereas a for-loop is about 800ms. I wouldn't recommend performance as a reason to use Array.Reverse though. It's a very minor difference which you'll lose the minute you load it into a List which will loop through the array again. Regardless, you shouldn't worry about performance until you've profiled your app and identified the performance bottlenecks. public static void Test() { var a = Enumerable.Range(0, 1000000).ToArray(); var stopwatch = Stopwatch.StartNew(); for(int i=0; i<1000; i++) { Array.Reverse(a); } stopwatch.Stop(); Console.WriteLine("Elapsed Array.Reverse: " + stopwatch.ElapsedMilliseconds); stopwatch = Stopwatch.StartNew(); for (int i = 0; i < 1000; i++) { MyReverse(a); } stopwatch.Stop(); Console.WriteLine("Elapsed MyReverse: " + stopwatch.ElapsedMilliseconds); } private static void MyReverse(int[] a) { int j = a.Length - 1; for(int i=0; i<j; i++, j--) { int z = a[i]; a[i] = a[j]; a[j] = z; } }
It is not possible to do this faster than a simple for loop.
You can accomplish it any number of ways, but the fastest way is get the elements in exactly the manner you are. You can use Array.Reverse, Array.Copy, etc., or you can use LINQ and extension methods, and both are valid alternatives, but they shouldn't be any faster.
In one of your comments: Currently we are pulling out one result and committing it to a database one at a time There is a big difference between using a for loop to iterate backwards over a List<T> and committing records to a database one at a time. The former is fine; nobody's endorsing the latter. Why not just iterate first--to populate an array--and then send that array into the database, all populated? var myArray = new T[numItemsYouWantToSend]; int arrayIndex = 0; for (int i = myList.Count - 1; arrayIndex < myArray.Length; --i) { if (i < 0) break; myArray[arrayIndex++] = myList[i]; } UpdateDatabase(myArray);