I wrote code to implement a bidirectional selection sort in parallel. I used c#, and the the parallel.invoke function. 2 loops were invoked in parallel, one to find the minimum, and one to find the max. Yet, it doesn't sort. I was wondering is the problem because this type of sort can't handle being done in parallel, since each loop relies on data existing in the other loop?...or is there simply something wrong with my code?
Parallel.Invoke(
() =>
{
for (int i=0; i < array.Length / 2; i++)
{
int m;
int min = i;
for (m = i + 1; m < array.Length - 1; m++)
if (array[m] < array[min])
min = m;
//swap
int temp = array[min];
array[min] = array[m];
array[m] = temp;
}
},
() =>
{
for (int m = 0; m < array.Length / 2; m++)
{
int length = array.Length - 1;
int max = length - m;
int k;
for (k = length--; k > 0; k--)
if (array[k] > array[max])
max = k;
//swap
int temp = array[max];
array[max] = array[k];
array[k] = temp;
}
});
I think it's easier if you search the minimum and maximum within the same loop in 1 thread: (java-code, but I assume you'll understand the principle)
int minimum, maximum;
int k = size();
for(int i = 0; i < size(); ++i)
{
--k;
minimum = i;
maximum = k;
if(k - i <= 0)
break;
for(int j = i; j <= k; ++j)
{
if(greaterThan(minimum, j))
minimum = j;
if(lessThan(maximum, j))
maximum = j;
}
if(minimum != i)
{
swap(minimum, i);
if(maximum == i)
maximum = minimum;
}
if(maximum != k)
swap(maximum, k);
}
The problem with your code is this:
Say this is the array:
[5, 4, 3, 2, 1]
Iteration 0: The first thread will find the smallest element to put on index 0
The first thread finds the minimum element at index 4
Iteration 0: The second thread will find the largest element to put on index 4
The second thread finds the maximum element at index 0
You will already see that this will not end well, as both threads will perform a swap between index 0 and 4 resulting in the same situation as it is now.
Another problem is if your first thread is looping from m -> array.length - 1. If at the same time thread 2 moves the minimum element (which it doesn't need, because it's searching the maximum) from index k to "max" via a swap. With index "max" being < "m". That means the first thread will never find the next minimum value because it was moved before its position.
EDIT: After consideration, I don't think it's possible to implement a straightforward parallel version of selection sort. The version I first recommended was indeed not going to work due to the algorithm finding the same minimum every time because it didn't change the input-array.
What is possible is to only perform selection sort with thread 1 on the first half of the array (and only allow it to find the minimum in that half) and the second half of the array is for the second thread. And then in the end you can merge both halfs with a mergesort-algorithm.
This way you can always use more than 2 threads; say "p" amount of threads for example. Each responsible for N/p part of the input array with "N" being the inputsize. And in the end you just merge every part with a mergesort-algorithm. I never implemented it myself, so I can't say if it would be efficient, but I assume there will be better algorithms to parallelize out there (like mergesort itself).
PS: About the code posted above. I assume everything seems rather straightforward except this part:
if(maximum == i)
maximum = minimum;
That's to deal with a situation like this:
. . . i . . . k
[1, 4, 3, 1, 5]
so with i = 1 and k = 3 (the indices).
The algorithm will find:
maximum = index 1
minimum = index 3
After swapping the minimum value with the one on index i, the situation changes like this:
. . . i . . . k
[1, 1, 3, 4, 5]
Meaning the maximum value (integer 4) actually moved from index "i" to index "minimum". If we would perform a swap(maximum, k), it would have a bad result. That's why we need to update the index of the maximum element if it was positioned at index i.
Related
So I'm curious.. Why is it that I need to do +1 and -1 when truncating a side of the array.
I get that an array is index based and starts at 0 but is that really the reason to why I need to do it? What's the actual logic behind it? I've noticed that if I don't do it, it just never exists the loop because it gets to a point where it just keeps dividing the values to the same value over and over again.
private static int[] values = { 1, 3, 5, 7, 10, 13, 15, 17 };
public static int FindValue(int valueToFind)
{
int l = 0;
int r = values.Length - 1;
while (l <= r)
{
var mid = (l + r) / 2;
if (values[mid] == valueToFind)
return mid;
if (values[mid] < valueToFind)
l = mid + 1;
else
r = mid - 1;
}
return -1;
}
If instead of l = mid + 1; we would have l = mid; then a problem arises when the l and r differ by at most 1 (so there are at most two array values in the running). In that case (l + r) / 2 == l, so that mid will be equal to l. Now let's suppose the value we look for is greater than values[mid], then the if block will execute and l will be assigned mid. But it already had that value, so nothing changes! The next iteration will start with exactly the same state as the previous one, and we'll loop without end.
If you would replace r = mid - 1; with just r = mid, then a similar problem can arise when there is just one value in the array left, i.e. l and r are equal. If the value we look for is less than that only value values[mid], then r will be assigned mid, but again, it already had that value. Nothing changes, and the looping goes on for ever.
The reasoning to have the +1 and -1 in those assignments is that:
it ensures that the interval will get smaller in each iteration, and so it will be impossible to have an infinite loop
it excludes mid from the reduced range, which makes sense, as with the first if we already compared with the value at that index, so it is no longer a candidate.
taking in your last comment, I would assume that it's a rounding issue. It's rounding up and the next calculated number is still higher than the target value. I would add some console logging to printout the value as it's searching.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
My code returns the correct answer the first duplicate is 3. I am struggling with time complexity. Is there a more efficient way to find the first duplicate?
my constraints are 1 ≤ a.length ≤ 10^5, 1 ≤ a[i] ≤ a.length. Thanks.
class Program
{
static void Main(string[] args)
{
int[] a = { 1, 2, 3, 4, 5, 6 };
int f = FirstDuplicate(a);
Console.ReadLine();
}
public static int FirstDuplicate(int[] a)
{
int[] answer = new int[2];
answer[0] = -1;
answer[1] = a.Length;
for (int i = 0; i < a.Length - 1; i++)
for (int j = i; j < a.Length; j++)
if (a[i] == a[j] && i != j)
{
if (i < answer[1])
{
answer[0] = a[i];
answer[1] = j;
break;
}
}
return answer[0];
You say
1 ≤ a.length ≤ 105,
and
I am struggling with time complexity. Is there a more efficient way to find the first duplicate?
Your question is nonsensical; your program is O(1) given the constraints. Any program where the problem size has a small bound is O(1).
Let's suppose we relax the condition that the length of the array is very small. In that case, plainly your method is quadratic.
There is a linear solution. It is:
seen = an empty set
for each element x of the array
if seen contains x then
return value x
else
seen = seen with x
end for
return not found
This is linear in the size of the array provided that testing containment of a set and growing the set is constant time.
Can you think of a way to make a set of integers such that checking membership in that set is constant time and adding a new member to the set is constant time?
Hint: Can you use the fact that the values in the array are small integers to your advantage?
Exercise: Now do the problem without any constraint on the size of the array or the size of its contents.
Exercise: Now do the problem on an arbitrary type T, where two Ts are equal if T.Equals(T) returns true.
I think there are a few improvements you can make. Items #3, #4, and #5 will all reduce the number of iterations compared to your current code:
We need to actually compare the values at a[i] and a[j] to see if we've found a duplicate.
Store the index of j in a variable if it's less than the current value (which we initialize to int.MaxValue, so the first match will automatically get added).
Add a condition to exit the loops if i or j are greater than the smallest duplicate index, because any match at that point will automatically be too large.
The outer loop only needs to go to i < a.Length - 1 since we will be comparing it to the next value (and there is no value after a.Length)
The inner loop can start at i + 1 to avoid doing comparisons of indexes we've already compared
Here's an example:
/// <summary>
/// Gets the index of the first duplicate item in an array
/// </summary>
/// <param name="a">The array to search</param>
/// <returns>The index of the first duplicate item, or -1 if none exist</returns>
public static int FirstDuplicate(int[] a)
{
if (a == null || a.Length < 2) return -1;
var smallestDupeIndex = int.MaxValue;
for (int i = 0; i < a.Length - 1 && i < smallestDupeIndex; i++)
{
for (int j = i + 1; j < a.Length && j < smallestDupeIndex; j++)
{
if (a[i] == a[j])
{
smallestDupeIndex = j;
}
}
}
return smallestDupeIndex == int.MaxValue ? -1 : smallestDupeIndex;
}
Here it is in use, with an array that has many duplicates:
private static void Main()
{
int[] a = {1, 2, 3, 4, 5, 4, 3, 2, 1};
Console.Write(GetFirstDupeIndex(a));
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
for (int i = uids.Count; i > 0; i--)
{
counting += 1;
if (counting == 30)
break;
string currentUidOnServer = uids[i - 1];
if (!seenUids.Contains(currentUidOnServer))
{
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
newMessages.Add(unseenMessage);
seenUids.Add(currentUidOnServer);
allMessages.Add(unseenMessage);
int nProgress = (uids.Count - i + 1) * 100 / uids.Count;
backgroundWorker1.ReportProgress(nProgress, client.GetMessageCount().ToString() + "/" + i);
}
}
The variable uids contain 7038 items.
I want to report to the backgroundworker progresschanged event.
And it does reporting but it did backward started from 7038 and 100%
And i want it to report from 0% to 100% so i changed the FOR to
for (int i = uids.Count; i > 0; i--)
It was
for (int i = 0; i < uids.Count; i++)
The first error out of index exception was on the line
string currentUidOnServer = uids[i - 1];
So i changed it to [i - 1]
Now i'm getting exception on the line
OpenPop.Mime.Message unseenMessage = client.GetMessage(i + 1);
Since 7038 + 1 not exist.
So i messed it all.
How this two lines i have/had the exceptions should be ?
This is the typical way to do this:
for (int i = uids.Count - 1; i >= 0; i--)
Then, use uids[i] and maybe client.GetMessage(i), however I have no idea, what "client" is in your code
Arrays in C# (and all the other C-like languages) are zero-indexed, which means that the first item in the array is at position 0. Attempting to access an array index that is less than 0 or greater than or equal to the number of elements in the array will result in an error as you have seen.
The first form of your loop:
for (int i = uids.Count; i > 0; i--)
...produces a sequence of numbers (on your 7038-item array) from 7038 down to 1. Since 7038 is an invalid array index (1 past the end of the array) and the sequence doesn't include 0, the array access expressions in the loop all use i -1 to shift the entire sequence down by 1.
To properly reverse the for without changing any other code you need to produce a sequence from 1 up to 7038, like this:
for (int i = 1; i <= uids.Count; i++)
This is the direct opposite form of your original.
Personally I would prefer that the loop variable be the array index most of the time, and my first instinct when I see a > 0 condition in a for statement is that someone forgot to put the = in.
You could just reverse your array with Array.reverse() and then iterate over it using i++ as per your original approach
Oops I thought this was JavaScript question lol, o well the approach I said can conceptually be applied to any language, just need to find the array reverse for your language
If I understood correctly, originally i went from 0 to uids.Count - 1. If you can get back to that situation, then your formula for nProgress should be
int nProgress = (i + 1) * 100 / uids.Count;
In a course a problem was to list the first n primes. Apparently we should implement trial division while saving primes in an array to reduce the number of divisions required. Initially I misunderstood, but got a working if slower solution using a separate function to test for primality but I would like to implement it the way I should have done.
Below is my attempt, with irrelevant code removed, such as the input test.
using System;
namespace PrimeNumbers
{
class MainClass
{
public static void Main (string[] args)
{
Console.Write("How many primes?\n");
string s = Console.ReadLine();
uint N;
UInt32.TryParse(s, out N)
uint[] PrimeTable = new uint[N];
PrimeTable[0] = 2;
for (uint i=1; i < N; i++)//loop n spaces in array, [0] set already so i starts from 1
{
uint j = PrimeTable[i -1] + 1;//sets j bigger than biggest prime so far
bool isPrime = false;// Just a condition to allow the loop to break???(Is that right?)
while (!isPrime)//so loop continues until a break is hit
{
isPrime = true;//to ensure that the loop executes
for(uint k=0; k < i; k++)//want to divide by first i primes
{
if (PrimeTable[k] == 0) break;//try to avoid divide by zero - unnecessary
if (j % PrimeTable[k] == 0)//zero remainder means not prime so break and increment j
{
isPrime = false;
break;
}
}
j++;//j increment mentioned above
}
PrimeTable[i] = j; //not different if this is enclosed in brace above
}
for (uint i = 0; i < N; i++)
Console.Write(PrimeTable[i] + " ");
Console.ReadLine();
}
}
}
My comments are my attempt to describe what I think the code is doing, I have tried very many small changes, often they would lead to divide by zero errors when running so I added in a test, but I don't think it should be necessary. (I also got several out of range errors when trying to change the loop conditions.)
I have looked at several questions on stack exchange, in particular:
Program to find prime numbers
The first answer uses a different method, the second is close to what I want, but the exact thing is in this comment from Nick Larsson:
You could make this faster by keeping track of the primes and only
trying to divide by those.
C# is not shown on here: http://rosettacode.org/wiki/Sequence_of_primes_by_Trial_Division#Python
I have seen plenty of other methods and algorithms, such as Eratosthenes sieve and GNF, but really only want to implement it this way, as I think my problem is with the program logic and I don't understand why it doesn't work. Thanks
The following should solve your problem:
for (uint i = 1; i < numberOfPrimes; i++)//loop n spaces in array, [0] set already so i starts from 1
{
uint j = PrimeTable[i - 1] + 1;//sets j bigger than biggest prime so far
bool isPrime = false;// Just a condition to allow the loop to break???(Is that right?)
while (!isPrime)//so loop continues until a break is hit
{
isPrime = true;//to ensure that the loop executes
for (uint k = 0; k < i; k++)//want to divide by first i primes
{
if (PrimeTable[k] == 0) break;//try to avoid divide by zero - unnecessary
if (j % PrimeTable[k] == 0)//zero remainder means not prime so break and increment j
{
isPrime = false;
j++;
break;
}
}
}
PrimeTable[i] = j;
}
The major change that I did was move the incrementation of the variable j to inside the conditional prime check. This is because, the current value is not prime, so we want to check the next prime number and must move to the next candidate before breaking in the loop.
Your code was incrementing after the check was made. Which means that when you found a prime candidate, you would increment to the next candidate and assign that as your prime. For example, when j = 3, it would pass the condition, isPrime would still = true, but then j++ would increment it to 4 and that would add it to the PrimeTable.
Make sense?
This might not be a very good answer to your question, but you might want to look at this implementation and see if you can spot where yours differs.
int primesCount = 10;
List<uint> primes = new List<uint>() { 2u };
for (uint n = 3u;; n += 2u)
{
if (primes.TakeWhile(u => u * u <= n).All(u => n % u != 0))
{
primes.Add(n);
}
if (primes.Count() >= primesCount)
{
break;
}
}
This correctly and efficiently computes the first primesCount primes.
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.