So in the programming course I'm taking we learned about recursion. I got an assignment to write recursive function that gets sorted array and a number and return the index of that number in the array if existed.
I didn't quite understand yet the subject of recursion so I need a little help with my code. I think i'm at the right direction but again, I'm a little struggling with the subject so I thought I could find guidance and help here.
this is the code I have at the moment:
private static int arrayIndexValue(int[] arr, int ind)
{
if (ind > arr.Length/2)
{
return arrayIndexValue(arr.Length/2, ind)
}
else if (ind < arr.Length/2)
{
return arrayIndexValue(arr.Length/2)
}
}
basically what i wanted to write here is something like this:
if the number the user inserts is smaller then the middle of the array, continue with the function but with the array cut in half (Binary search)
same if the number is bigger (i suggested to use my function with something like the binary search but as you can see i dont quite know how to apply it to my code)
Recursion works by breaking the entire problem into smaller parts. If you are at the smallest part (meaning that your array has only one value) then you would have your solution. This would also be your first case that you have to handle.
if (arr.Length == 1) return arr[0];
Now you can start to break down the problem. Binary left or right decision. As you already wrote you want to check weather the number is left or right from the middle of your array. So in your condition you need to access the element in the array using the [ ] operator:
if (ind > arr[arr.Length / 2]) // check if larger than the middle element
To extract a part of the array you need a second array in which you can copy the content that you want. Since you intend to pass only half of the current array into the recursive call you also need only half of the size.
int [] temp = new int[arr.Length / 2];
Now you can copy the part that you desire (first or second) depending on your condition and keep searching with a recursive call.
To copy the Array you can use the Arra.Copy method. You can pass the start and length to this method and it will copy the left or the right part into the int [] temp array. Here is an example of how to copy the right part:
Array.Copy(arr, arr.Length / 2, temp, 0, arr.Length / 2);
In the end you will need to fire your recursive call. This call will expect the new array and still the same number to look for. So since you copied either the left or right half of the previous array, now you pass the new short array to the recursive call:
return arrayIndexValue(temp, ind);
And there you have it
i got an assignment to write recursive function that gets sorted array
and a number and return the index of that number in the array if
existed.
In your method you check indexes, not values - you should compare values of elements, not indexes.
To write recursive function to find element you should pass array, element to find, start index and end index. Start index and end index will be used for finding in part of array.
Your method will be something like this:
private static int GetIndex(int[] arr, int element, int startIndex, int endIndex)
{
if (startIndex > endIndex)
{
return -1; //not found
}
var middleIndex = (startIndex + endIndex) / 2;
if (element == arr[middleIndex])
{
return middleIndex;
}
if (element < arr[middleIndex])
{
return GetIndex(arr, element, startIndex, middleIndex - 1);
}
else
{
return GetIndex(arr, element, middleIndex + 1, endIndex);
}
}
and to get some index:
static void Main(String[] args)
{
var arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var element = 5;
var index = GetIndex(arr, element , 0, arr.Length - 1);
}
So the problem you have right now is that you haven't broken your problem into repeating steps. It actually should be very similar flow to a loop without all the variables. I want to do something a little simpler first.
void int find(int[] values, int at, int value) {
if (values.Length >= at || at < 0) {
return -1;
} else if (values[at] == value) {
return at;
}
return find(values, at+1, value);
}
This function just moves a index up one every time via recursion, but we can also do something very similar with a loop.
void int find(int[] values, int at, int value) {
while (values.Length < at && at >= 0) {
if (values[at] == value) {
return at;
}
at = at + 1;
}
return -1;
}
The whole reason we usually talk about recursion is that it is usually used so that you have no "mutating" state. The variables and there values are the same for every value. You can break this, but it is usually considered beneficial. A quick stab at your problem produces something like
void int find(int[] sortedValues, int start, int end, int value) {
var midIndex = (start + end) / 2;
var mid = sortedValues[midIndex];
if (start == end) {
return mid == value ? midIndex : -1;
} else if (mid > value) {
return find(sortedValues, mid, end, value);
} else if (mid < value) {
return find(sortedValues, start, mid, value);
} else {
return midIndex;
}
}
However, this isn't perfect. It has known issues like edge cases that would cause a crash. It should definitely be cleaned up a little. If you want to really want to dip your toe into recursion, try a purely functional language where you cannot mutate, like Haskell, Elm, or maybe something a little impure like F#, Clojure, or Scala. Anyway have fun.
Related
I've tried changing my sort into a recursive function where the method calls itself. At least that's my understanding of recursion to forego for loops and the method calls itself to repeat the necessary iterations.
Below is my iterative verion:
for (int i = 0; i < Integers.Count; i++) //loops through all the numbers
{
min = i; //setting the current index number to be the minimum
for (int index = i + 1; index < Integers.Count; index++) //finds and checks pos of min value
{ //and switches it with last element using the swap method
if ((int) Integers[index] > (int) Integers[min]) {
min = index;
}
comparisons++;
}
if (i != min) //if statement for if swop is done
{
Swap(i, min, Integers, ref swops); //swap method called
}
//Swap method called
}
I've tried making it recursive. I read online that it was OK to still have for loops in a recursive funtion which I guess is not true. I just havent been able to develop a working sort. Am I going to need to split the method into 2 where one method traverses a list and the other does the sort?
Here's my selection sort recursive method attempt below:
static void DoSelectionSortRecursive(ArrayList Integers, int i, int swops, int comparisons) {
int min;
min = i;
for (int index = i + 1; index < Integers.Count; index++) //read online that the use of arraylists are deprecated, and i shoudlve rather used List<int> in order to remedy the code. is it necassary
{
if ((int) Integers[index] > (int) Integers[min]) {
min = index;
}
comparisons++;
}
if (i != min) {
Swap(i, min, Integers, ref swops);
}
DoSelectionSortRecursive(Integers, (i + 1), comparisons, swops); //DoSelectionSortRecursive method called
}
This is my imporved attempt including performance measures and everything. The original list of integers in the unsorted lists. 84,24,13,10,37.
and im getting 84,24,13,37,10. clearly not in a sorted descending order.
below is the improved code
static void DoSelectionSortRecursive(ArrayList Integers)
{
Stopwatch timer = new Stopwatch();
timer.Start();
int shifts = 0;
int swops = 0;
int comparisons = 0;
Sort(Integers, 1,ref swops,ref comparisons);
timer.Stop();
Console.WriteLine("Selection Sort Recursive: ");
Console.WriteLine(timer.ElapsedMilliseconds);
Console.WriteLine(swops);
Console.WriteLine(comparisons);
Console.WriteLine(shifts); //not needed in this sort
Console.WriteLine("-------------------------------------");
foreach (int i in Integers)
{
Console.WriteLine(i);
}
}
static void Sort(ArrayList Integers, int i, ref int swops, ref int comparisons)
{
int min = i;
int index = i + 1;
if (index < Integers.Count) //read online that the use of arraylists are deprecated, and i shoudlve rather used List<int> in order to remedy the code. is it necassary
{
if ((int)Integers[index] > (int)Integers[min])
{
min = index;
}
comparisons++;
index++;
}
if (i != min)
{
Swap(i, min, Integers, ref swops);
}
if (i < Integers.Count - 1)
{
Sort(Integers, (i + 1), ref comparisons, ref swops); //DoSelectionSortRecursive method called
}
}
static void Swap(int x, int y, ArrayList Integers, ref int swap) //swap method, swaps the position of 2 elements
{
swap++;
int temporary = (int)Integers[x]; //essentially will swap the min with the current position
Integers[x] = Integers[y];
Integers[y] = temporary;
}
There are no "rules" about recursion that say you cannot use loops in the recursive method body. The only rule in recursion is that the function has to call itself, which your second code snippet does, so DoSelectionSortRecursive is legitimately recursive.
For example, merge sort uses recursion for splitting the array and loops for merging the sorted subarrays. It'd be wrong to call it anything but a recursive function, and it'd be somewhat silly to implement the merging stage (an implementation detail of merge sort) recursively -- it'd be slower and harder to reason about, so loops are the natural choice.
On the other hand, the splitting part of merge sort makes sense to write recursively because it chops the problem space down by a logarithmic factor and has multiple branches. The repeated halving means it won't need to make more than a few or a dozen recursive calls on a typical array. These calls don't incur much overhead and fit well within the call stack.
On the other hand, the call stack can easily blow for linear recursive algorithms in languages without tail-call optimization like C# where each index in the linear structure requires a whole stack frame.
Rules prohibiting loops are concoted by educators who are trying to teach recursion by forcing you to use a specific approach in your solution. It's up to your instructor to determine whether one or both loops need to be converted to recursion for it to "count" as far as the course is concerned. (apologies if my assumptions about your educational arrangement are incorrect)
All that is to say that this requirement to write a nested-loop sort recursively is basically a misapplication of recursion for pedagogical purposes. In the "real world", you'd just write it iteratively and be done with it, as Google does in the V8 JavaScript engine, which uses insertion sort on small arrays. I suspect there are many other cases, but this is the one I'm most readily familiar with.
The point with using simple, nested loop sorts in performance-sensitive production code is that they're not recursive. These sorts' advantage is that they avoid allocating stack frames and incurring function call overhead to sort small arrays of a dozen numbers where the quadratic time complexity isn't a significant factor. When the array is mostly sorted, insertion sort in particular doesn't have to do much work and is mostly a linear walk over the array (sometimes a drawback in certain real-time applications that need predictable performance, in which case selection sort might be preferable -- see Wikipedia).
Regarding ArrayLists, the docs say: "We don't recommend that you use the ArrayList class for new development. Instead, we recommend that you use the generic List<T> class." So you can basically forget about ArrayList unless you're doing legacy code (Note: Java does use ArrayLists which are more akin to the C# List. std::list isn't an array in C++, so it can be confusing to keep all of this straight).
It's commendable that you've written your sort iteratively first, then translated to recursion on the outer loop only. It's good to start with what you know and get something working, then gradually transform it to meet the new requirements.
Zooming out a bit, we can isolate the role this inner loop plays when we pull it out as a function, then write and test it independent of the selection sort we hope to use it in. After the subroutine works on its own, then selection sort can use it as a black box and the overall design is verifiable and modular.
More specifically, the role of this inner loop is to find the minimum value beginning at an index: int IndexOfMin(List<int> lst, int i = 0). The contract is that it'll throw an ArgumentOutOfRangeException error if the precondition 0 <= i < lst.Count is violated.
I skipped the metrics variables for simplicity but added a random test harness that gives a pretty reasonable validation against the built-in sort.
using System;
using System.Collections.Generic;
using System.Linq;
class Sorter
{
private static void Swap(List<int> lst, int i, int j)
{
int temp = lst[i];
lst[i] = lst[j];
lst[j] = temp;
}
private static int IndexOfMin(List<int> lst, int i = 0)
{
if (i < 0 || i >= lst.Count)
{
throw new ArgumentOutOfRangeException();
}
else if (i == lst.Count - 1)
{
return i;
}
int bestIndex = IndexOfMin(lst, i + 1);
return lst[bestIndex] < lst[i] ? bestIndex : i;
}
public static void SelectionSort(List<int> lst, int i = 0)
{
if (i < lst.Count)
{
Swap(lst, i, IndexOfMin(lst, i));
SelectionSort(lst, i + 1);
}
}
public static void Main(string[] args)
{
var rand = new Random();
int tests = 1000;
int lstSize = 100;
int randMax = 1000;
for (int i = 0; i < tests; i++)
{
var lst = new List<int>();
for (int j = 0; j < lstSize; j++)
{
lst.Add(rand.Next(randMax));
}
var actual = new List<int>(lst);
SelectionSort(actual);
lst.Sort();
if (!lst.SequenceEqual(actual))
{
Console.WriteLine("FAIL:");
Console.WriteLine($"Expected => {String.Join(",", lst)}");
Console.WriteLine($"Actual => {String.Join(",", actual)}\n");
}
}
}
}
Here's a more generalized solution that uses generics and CompareTo so that you can sort any list of objects that implement the IComparable interface. This functionality is more akin to the built-in sort.
using System;
using System.Collections.Generic;
using System.Linq;
class Sorter
{
public static void Swap<T>(List<T> lst, int i, int j)
{
T temp = lst[i];
lst[i] = lst[j];
lst[j] = temp;
}
public static int IndexOfMin<T>(List<T> lst, int i = 0)
where T : IComparable<T>
{
if (i < 0 || i >= lst.Count)
{
throw new ArgumentOutOfRangeException();
}
else if (i == lst.Count - 1)
{
return i;
}
int bestIndex = IndexOfMin(lst, i + 1);
return lst[bestIndex].CompareTo(lst[i]) < 0 ? bestIndex : i;
}
public static void SelectionSort<T>(List<T> lst, int i = 0)
where T : IComparable<T>
{
if (i < lst.Count)
{
Swap(lst, i, IndexOfMin(lst, i));
SelectionSort(lst, i + 1);
}
}
public static void Main(string[] args)
{
// same as above
}
}
Since you asked how to smush both of the recursive functions into one, it's possible by keeping track of both i and j indices in the parameter list and adding a branch to figure out whether to deal with the inner or outer loop on a frame. For example:
public static void SelectionSort<T>(
List<T> lst,
int i = 0,
int j = 0,
int minJ = 0
) where T : IComparable<T>
{
if (i >= lst.Count)
{
return;
}
else if (j < lst.Count)
{
minJ = lst[minJ].CompareTo(lst[j]) < 0 ? minJ : j;
SelectionSort(lst, i, j + 1, minJ);
}
else
{
Swap(lst, i, minJ);
SelectionSort(lst, i + 1, i + 1, i + 1);
}
}
All of the code shown in this post is not suitable for production -- the point is to illustrate what not to do.
So Ive been trying to compare given double values in an array with eachother to return the smallest one, but the way I do it does not seem to work consistently and very efficient. Im feeling lost.
public static double FindSmallestNum(double[] arr)
{
double max = 0;
for (int x=0;x<arr.Length-1;x++){
if ( arr[x]>= arr[x+1]){
if (max >= arr[x+1]){
max = arr[x+1];
}
}
else if (max >=arr[x]){
max = arr[x];
}
else {
max = arr[x];
}
}
return max;
}
If you are willing to use System.Linq (which it appears that you are, given the accepted answer), then you may as well just go straight to the Min() method:
public static double FindSmallestNum(double[] arr)
{
return arr.Min();
}
Although, given that it's a simple one-line method call, it's not clear that a helper method is really all that helpful in this case.
Problems with your code
In your sample code, it appears that the problem is that you set max = 0; (why do you call it max instead of min?) and then start doing comparisons to see if max is larger than items in the array. This can be problematic, since all positive numbers will be larger than max, so they will never be considered.
To fix this, first let's rename that variable to min, so we remember what we're doing, and then set it to the first value in the array. This way we know we're dealing with a number in our array, and all comparisons will be valid.
Next, we don't need to compare each item with the next item - that comparison is not relevant to finding the smallest of all the items. We only need to compare each item to the current value of min (and do the necessary reassignment if we find a lower number).
This would reduce the code to something like:
public static double FindSmallestNum(double[] input)
{
if (input == null) throw new ArgumentNullException(nameof(input));
if (input.Length == 0)
throw new InvalidOperationException("array contains no elements");
// Start with the first number
double smallest = input[0];
// Now compare the rest of the items with 'smallest'
for (int index = 1; index < input.Length; index++)
{
if (input[index] < smallest) smallest = input[index];
}
return smallest;
}
Your code can further be optimized. you can see the below logic. Complexity of this code is O(N)
static void GetSmallest(int[] arr)
{
int first, arr_size = arr.Length;
first = int.MaxValue;
for (int i = 0; i < arr_size; i++)
{
if (arr[i] < first)
{
first = arr[i];
}
}
}
You can use the below code also.
int[] arr = new int[5] { 1, 2, 3, 4, 5 };
int min = arr.Min();
Just use Linq:
var min = arr.OrderBy(v => v).FirstOrDefault();
min will be the smallest number in your array.
I want to sort a char array as efficiently as possible, i.e. with minimal CPU usage, memory allocs and garbage collection overhead. My naive first attempt is this simple example:
Assume the array already exists, e.g.
char[] word = "hello world".ToCharArray();
Optimise this naive approach:
Array.Sort(word, StringComparer.Ordinal);
Actually I was surprised this worked since it's using a string comparer to compare chars, so I'm suspecting there is a conversion from char to string going on inside the comparer, which would be sub-optimal in terms of CPU usage and garbage collection, etc.
Assuming I wanted to perform this sort as efficiently as possible, what is the best approach?
Right now my fall-back is to use something like:
List<char> wordChars = "hello world".ToList();
wordChars.Sort((char x, char y) =>
{
return (int)x - (int)y;
});
I'd prefer not to have the overhead of a List for each word though. The other option is to write my own quicksort routine!
P.S. To pre-empt the usual barrage of challenges - Yes I really do want to sort a char array by code point, and yes I do need to make it optimal!! The faster the better. Thanks!
For the record here is a strongly typed char quick sort...
public static class CharSort
{
public static void QuickSort(char[] arr)
{
QuickSort(arr, 0, arr.Length - 1);
}
private static void QuickSort(char[] arr, int left, int right)
{
do
{
int p = left;
int q = right;
char val = arr[p + (q - p >> 1)];
do
{
if(p < arr.Length)
{
if(val - arr[p] > 0)
{
p++;
continue;
}
}
while (q >= 0 && (val - arr[q] < 0))
{
q--;
}
if(p > q) {
break;
}
if(p < q)
{
char num3 = arr[p];
arr[p] = arr[q];
arr[q] = num3;
}
p++;
q--;
}
while(p <= q);
if(q - left <= right - p)
{
if(left < q) {
QuickSort(arr, left, q);
}
left = p;
}
else
{
if(p < right) {
QuickSort(arr, p, right);
}
right = q;
}
}
while(left < right);
}
}
List.Sort is probably better than what you will be able to write in a short time, it works like this [see]:
If the partition size is fewer than 16 elements, it uses an insertion
sort algorithm.
If the number of partitions exceeds 2 * LogN, where N is the range of
the input array, it uses a Heapsort algorithm.
Otherwise, it uses a Quicksort algorithm.
I imagine it might be faster to simply count the occurrence of each character, but this can get tricky with Unicode code points (surrogate pairs). If all you are concerned with is common English characters (ASCII range), you can just allocate an array the size of the range of characters (127), loop thru the string using the character value as the index and increment. If you really need the actual string you can reconstitute it by creating a string buffer and filling it with the counts of each non-zero character count, in index order.
One thing worth mentioning is you need to ask yourself what is "fast enough". Clearly, there is a reason you feel that "string".ToArray().Sort() isn't fast enough. That might indicate that an approach other than a sort might be needed. Hard to say given the limited details.
I had an interview question to write a program in C# that Outputs odd number of occurrences in an array.
Example: [2, 2, 3, 3, 3] => [3] (Considering the array is sorted)
My solution was:
public list<int> OddOccurance(list<int> InputList)
{
list<int> output = new list<int>();
for(int i=0; i<InputList.length; i++)
{
int Count = 0;
for(int j=1; j<(InputList.length-1); j++)
{
if(InputList[i] == InputList[j])
{
Count++;
}
}
if(Count % 2 != 0)
{
output.add(InputList[i]);
}
}
return output.distinct();
}
I am thinking the answer is correct only but the interviewer had asked me like different ways of how I can make the solution much faster.
Can anyone please tell me the time complexity of the above solution please.
If there is a way to make the above solution much faster then what can be the time complexity of that solution.
Your solution is O(n^2) - if you don't know why - evaluate sum:
This is an equation which describes the running time of your algorithm. You can solve it in linear time easily - just increment i instead of inner loop over all values in array.
for (int i=0; i<InputList.Length; ++i)
{
int currentValue = InputList[i];
int j=i+1;
int count = 1;
while (InputList[j] == currentValue && j<InputList.Length)
{
count++;
i++;
j++;
}
if (count % 2 == 0)
..
}
If array is not sorted - use dictionary (hash table - Dictionary in C#) - value is a dictionary key, count is a dictionary value. (that will give you Contains key check in O(1)) Another way to get linear time if implemented properly.
The root problem of your solution is seen on this line:
return output.Distinct();
The very fact that you are doing a Distinct means that you may be adding more entries than you should.
So how can you optimize it? Observe that since the array is sorted, the only place where you can find a number that's the same as the one you're looking at is next to it, or next to another number that's equal to your current number. In other words, your numbers go in "runs".
This observation lets you go from two nested loops and an O(N2) solution to a single loop and an O(N) solution. Simply walk the array, and check lengths of each "run": when you see a new number, store its index. If you come across a new number, see if the length of the "run" is odd, and start a new run:
int start = 0;
int pos = 1;
while (pos < InputList.Length) {
if (InputList[pos] != InputList[start]) {
if ((pos-start) % 2 == 1) {
output.Add(InputList[start]);
}
start = pos;
}
pos++;
}
// Process the last run
if ((InputList.Length-start) % 2 == 1) {
output.Add(InputList[start]);
}
Demo.
I'm trying to create a "lookup" column that would return the index of the array value that is equal to or less than the value being looked up. So this is my attempt, which seems to work fine, but I was wondering if there is a cleaner way of doing it ?
// Sorted
float[] ranges = new float[]
{
0.8f,
1.1f,
2.7f,
3.9f,
4.5f,
5.1f,
};
private int GetIndex(float lookupValue)
{
int position = Array.BinarySearch(ranges, lookupValue);
if (position < 0)
{
// Find the highest available value that does not
// exceed the value being looked up.
position = ~position - 1;
}
// If position is still negative => all values in array
// are greater than lookupValue, return 0
return position < 0 ? 0 : position;
}
Thanks.
Nope, I think this is a pretty good approach.
The only thing I might change is to make it an extension method on arrays, instead of a private function referring to a class variable. Then it becomes general / not tied to one class, and the syntax is cleaner too: ranges.GetIndex(...)
Something like this:
public static class Extensions
{
public static int GetIndex<T>(this T[] ranges, T lookupValue)
{
// your code here
}
}
Of course, you'll have to remember this only works on sorted arrays...
You could use a normal for loop (assuming your data is ordered). Not sure if it's cleaner, but certainly not as effective on lots of data. Personally I would go for the BinarySearch you have.
int GetIndex(IList<float> ranges, float target)
{
for (int i = 0; i < ranges.Count; i++)
{
if(ranges[i] < target) continue;
if (ranges[i] >= target) return i;
}
return 0;
}