Binary search on list - c#

I have the following code which fetches a country ID based on the IP address:
countryID = GetAllCountryIPRanges().Single(c => c.BeginIPNum <= intIp && intIp <= c.EndIPNum).CountryID;
It's unfortunately quite slow as there's ~200,000 records. The ranges do not overlap, and GetAllCountryIPRanges() is in ascending order by BeginIPNum.
How do I implement .BinarySearch() on this list to find the correct record?

List has a binary search method but since binary search is so easy to implement and since the IComparator you would need to define is so complex due to the range thing I suggest you implement the binary search method
Something like this (NOT TESTED!)
public static IPRange BinarySearch(List<IPRange> source, int intIp)
{
int startIndex = 0;
int endIndex = source.Count;
while (endIndex >= startIndex)
{
int middleIndex = startIndex + (endIndex - startIndex) / 2;
if (source[middleIndex].BeginIPNum <= intIp && intIp <= source[middleIndex].EndIPNum)
{
return source[middleIndex];
}
else if (source[middleIndex].BeginIPNum < intIp)
{
startIndex = middleIndex + 1;
}
else
{
endIndex = middleIndex - 1;
}
}
return null;
}
Assuming the List is sorted and there are no overlapping ranges.

Gotta love the elegance of recursion... (not tested)
public static IPRange BinarySearch(IList<IPRange> ipList, int ip)
{
return BinarySearch(source, ip, 0, ipList.Count - 1);
}
public static IPRange BinarySearch(IList<IPRange> ipList, int ip, int min, int max)
{
if (min > max)
{
throw new Assertion("Error: ipList is empty, out-of-order, or does not contain an element that includes the IP");
}
int mid = (min + max) / 2;
var midIp = ipList[mid];
if (ip < midIp.BeginIpNum)
{
return BinarySearch(ipList, ip, min, mid-1);
}
if (ip > midIp.EndIpNum)
{
return BinarySearch(ipList, ip, mid+1, max);
}
return midIp;
}

Related

Recursive - stack overflow error

Given an unsorted array find the max and min values. I'm trying to do this in a recursive, divide and conquer way but I keep getting a stack overflow error. I debugged and i keep getting the error in my recursive calls but do not know what is wrong or how to fix it.
I do have static min and max variables.
Thanks for the information and help!
static void findMaxMin(int[] array, int start, int end)
{
if (end == 2)
{
setMaxMin(array);
}
else
{
int mid = ((end) / 2);
findMaxMin(array, start, mid);
findMaxMin(array, mid + 1, end);
}
}
private static void setMaxMin(int[] array)
{
if (array[0] > array[1])
{
max = array[0];
min = array[1];
}
else
{
min = array[0];
max = array[1];
}
}
Here is one simple way to do it (without recursion):
void FindMinAndMaxValues(int[] array out int min, out int max)
{
min = int.MaxValue,
max = int.MinValue;
foreach(var val in array)
{
max = (val > max) ? val : max;
min = (val < min) ? val : min;
}
}
Please note that I'm using out parameters here. This is done for simplicity of the code. Usually, I would prefer to either return a designated class or a tuple.
Also, LINQ has min and max extension methods that you can use - so the entire thing turns to something like this:
var max = array.Max();
var min = array.Min();

What Data Structure is the best suited for working with Search algorithms?

I have a task where I need to implement a fully written Search algorithm to search according to the content of the Month and display all of the corresponding data from different data files.
What Data Structure is best suited to store my data so that I can:
Apply Binary Search algorithm on it.
Store the data in a corresponding way.
Take a look at how my Data is currently stored in the Array:
And this is what I'm aiming for:
As you can see from the After image I edited quotation marks around the Months column, this is to make it clear that I want to search the data according to the content of the Month. (e.g. When I use the algorithm to search for all the "January" Months all the January values get printed out along with their corresponding data).
I am trying to store the data with these conditions:
The values from different arrays still correspond to eachother.
I am able to apply Search algorithm on the data and search corresponding data according to the content of the Month.
It's really hard for me to word this problem in a concise, easy to understand way, I hope this is not too confusing. I've been struggling with this problem for dozens of hours and can't seem to find a solution from anywhere.
This is how I store my arrays:
//Read in the files and put them into arrays.
String[] Years = File.ReadAllLines(#"Data\Year_1.txt");
String[] Months = File.ReadAllLines(#"Data\Month_1.txt");
String[] Days = File.ReadAllLines(#"Data\Day_1.txt");
String[] Times = File.ReadAllLines(#"Data\Time_1.txt");
String[] Depths = File.ReadAllLines(#"Data\Depth_1.txt");
String[] Latitudes = File.ReadAllLines(#"Data\Latitude_1.txt");
String[] Longitudes = File.ReadAllLines(#"Data\Longitude_1.txt");
String[] Magnitudes = File.ReadAllLines(#"Data\Magnitude_1.txt");
String[] Regions = File.ReadAllLines(#"Data\Region_1.txt");
String[] IRIS_IDs = File.ReadAllLines(#"Data\IRIS_ID_1.txt");
String[] Timestamps = File.ReadAllLines(#"Data\Timestamp_1.txt");
//Creating an array of months and adding corresponding data from other arrays.
string[] MonthsArray = new string[Days.Length];
//Since all files have same number of items, using any array.Length will iterate through all the items.
for (int i = 0; i < Days.Length; i++)
{
MonthsArray[i] = string.Format("{0,10} {1,6} {2,6} {3,9} {4,7} {5,7} {6,7} {7,7} {8,29} {9,9} {10,9}", Months[i], Years[i], Days[i], Times[i], Magnitudes[i], Latitudes[i], Longitudes[i], Depths[i], Regions[i], IRIS_IDs[i], Timestamps[i]);
}
//Creating an array of Years and adding corresponding data from other arrays.
string[] YearsArray = new string[Days.Length];
//Since all files have same number of items, using any array.Length will iterate through all the items.
for (int i = 0; i < Days.Length; i++)
{
YearsArray[i] = string.Format("{0,6} {1,10} {2,6} {3,9} {4,7} {5,7} {6,7} {7,7} {8,29} {9,9} {10,9}", Years[i], Months[i], Days[i], Times[i], Magnitudes[i], Latitudes[i], Longitudes[i], Depths[i], Regions[i], IRIS_IDs[i], Timestamps[i]);
}
This is my Binary Search algorithm which counts the occurrences of duplicates so that I can print out all the searched values:
public static int Binary_Search<T>(T[] data, int n, T Search, bool searchFirst, Comparer<T> comparer)
{
int low = 0;
int high = n - 1;
int result = -1;
while (low <= high)
{
int mid = (low + high) / 2;
if (comparer.Compare(data[mid], Search) == 0)
{
result = mid;
if (searchFirst)
high = mid - 1;
else
low = mid + 1;
}
else if (comparer.Compare(Search, data[mid]) < 0)
high = mid - 1;
else
low = mid + 1;
}
return result;
}
This is how I perform the Binary Search on already sorted array and display the searched values:
Console.WriteLine("\nEnter the name of the Month to display all the seismic Data in that month.");
Console.Write("Month: \n");
var Search1 = Console.ReadLine();
int firstIndex1 = Binary_Search(MonthsArray, MonthsArray.Length, Search1, true, Comparer<string>.Default);
if (firstIndex1 == -1)
{
Console.WriteLine("Count of {0} is {1}", Search1, 0);
}
else
{
int lastIndex = Binary_Search(MonthsArray, MonthsArray.Length, Search1, false, Comparer<string>.Default);
//Count the occurrence of duplicate elements and display the searched value per each occurrence.
int occurence = lastIndex - firstIndex1 + 1;
for (int i = 0; i < occurence; i++)
{
Console.WriteLine(MonthsArray);
}
Console.WriteLine("Number of searched items found in the array: {0}", occurence);
}
break;
}
break;
Class for the Data with their corresponding data types.
public class SeismicData
{
public int Year { get; set; }
public string Month { get; set; }
public int Day { get; set; }
public double Time { get; set; }
public double Depth { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Magnitude { get; set; }
public string Region { get; set; }
public int IRIS_ID { get; set; }
public int TimeStamp { get; set; }
}
My QuickSort Algorithm:
//QuickSort method for ascending arrays. Takes in any data type array and sorts it.
public static void QuickSort<T>(T[] data)
{
Quick_Sort(data, 0, data.Length - 1, Comparer<T>.Default);
}
//Second QuickSort method for case 2 for Descending the array.
public static void QuickSort<T>(T[] data, Comparer<T> comparer)
{
Quick_Sort(data, 0, data.Length - 1, comparer);
}
//QuickSort algorithm using comparer
public static void Quick_Sort<T>(T[] array, int left, int right, Comparer<T> comparer)
{
int i, j;
T pivot, temp;
i = left;
j = right;
pivot = array[(left + right) / 2];
do
{
while ((comparer.Compare(array[i], pivot) < 0) && (i < right)) i++;
while ((comparer.Compare(pivot, array[j]) < 0) && (j > left)) j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (left < j) Quick_Sort(array, left, j, comparer);
if (i < right) Quick_Sort(array, i, right, comparer);
}

C# Get Binary Search To Display All Duplicate Values In Array

If I search through my sorted array it only displays one of the values even if there are multiple of the same value in the array. I don't want it to tell me how many duplicates there are, I want it to display all of the duplicate values in the array that I search for. Or is there are different search I need to use to do this?
So if I have array1{1,2,3,4,4,5,5,5,5,6} and I search for 5 I want it to output:
5
5
5
5
This is is my code with binary search.
public class search
{
public static void Main(string[] args)
{
//Arrays are created here. e.g. array1{1,2,3,4,4,5,5,5,5,6}
int Input;
Console.WriteLine("Enter the number you would like to search for.");
Input = Convert.ToInt32(Console.ReadLine());
int y = BinarySearch(array1, Input);
Console.WriteLine("array1 {0} : array2{1} : array3 {2} : array4 {3} : array5 {4}",array1[y], array2[y], array3[y], array4[y], array5[y]);
}
public static int BinarySearch(double[] Array, int Search)
{
int x = Array.Length;
int low = 0;
int high = x - 1;
while (low <= high)
{
while (low <= high)
{
int mid = (low + high) / 2;
if (Search < Array[mid])
{
high = mid - 1;
}
else if (Search > Array[mid])
{
low = mid + 1;
}
else if (Search == Array[mid])
{
Console.WriteLine("{0}", Search);
return mid;
}
}
Console.WriteLine("{0} was not found.", Search);
}
return high;
}
}
Sure, you can use binary search for this. But your code is kinda weird. Because when you find the first element here else if (Search == array[mid]) ... you immediately return from the function and never call it again. That is why you get only one result.
To make it work, when you find such element, you need to search in the array through indices low ... mid-1 and then through indices mid+1 ... high.
Here is the code, but I strongly advise you not just to copy that and maybe try to rewrite this into while loop (every recursion can be rewritten as a loop)
static void BinarySearch(int[] array, int low, int high, int searchedValue)
{
if (low > high)
return;
int mid = (low + high) / 2;
if (searchedValue < array[mid])
{
high = mid - 1;
BinarySearch(array, low, high, searchedValue);
}
else if (searchedValue > array[mid])
{
low = mid + 1;
BinarySearch(array, low, high, searchedValue);
}
else if (searchedValue == array[mid])
{
Console.WriteLine(array[mid]);
BinarySearch(array, low, mid - 1, searchedValue);
BinarySearch(array, mid + 1, high, searchedValue);
}
}

Looking up values based on range data

What data structure or datatype would be good for holding data ranges, and return a value based on data that lies in that range?
For example suppose I have the following ranges
1-10 -> 1
11-35 -> 2.5
36-49-> 3.8
50-60 -> 1.2
61-80 -> 0.9
In this case given the number 41 I would want the number 3.8 returned (as 41 is between the ranges of 36 and 49).
Is there a clever way of representing such data in a datastructure in order to perform this lookup?
A comparatively convenient and very performant implementation would be to use a SortedList<int, Tuple<int, double>>. Use the lower bound for each segment as the key and a tuple of upper bound + mapped value for the value:
var list = new SortedList<int, Tuple<int, double>>
{
{ 1, Tuple.Create(10, 1.0) },
{ 11, Tuple.Create(35, 2.5) },
};
(Of course you could decide to use a better-looking data structure to declare your parameters in order to enhance code maintainability and internally convert to this before getting down to business).
Since list.Keys is guaranteed to be sorted, when looking up a value you can use binary search on it to find the index that is equal to or greater than your input value:
var index = list.Keys.BinarySearch(value);
if (index < 0 && ~index == 0) {
// no match, stop processing
}
else if (index < 0) {
// key not found as is, look at the previous interval
index = ~index - 1;
}
At this point index points at the only range that might include value, so all that remains is to test for that:
if(x >= list.Keys[index] && x <= list.Values[index].Item1) {
var result = list.Values[index].Item2;
}
else {
// no match
}
You wouldn't call this "clean", but it's very short and very fast.
You can use this code
Key :
public class Interval<T> where T : IComparable
{
public Nullable<T> Start { get; set; }
public Nullable<T> End { get; set; }
public Interval(T start, T end)
{
Start = start;
End = end;
}
public bool InRange(T value)
{
return ((!Start.HasValue || value.CompareTo(Start.Value) > 0) &&
(!End.HasValue || End.Value.CompareTo(value) > 0));
}
}
value : decimal
And you can use this Type : Dictionary<Interval, decimal>
Nota : you can define access methods
It took me a while but I have a QuickAndDirty method which assumes all given values are valid and ranges are adjacent, without using any data structures.
And a very specific data structure which will only return something if the given index is exactly in the specified range and which can be expanded at run-time.
public abstract class TreeNode
{
public static double QuickAndDirty(int index)
{
double result = 1.0;
if (index > 10)
result = 2.5;
if (index > 35)
result = 3.8;
if (index > 49)
result = 1.2;
if (index > 60)
result = 0.9;
return result;
}
public abstract double GetValue(int index);
public abstract TreeNode AddRange(int begin, int end, double value);
public static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges)
{
return TreeNode.MakeTreePart(ranges, 0, ranges.Length >> 1, ranges.Length - 1);
}
private static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges, int min, int index, int max)
{
if (index == min || index == max)
return new Leaf(ranges[index].Item1, ranges[index].Item2, ranges[index].Item3);
return new SegmentTree(
ranges[index].Item2 + .5,
TreeNode.MakeTreePart(ranges, min, index >> 1, index - 1),
TreeNode.MakeTreePart(ranges, index + 1, index << 1, max));
}
}
public class SegmentTree : TreeNode
{
private double pivot;
private TreeNode left, right;
public SegmentTree(double pivot, TreeNode left, TreeNode right)
{
this.pivot = pivot;
this.left = left;
this.right = right;
}
public override double GetValue(int index)
{
if (index < pivot)
return left.GetValue(index);
return right.GetValue(index);
}
public override TreeNode AddRange(int begin, int end, double value)
{
if (end < pivot)
this.left = this.left.AddRange(begin, end, value);
else
this.right = this.right.AddRange(begin, end, value);
// Do this to confirm to the interface.
return this;
}
}
public class Leaf : TreeNode
{
private int begin, end;
private double value;
public Leaf(int begin, int end, double value)
{
this.begin = begin;
this.end = end;
this.value = value;
}
public override double GetValue(int index)
{
if (index >= begin && index <= end)
return value;
throw new Exception("index out of range");
}
public override TreeNode AddRange(int begin, int end, double value)
{
if (this.end < begin)
return new SegmentTree(((double)this.end + begin) * .5, this, new Leaf(begin, end, value));
else if (end < this.begin)
return new SegmentTree(((double)end + this.begin) * .5, new Leaf(begin, end, value), this);
else throw new Exception("Indexes overlap.");
}
}
static void Main()
{
TreeNode start = new Leaf(36, 49, 3.8);
start = start.AddRange(11, 35, 2.5);
start = start.AddRange(1, 10, 1.0);
start = start.AddRange(50, 60, 1.2);
start = start.AddRange(61, 80, 0.9);
double[] values = new double[70];
for (int i = 1; i < values.Length; i++)
values[i] = start.GetValue(i);
TreeNode array = TreeNode.MakeTreePart(
new Tuple<int, int, double>[]
{
Tuple.Create(1, 10, 1.0),
Tuple.Create(11, 35, 2.5),
Tuple.Create(36, 49, 3.8),
Tuple.Create(50, 60, 1.2),
Tuple.Create(61, 80, 0.9)
});
for (int i = 1; i < values.Length; i++)
values[i] = start.GetValue(i);
}

Bubble sort using recursion in C#

I've wrote this simple piece of code. And I have a slight problem with it.
int [] x = [50,70,10,12,129];
sort(x, 0,1);
sort(x, 1,2);
sort(x, 2,3);
sort(x, 3,4);
for(int i = 0; i < 5; i++)
Console.WriteLine(x[i]);
static int [] sort(int [] x, int i, int j)
{
if(j ==x.length)
return x;
else if(x[i]>x[j])
{
int temp = x[i];
x[i] = x[j];
x[j] = temp;
return sort(x, i, j+1);
}
else
return sort(x, i, j+1);
}
I feel that calling sort 4 time isn't the best soultion. I need a way to handle this using sort() also. I also ask you for your advice, suggestion, or tip.
Thanks
Firstly, your sort is restricted to ints, however you can use the IComparable<T> interface to extend it to any comparable type. Alternatively you could have another parameter for a Comparer<T> to allow the user to define how to compare items in the input.
A recursive bubble sort would probably look something like this: (NOTE: not tested...)
public static T[] BubbleSort(T[] input) where T : IComparable<T>
{
return BubbleSort(input, 0, 0);
}
public static T[] BubbleSort(T[] input, int passStartIndex, int currentIndex) where T : IComparable<T>
{
if(passStartIndex == input.Length - 1) return input;
if(currentIndex == input.Length - 1) return BubbleSort(input, passStartIndex+1, passStartIndex+1);
//compare items at current index and current index + 1 and swap if required
int nextIndex = currentIndex + 1;
if(input[currentIndex].CompareTo(input[nextIndex]) > 0)
{
T temp = input[nextIndex];
input[nextIndex] = input[currentIndex];
input[currentIndex] = temp;
}
return BubbleSort(input, passStartIndex, currentIndex + 1);
}
However, an iterative solution would probably be more efficient and easier to understand...
A simple bubblesort shouldn't need recursion. You could do something like this, just passing in the array to sort:
public int[] Sort(int[] sortArray)
{
for (int i = 0; i < sortArray.Length - 1; i++)
{
for (int j = sortArray.Length - 1; j > i; j--)
{
if (sortArray[j] < sortArray[j - 1])
{
int x = sortArray[j];
sortArray[j] = sortArray[j - 1];
sortArray[j - 1] = x;
}
}
}
return sortArray;
}
Nothing wrong with wanting to learn - couple of obvious things.
Firstly you're already aware that there's a length property for the array - so you could use that to create a loop that gets rid of the multiple calls to sort at the start and makes the length of the array a non problem.
Secondly you might want to think about the way the sort works - how about this: you're attempting to bubble a value up to its correct place in the list (or down if you prefer!) - so for a list of n items, remove the first, sort the remaining n - 1 items (that's the recursive bit) then bubble the first item into place.
Been decades since I thought about this, fun!
another one with only 2 params :p yeah :
static void Sort(IList<int> data)
{
Sort(data, 0);
}
static void Sort(IList<int> data, int startIndex)
{
if (startIndex >= data.Count) return;
//find the index of the min value
int minIndex = startIndex;
for (int i = startIndex; i < data.Count; i++)
if (data[i] < data[minIndex])
minIndex = i;
//exchange the values
if (minIndex != startIndex)
{
var temp = data[startIndex];
data[startIndex] = data[minIndex];
data[minIndex] = temp;
}
//recurring to the next
Sort(data, startIndex + 1);
}
Note : This is completly useless in real life because
- its extremely slow
- its recursion iteration is linear meaning that when you have more than 1k items, it will stackoverflow

Categories