Another problem here!
I've been coding a Binary Search with recursive algorithm.
Now it seems to be some problem when it search in upper half of the array. I can't really find whats wrong.
//=====Binary Search=====//
static int BinarySearch(City[] cities, int key, int low, int high)
{
int mid;
if (low > high)
{
return -1;
}
mid = low + high / 2;
if (key == cities[mid].temp)
{
return mid;
}
else if (key < cities[mid].temp)
{
return BinarySearch(cities, key, low, mid - 1);
}
else
{
return BinarySearch(cities, key, mid +1, high);
}
}
When I search for a number that can't be found it will print: "can't find temperature".
It is doing its work as long as I don't search for a number in the upper half.
Console.WriteLine("\n\tBINÄR SÖKNING\n");
do
{
loop = true;
Console.Write("search temperature:");
str = Console.ReadLine();
try
{
key = Convert.ToInt32(str);
index = BinarySearch(cities, key, low, high);
if (index == -1)
{
Console.WriteLine($"can't find temperature: {key}°C");
}
else
{
Console.WriteLine("");
Console.WriteLine(cities[index].ToString());
loop = false;
}
}
catch
{
Console.WriteLine("Only numbers, please");
}
} while (loop);
If I search for a number in the upper half, the console will print "Only numbers, please". It goes to the catch-part. as it should if I search for something that can NOT convert to int.
Operator precedence bites again.
How is the expression low + high / 2 parsed?
Probably not the way you think. Multiplicative operators have higher precedence than additive operators, so
low + high / 2
gets parsed as
low + (high / 2)
rather than your intended
(low + high) / 2
Related
I keep getting an "int cannot convert to bool" error at if(number % NUMINROW), and I do not know how to fix it. I am fairly new to C#, but I know Python and how for loops work, but I am still confused.
// Program displays every possible ID number for a company
// ID number is a letter, followed by a two-digit number
// For example -- A00 or Z99
// Go to a new display line after every 20 IDs
using static System.Console;
class DebugFive3
{
static void Main()
{
char letter;
int number;
const int LOW = 0;
const int HIGH = 99;
const int NUMINROW = 20;
for(letter = 'A'; letter <= 'Z'; ++letter)
for(number = LOW; number >= HIGH; ++number)
{
if(number % NUMINROW)
WriteLine();
Write("{0}{1} ", letter, number.ToString("D2"));
}
}
}
You have error on second for and in condition if(number % NUMINROW)
static void Main(string[] args)
{
char letter;
int number;
const int LOW = 0;
const int HIGH = 99;
const int NUMINROW = 20;
for (letter = 'A'; letter <= 'Z'; ++letter)
{
for (number = LOW; number <= HIGH; ++number)
{
if (number % NUMINROW == 0)
Console.WriteLine();
else
Console.Write("{0}{1} ", letter, number.ToString("D2"));
}
}
Console.ReadLine();
}
The reason you're getting that compile error is that number % NUMINROW returns the remainder after dividing number by NUMINROW, which is an int, whereas an if condition must return a bool (and there is no implicit conversion from int to bool in C#).
One way to fix this is to modify the condition so that it compares the result of the modulus operation to another int, for example:
if(number % NUMINROW == 0)
Other Issues
There is no Console.ReadLine() at the end of the Main method, so as soon as the data is displayed, the console window will dissapear. Adding this line will pause execution until the user presses the Enter key, giving them time to see the data.
This condition is incorrect: number = LOW; number >= HIGH. It reads, "set number to LOW, then loop while number is greater than or equal to HIGH." That condition will never be true!! We should use <= instead.
The current code is completely ignoring the 20th column. To solve this, we can remove the else clause and switch the order of the code lines so that we always write the value, and then conditionally add a new line.
Assuming we want NUMINROW columns displayed, our modulus condition should compare the next number to this value, since we're starting at 0 (so the first row would be 0-19, followed by 20-39). Another reason to add one to the value before doing the comparison is that 0 modulus any number is 0, so we would have an extra new line before the first item (where number is 0).
Not a problem, really, but since we don't use the variables letter or number outside the loops, it's generally better to declare them as part of the for loop itself, to reduce their scope.
Here's a sample of how to solve these issues:
static void Main(string[] args)
{
const int LOW = 0;
const int HIGH = 99;
const int NUMINROW = 20;
for (char letter = 'A'; letter <= 'Z'; letter++)
{
for (int number = LOW; number <= HIGH; number++)
{
Write("{0}{1} ", letter, number.ToString("D2"));
if ((number + 1) % NUMINROW == 0) WriteLine();
}
}
ReadLine(); // Wait for user input
}
Output
As a side note, here's a fun little sample using System.Linq that does it all in one line (not recommended, since it's hard to read/debug, but thought it might be interesting):
const int LOW = 0;
const int HIGH = 99;
const int NUMINROW = 20;
WriteLine(string.Concat(Enumerable.Range('A', 26)
.Select(chr => string.Concat(Enumerable.Range(LOW, HIGH + 1)
.Select(num => $"{(char) chr}{num:D2}" + ((num + 1) % NUMINROW == 0
? Environment.NewLine : " "))))));
ReadLine();
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);
}
}
I want to find whether a number is prime or not by limiting the number of iterations as much as possible.The following program was suggested in a blog.I can understand these parts of the code..
public static bool Isprime(long i)
{
if (i == 1)
{
return false;
}
else if (i < 4)
{
return true;
}
else if (i % 2 == 0)
{
return false;
}
else if (i < 9)
{
return true;
}
else if (i % 3 == 0)
{
return false;
}
But I don't understand why f is incremented by 6.
else
{
double r = Math.Floor(Math.Sqrt(i));
int f = 5;
while (f <= r)
{
if (i % f == 0) { return false; }
if (i % (f + 2) == 0) { return false; }
f = f + 6;
}
return true;
}
}
Because every prime number (except 2 and 3) is of the form 6k +/- 1
Every other number cannot be prime, because they are divisible by 2 or 3
Also, a few modifications to your method:
public static bool Isprime(long i)
{
if (i < 2)
{
return false;
}
else if (i < 4)
{
return true;
}
else if ((i & 1) == 0)
{
return false;
}
else if (i < 9)
{
return true;
}
else if (i % 3 == 0)
{
return false;
}
else
{
double r = Math.Floor(Math.Sqrt(i));
int f = 5;
while (f <= r)
{
if (i % f == 0) { return false; }
if (i % (f + 2) == 0) { return false; }
f = f + 6;
}
return true;
}
}
You didn't check for negative numbers
To check if a number is even, (i & 1) == 0 is more efficient. Unfortunately, there is no such trick for i % 3
Though a good answer has been accepted, and I've offered another answer previously, I offer a new method for ulong that does things slightly different that may help explain why the 6 is important. This uses a for loop rather than a while.
UPDATE: I have expanded upon this answer with a version that runs in parallel threads. See this CodeReview Link for the parallel version.
Edit: added quick elimination of many composites
public static bool IsPrime6(ulong number)
{
// Get the quick checks out of the way.
if (number < 2) { return false; }
// Dispense with multiples of 2 and 3.
if (number % 2 == 0) { return (number == 2); }
if (number % 3 == 0) { return (number == 3); }
// Another quick check to eliminate known composites.
// http://programmers.stackexchange.com/questions/120934/best-and-most-used-algorithm-for-finding-the-primality-of-given-positive-number/120963#120963
if (!( ((number - 1) % 6 == 0) || ((number + 1) % 6 == 0)) )
{
return false;
}
// Quick checks are over. Number is at least POSSIBLY prime.
// Must iterate to determine the absolute answer.
// We loop over 1/6 of the required possible factors to check,
// but since we check twice in each iteration, we are actually
// checking 1/3 of the possible divisors. This is an improvement
// over the typical naive test of odds only which tests 1/2
// of the factors.
// Though the whole number portion of the square root of ulong.MaxValue
// would fit in a uint, there is better performance inside the loop
// if we don't need to implicitly cast over and over a few million times.
ulong root = (ulong)(uint)Math.Sqrt(number);
// Corner Case: Math.Sqrt error for really HUGE ulong.
if (root == 0) root = (ulong)uint.MaxValue;
// Start at 5, which is (6k-1) where k=1.
// Increment the loop by 6, which is same as incrementing k by 1.
for (ulong factor = 5; factor <= root; factor += 6)
{
// Check (6k-1)
if (number % factor == 0) { return false; }
// Check (6k+1)
if (number % (factor + 2UL) == 0) { return false; }
}
return true;
}
This is based on math theorem that states every prime number > 3 can be represented as (6k+/-1). But that doesn't mean every number of the form (6k+/1) is a prime.
The correct converse would be that if you have a number that is not represented as (6k+/-1) then that number cannot be prime.
For later use with modulo operator, (6k-1) is equivalent to (6(k+1)+5).
Thus our intent is to start the loop at 5, i.e. the first occurrence of (6k-1) for k=1, do checks inside the loop for (6k-1) and (6k+1), and then increment by 6 for another iteration through the loop.
In short, iterating by adding 6 to the previous factor is the same as adding 1 to k.
Explanation of Ugly Explicit Casts
I took out the UL designators after further tests showed that for this algorithm they made little difference.
Tests
To run some tests, you could try:
const long Largest63bitPrime = 9223372036854775783L;
const ulong Largest64bitPrime = 18446744073709551557UL;
On my laptop, it take 13 seconds for the largest 63-bit prime, and 18 seconds for the largest 64-bit prime. Surprisingly, the version above is 1.5 seconds faster against (ulong)Largest63bitPrime than using my other answer's long specific version that employs a while.
Quick Elimination of Many Composites
Based on comments to the OP itself, I added a new check. It’s kind of difficult to find the worst case scenario, or best time-savings case here. I tested it against Largest64bitPrime + 6. Without the check, it was 14.2 microseconds compared to 1.1 microseconds with it. But's in now included so that the algorithm is considered complete.
See #Dennis_E's answer and explanation, which I gave +1. I offer 2 variations on his. There could be 100's of millions of implicit casts being done by these statements:
double r = Math.Floor(Math.Sqrt(i));
int f = 5;
while (f <= r)
The loop conditional implicitly cast f to a double repeatedly. That obscures where some performance can be degraded. While the whole number portion of the square root of long.MaxValue could fit in a uint, to boost performance you are better off keeping every as long. Now performance inside the loop will suffer from any implicit casts.
public static bool Isprime1(long number)
{
// Get the quick checks out of the way.
if (number < 2) { return false; }
// 2 and 3 are prime.
if (number < 4) { return true; }
// besides 2, any other even number, i.e. any other multiple of 2, is not prime.
if ((number % 2) == 0) { return false; }
// 5 and 7 are also prime.
if (number < 9) { return true; }
// multiples of 3 are not prime.
if (number % 3 == 0) { return false; }
// Quick checks are over. Must iterate to find the answer.
// Though the whole number portion of the square root of long.MaxValue
// would fit in a uint, there is better performance inside the loop
// if we don't need to implicitly cast over and over a few million times.
long root = (long)Math.Sqrt(number);
long factor = 5;
while (factor <= root)
{
if (number % factor == 0L) { return false; }
if (number % (factor + 2L) == 0L) { return false; }
factor = factor + 6L;
}
return true;
}
All the above extends the answer by #Dennis_E. Another variation would be:
public static bool Isprime2(long number)
{
// Get the quick checks out of the way.
if (number < 2) { return false; }
// 2, 3, 5, & 7 are prime.
if ((new long[] { 2L, 3L, 5L, 7L }).Contains(number)) { return true; }
// any other multiples of 2 are not prime.
if ((number % 2) == 0) { return false; }
// any other multiples of 3 are not prime.
if (number % 3 == 0) { return false; }
// Quick checks are over. Must iterate to find the answer.
// Though the whole number portion of the square root of long.MaxValue
// would fit in a uint, there is better performance inside the loop
// if we don't need to implicitly cast over and over a few million times.
long root = (long)Math.Sqrt(number);
long factor = 5;
while (factor <= root)
{
if (number % factor == 0L) { return false; }
if (number % (factor + 2L) == 0L) { return false; }
factor = factor + 6L;
}
return true;
}
public class Prime {
public static void main(String[] args) {
Scanner get=new Scanner(System.in);
int n;
System.out.println("Enter a number to find its primality");
n=get.nextInt();
System.out.println(n+" isPRime? "+isPrime(Math.ceil(Math.sqrt(n)),n));
}
private static boolean isPrime(double n,int k){
boolean isPrim=true;
int p=(int)n;
for(int i=2;i<=p;i++){
boolean iprime=false;
for(int j=2;j<i/2;j++){
if(i%j==0){
iprime=true;
break;
}
}
if(!iprime && k>i){
if(k%i==0){
isPrim=false;
return isPrim;
}
}
}
return isPrim;
}
}
here is sample code
public static decimal factorization(decimal num, decimal factor)
{
if (num == 1)
{
return 1;
}
if ((num % factor)!= 0)
{
while(num% factor != 0)
{
factor++;
}
}
factors.Add(factorization(num / factor, factor));
return factor;
}
Note : I have initialize factors as global.
Above code will work fine for sample inputs 90 , 18991325453139 but will not work for input 12745267386521023 ... so how can I do that ? How can I achieve this efficiently ... I know recursive call will consume memory that's why I have checked the last input using without recursion .. But its not working too
You can use that if
factor*factor > num
then num is prime
It will decrease complexity from O(n) to O(sqrt(n))
EDIT
while(num% factor != 0)
{
factor++;
if(factor*factor>num){ // You can precalc sqrt(num) if use big arifmetic
factor=num; //skip factors between sqrt(num) and num;
}
}
using System.Collections;
public static int[] PrimeFactors(int num)
{
ArrayList factors = new ArrayList();
bool alreadyCounted = false;
while (num % 2 == 0)
{
if (alreadyCounted == false)
{
factors.Add(2);
alreadyCounted = true;
}
num = num / 2;
}
int divisor = 3;
alreadyCounted = false;
while (divisor <= num)
{
if (num % divisor == 0)
{
if (alreadyCounted == false)
{
factors.Add(divisor);
alreadyCounted = true;
}
num = num / divisor;
}
else
{
alreadyCounted = false;
divisor += 2;
}
}
int[] returnFactors = (int[])factors.ToArray(typeof(int));
return returnFactors;
}
I just copied and posted some code from Smokey Cogs because this is a very common problem.
The code does some things better than yours.
First you divide by two until the number is no longer even. From there, you can start with 3 and increment by 2 (skip every even number) since all the 2's have been factored out.
Nonetheless, there are ways to improve. Think about the usage of "alreadyCounted" in the code. Is it absolutely essential? For example, using
if (num % 2 == 0)
{
factors.Add(2);
num = num/2;
}
while( num %2 == 0)
{num = num/2;}
Allows you to skip the extra comparisons in the beginning.
RiaD also gave a great heuristic that factor^2 > num implies that num is prime. This is because (sqrt(n))^2 = n, so the only number after sqrt(n) that divides num will be num itself, once you've taken out the previous primes.
Hope it helps!
To see how to find the factors of a given number in C# see this (duplicate?) StackOverflow
question.
A few points on your code:
there is no need for recursion if using a naive search, just build a list of factors within the method and return it at the end (or use yield).
your second if statement is redundant as it wraps a while loop with the same condition.
you should use an integer type (and unsigned integer types will allow larger numbers than their signed counterparts, e.g. uint or ulong) rather than decimal as you are working with integers. For arbitrarily large integers, use System.Numerics.BigInteger.
if you search incrementally upwards for a factor, you can stop looking when you have got as far as the square root of the original number, as no factor can be larger than that.
Also, note that there is no known efficient algorithm for factoring large numbers (see Wikipedia for a brief overview).
Here's example code, based on the above observations:
static IList<BigInteger> GetFactors(BigInteger n)
{
List<BigInteger> factors = new List<BigInteger>();
BigInteger x = 2;
while (x <= n)
{
if (n % x == 0)
{
factors.Add(x);
n = n / x;
}
else
{
x++;
if (x * x >= n)
{
factors.Add(n);
break;
}
}
}
return factors;
}
Note that this is still a rather naive algorithm which could easily be further improved.
Below is my Generic Binary Search. It works okay with the integers type array (it finds all the elements in it). But the problem arises when I use a string array to find any string data. It runs okay for the first index and last index elements but I can't find the middle elements.
Stringarray = new string[] { "b", "a", "ab", "abc", "c" };
public static void BinarySearch<T>(T[] array, T searchFor, Comparer<T> comparer) {
int high, low, mid;
high = array.Length - 1;
low = 0;
if (array[0].Equals(searchFor))
Console.WriteLine("Value {0} Found At Index {1}",array[0],0);
else if (array[high].Equals(searchFor))
Console.WriteLine("Value {0} Found At Index {1}", array[high], high);
else
{
while (low <= high)
{
mid = (high + low) / 2;
if (comparer.Compare(array[mid], searchFor) == 0)
{
Console.WriteLine("Value {0} Found At Index {1}", array[mid], mid);
break;
}
else
{
if (comparer.Compare(searchFor, array[mid]) > 0)
high = mid + 1;
else
low = mid + 1;
}
}
if (low > high)
{
Console.WriteLine("Value Not Found In the Collection");
}
}
}
A binary search requires that the input be sorted. How is "b, a, ab, abc, c" sorted? It does not appear to be sorted on any obvious sort key. If you are trying to search unsorted data you should be using a hash set, not a binary search on a list.
Also, your calculation of midpoint is subtly wrong because the addition of high + low can overflow. It then becomes a negative number, which is divided by two.
This is extremely unlikely for realistically-sized arrays but it is entirely possible that you'll want to use this algorithm someday for data types that support indexing with large integers, like a memory-mapped file of sorted data.
The best practice for writing a binary search algorithm is to do (high - low) / 2 + low when calculating the midpoint, because that stays in range the whole time.
The two lines are suspect:
high = mid + 1
low = mid + 1
Hmm. Look at the offsets. Of course this is well documented Binary Search Algorithm on Wikipedia. You also do extra work. Examine the pseudo-code and examples closely.
pst Your advice really worked. :) this code is working for both int and string.
public static int BinarySearch<T>(T[] array, T searchFor, Comparer<T> comparer)
{
int high, low, mid;
high = array.Length - 1;
low = 0;
if (array[0].Equals(searchFor))
return 0;
else if (array[high].Equals(searchFor))
return high;
else
{
while (low <= high)
{
mid = (high + low) / 2;
if (comparer.Compare(array[mid], searchFor) == 0)
return mid;
else if (comparer.Compare(array[mid], searchFor) > 0)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
}
//Binary search recursive method
public void BinarySearch(int[] input,int key,int start,int end)
{
int index=-1;
int mid=(start+end)/2;
if (input[start] <= key && key <= input[end])
{
if (key < input[mid])
BinarySearch(input, key, start, mid);
else if (key > input[mid])
BinarySearch(input, key, mid + 1, end);
else if (key == input[mid])
index = mid;
if (index != -1)
Console.WriteLine("got it at " + index);
}
}
int[] input4 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
BinarySearch(input4, 1, 0, 8);