I am learning to code and I though I'd try writing a merge sort algorithm (something we heard about in our analytic course but NOT homework). I was working from the pseudo code the trainer showed us but I cannot identify the problem. Any chance someone could point me in the right direction?
edit: The algorithm only returns the first value in the List.
static List<int> mergeSort(List<int> mj)
{
List<int>m = mj;
if(m.Count <= 1)
return m;
List<int> merge = new List<int>();
List<int> left = new List<int>();
List<int> right = new List<int>();
int middle = m.Count/2;
for (int i = 0; i < middle; i++)
left.Add(m[i]);
for (int j = middle; j >= m.Count; j++)
right.Add(m[j]);
left = mergeSort(left);
right = mergeSort(right);
merge.AddRange(left);
merge.AddRange(right);
for (int k = 0; k < merge.Count; k++)
{
Console.Write(merge[k] + ",");
}
return merge;
}
The problem with your code (apart from the bug Mike Cowan mentioned) is that you’re not performing any actual sorting. You’re first recursively splitting your lists in half (which is correct), but then you’re simply concatenating them back together in their original order, thereby achieving no result:
merge.AddRange(left);
merge.AddRange(right);
What you need to do instead is iterate through your two sublists (which, by induction, should have been respectively sorted in the recursive calls), and add elements to the merged list in order.
We start off by comparing the 0th elements: left[0] against right[0]. Whichever of the two is smaller, is added to the merge list, and its sublist’s counter is incremented. Suppose that left[0] < right[0]: we add left[0] to merge, and in the next iteration, we would then need to consider left[1] against right[0]. If left[1] is again smaller, we add it to merge and, in the next iteration, consider left[2] against right[0]. If right[0] is now the smaller of the two, we add it to merge and, in the next iteration, compare left[2] against right[1]. And so on.
This keeps going on until one of the sublists is exhausted. When that happens, we simply add all the elements from the remaining sublist into merge.
int leftIndex = 0;
int rightIndex = 0;
while (leftIndex < left.Count && rightIndex < right.Count)
if (left[leftIndex] < right[rightIndex])
merge.Add(left[leftIndex++]);
else
merge.Add(right[rightIndex++]);
while (leftIndex < left.Count)
merge.Add(left[leftIndex++]);
while (rightIndex < right.Count)
merge.Add(right[rightIndex++]);
Additionally, you should not be writing to console within your recursive method. Move your Console.Write calls to your Main method:
static void Main(string[] args)
{
List<int> original = new List<int>(new int[] { 4, 75, 12, 65, 2, 71, 56, 33, 78,1, 4, 56, 85, 12, 5,77, 32, 5 });
List<int> sorted = mergeSort(original);
for (int k = 0; k < sorted.Count; k++)
Console.Write(sorted[k] + ",");
}
This line:
for (int j = middle; j >= m.Count; j++)
right.Add(m[j]);
should read:
for (int j = middle; j < m.Count; j++)
right.Add(m[j]);
First off, the line
for (int j = middle; j >= m.Count; j++)
should be
for (int j = middle; j < m.Count; j++)
Also, you never actually merge the left and right, you're just placing them on top of eachother. The line
merge.AddRange(left);
merge.AddRange(right);
Should be something like
mergeLeftRight(left, right)
Where mergeLeftRight is a second function you define that does the actual sorting. Read the wikipedia article on Merge Sorts: http://en.wikipedia.org/wiki/Merge_sort
Simple merge sort steps
if( mj.length == 1 ) return mj;
Split into left and right lists and recurse
when left and right lists return, merge them <-- you do not do this
return merged left and right lists
Related
I'm trying to rotate a multi-dimensional array clockwise.
Here's my code.
I've already got the transpose part down but I need help with the reverse section.
I've tried multiple solution but they just don't work with the code I already have so, yeah. Thank you.
Desired output
7 4 1
8 5 2
9 6 3
static void RotateMatrix()
{
// Multidimenonsal array to rotate
int[,] matrix = new int[,]
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Swaps places -- transpose
/*
Output of this for loop
{
1 4 7
2 5 8
3 6 9
}
*/
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
var temp = matrix[i, j]; // store matrix(pos x, pos y) in temp var
matrix[i, j] = matrix[j, i]; // set the position matrix(pos x, pos y) to (opposite position)
matrix[j, i] = temp; // set (opposite position) to temp var
}
}
// Reverse !! Need help Here!!
// Prints out the rotated matrix
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.Write(matrix[j, i]);
}
Console.WriteLine();
}
}
Rotating a matrix in place will be quite challenging. I would highly recommend just creating a new matrix, especially when dealing with small matrices. You will also need to reverse the direction in one of the index operations:
var result = new int[3,3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
result[j, 2-i] = matrix[i, j];
}
}
However, unless you are doing this for learning I would suggest using a pre-existing matrix library, it will likely both have more features and be faster.
For example, you made one of the classic blunders when working with multidimensional matrices and call matrix.GetLength(...) for each iteration, this method is fairly slow, so you should be getting the length outside the loop and storing it.
I have 2 tables with random numbers and i want to check which number from first table doesn't exist in second one and output it.
Example:
First table: 2, 6, 7, 9
Second table: 0, 6, 11, 3
Output: 2, 7, 9
My current code:
#region CompareTables
int[,] TABLE1 = new int[5, 10];
int[,] TABLE2 = new int[5, 10];
Random rnd = new Random();
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
{
TABLE1[i, j] = rnd.Next(1, 100);
TABLE2[i, j] = rnd.Next(1, 100);
}
}
Console.Write("TABLE1" + "\n\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
Console.Write(TABLE1[i, j] + " " + "\t");
Console.WriteLine();
}
Console.Write("\n");
Console.Write("TABLE2" + "\n\n");
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
Console.Write(TABLE2[i, j] + " " + "\t");
Console.WriteLine();
}
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 10; j++)
if (TABLE1[i, j] == TABLE2[i, j])
Console.WriteLine();
}
Console.ReadKey();
#endregion
I would like to ask how to output numbers that are in first table but not in second?
The problem you are having is that your tables are 2 dimensional arrays and you are trying to index into them as if they were one dimensional arrays.
Look at how your are filling them up:
TABLE1[i, j] = rnd.Next(1, 100);
TABLE2[i, j] = rnd.Next(1, 100);
You are correctly using two indexes i and j (think of rows and columns).
However, later on you are doing:
if (TABLE1[1] == TABLE2[i]) //where is the second index?
This is obviously wrong, but instead of making this work, lets take a step back and think this through again. All this mucking around with two indexes seems a little... yeah, mucky, shouldn't there be a better way to do this?
In your current problem, the fact that the tables are multidimensional is simply a pain that doesn't really add any value. If you only need to return elements of the first table that are not present in the second table without any position information, then why all this hassle with indexes to begin with? Lets create a helper method that flattens the arrays and enables us to get rid of at least one index:
static IEnumerable<T> Flatten<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
for (var j = 0; j < array.GetLength(1); j++)
yield return array[i, j];
}
And now that we have one dimensional arrays (IEnumerable<T>s) we can leverage C#'s magic stick...LINQ! Solving your problem is as simple as:
var notPresent = TABLE1.Flatten().Except(TABLE2.Flatten());
But this can have horrible performance if the arrays are big enough. Remember how you would solve this problem by hand (and how Except does it too): take first element from table 1, check all elements from table 2 until you either find a match or there are no more elements. Take second element from table 1, check all elements from table 2 until... etc. That seems a lot of work, and it grows really fast if the tables are big. Also if your are not smart about it you might be doing unnecessary extra work because Table 1 and 2 might contain duplicate elements...
Can this be improved? Yes, there are specially built collections that allow really fast searches; Sets. In your case, a HashSet<int> seems like a pretty good choice.
Your code now would look like:
var set = new HashSet<int>(TABLE1.Flatten());
var notPresent = set.Except(TABLE2.Flatten());
And this will perform much better.
You could covert your 2D arrays into lists and find the numbers from TABLE1 that don't exist in TABLE2 with LINQ Except:
List<int> LIST1 = TABLE1.Cast<int>().ToList();
List<int> LIST2 = TABLE2.Cast<int>().ToList();
var result = LIST1.Except(LIST2);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm struggling in the making of algorithm that "shuffles" a set of numbers in such way that they are sorted in ascending order starting from 0 ,the next number must not exceed the previous one + 1, they must also have a length of 15 and every single number from the set of numbers must be included. For example if we have the numbers :
0, 1
the desired output is :
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 (yes those are 14 zeros)
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1
..
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1
same goes if the numbers were
0, 1, 2
0,0,0,0,0,0,0,0,0,0,0,0,0,1,2 (every number must be included)
I tried the following and I failed miserably :
Version 1
private static List<List<int>> GetNumbers(int lastNumber)
{
if (lastNumber == 0)
{
return new List<List<int>> { new List<int> { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
}
int[] setOfNumbers = new int[lastNumber + 1];
List<List<int>> possibleRoutes = new List<List<int>>().ToList();
for (int i = 0; i <= lastNumber; i++)
{
setOfNumbers[i] = i;
}
var temp = new List<int>();
int[] possibleRoute = new int[15];
for (int j = 0; j < size - lastNumber; j++)
{
possibleRoute[j] = 0;
}
for (int j = lastNumber; j < possibleRoute.Length; j++)
{
for (int k = j; k > 0; k--)
{
possibleRoute[k] = lastNumber - 1;
}
for (int i = size - 1; i >= j; i--)
{
possibleRoute[i] = lastNumber;
}
possibleRoutes.Add(possibleRoute.ToList());
generalCounter++;
}
return possibleRoutes;
}
Version 2
private static List<List<int>> GetNumbers(int lastNumber)
{
if (lastNumber == 0)
{
return new List<List<int>> {new List<int> {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
}
int[] setOfNumbers = new int[lastNumber + 1];
List<List<int>> possibleRoutes = new List<List<int>>().ToList();
for (int i = 0; i <= lastNumber; i++)
{
setOfNumbers[i] = i;
}
var temp = new List<int>();
int[] possibleRoute = new int[15];
for (int j = 0; j < size - lastNumber; j++)
{
possibleRoute[j] = 0;
}
for (int i = 1 ; i <= lastNumber ; i++)
{
int newNumber = lastNumber - i;
for (int k1 = i + 1; k1 <= size; k1++)
{
for (int j = possibleRoute.Length - 1; j > k1 - i - 1; j--)
{
possibleRoute[j] = lastNumber;
}
for (int k = i; k <= k1 - 1; k++)
{
possibleRoute[k] = newNumber;
}
possibleRoutes.Add(possibleRoute.ToList());
generalCounter++;
}
}
return possibleRoutes;
}
I misunderstood the problem. Starting this answer over.
Let's state the problem another way.
We have a number of items, fifteen.
We have a number of digits, say 0, 1, 2.
We wish to know what are the combinations of x zeros, y ones and z twos such that x + y + z = 15 and x, y and z are all at least one.
So, reduce it to an easier problem. Suppose there is one zero. Now can you solve the easier problem? The problem is now smaller: the problem is now "generate all the sequences of length 14 that have at least one 1 and one 2". Do you see how to solve the easier problem?
If not, break it down into a still easier problem. Suppose there is one 1. Can you solve the problem now? The problem now is to find all the sequences that have thirteen 2s in them, and there's only one of those.
Now suppose there are two 1s. Can you solve the problem there?
Do you see how to use the solution to the easier problems to solve the harder problems?
A simple strategy which works with a wide variety of problems like this is to list the possibilities in lexicographical order. In pseudocode, you would do something like this:
Set V to the first possible sequence, in lexicographical order.
Repeat the following:
Output V
If possible, set V to the next sequence in lexicographical order.
If that was not possible, exit the loop.
For many cases, you can solve the second sub-problem ("set V to the next sequence") by searching backwards in V for the right-most "incrementable" value; that is, the right-most value which could be incremented resulting an a possible prefix of a sequence. Once that value has been incremented (by the minimum amount), you find the minimum sequence which starts with that prefix. (Which is a simple generalization of the first sub-problem: "find the minimum sequence".)
In this case, both of these sub-problems are simple.
A value is incrementable if it is not the largest number in the set and it is the same as the preceding value. It can only be incremented to the next larger value in the set.
To find the smallest sequence starting with a prefix ending with k, start by finding all the values in the set which are greater than k, and putting them in order at the end of the sequence. Then fill in the rest of the values after the prefix (if any) with k.
For the application of this approach to a different enumeration problem, see https://stackoverflow.com/a/30898130/1566221. It is also the essence of the standard implementation of next_permutation.
I'm trying to write a code that will fill array with unique numbers.
I could write the code separately for 1, 2 and 3 dimensional arrays but number of for cycles grow to "infinity".
this is the code for 2D array:
static void fillArray(int[,] array)
{
Random rand = new Random();
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = rand.Next(1, 100);
for (int k = 0; k < j; k++)
if (array[i, k] == array[i, j])
j--;
}
}
print_info(array);
}
Is it possible to do something like this for n-dimensional arrays?
My approach is to start with a 1-d array of unique numbers, which you can shuffle, and then slot into appropriate places in your real array.
Here is the main function:
private static void Initialize(Array array)
{
var rank = array.Rank;
var dimensionLengths = new List<int>();
var totalSize = 1;
int[] arrayIndices = new int[rank];
for (var dimension = 0; dimension < rank; dimension++)
{
var upperBound = array.GetLength(dimension);
dimensionLengths.Add(upperBound);
totalSize *= upperBound;
}
var singleArray = new int[totalSize];
for (int i = 0; i < totalSize; i++) singleArray[i] = i;
singleArray = Shuffle(singleArray);
for (var i = 0; i < singleArray.Length; i++)
{
var remainingIndex = i;
for (var dimension = array.Rank - 1; dimension >= 0; dimension--)
{
arrayIndices[dimension] = remainingIndex%dimensionLengths[dimension];
remainingIndex /= dimensionLengths[dimension];
}
// Now, set the appropriate cell in your real array:
array.SetValue(singleArray[i], arrayIndices);
}
}
The key in this example is the array.SetValue(value, params int[] indices) function. By building up the correct list of indices, you can use this function to set an arbitrary cell in your array.
Here is the Shuffle function:
private static int[] Shuffle(int[] singleArray)
{
var random = new Random();
for (int i = singleArray.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
int tmp = singleArray[j];
singleArray[j] = singleArray[i - 1];
singleArray[i - 1] = tmp;
}
return singleArray;
}
And finally a demonstration of it in use:
var array1 = new int[2,3,5];
Initialize(array1);
var array2 = new int[2,2,3,4];
Initialize(array2);
My strategy assigns sequential numbers to the original 1-d array to ensure uniqueness, but you can adopt a different strategy for this as you see fit.
You can use Rank property to get the total number of dimentions in your array
To insert use SetValue method
In the first two for loops you are analysing the array properly (i and j go from the start to the end of the corresponding dimension). The problem comes in the most internal part where you introduce a "correction" which actually provokes an endless loop for j.
First iteration:
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
Second iteration
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
. etc., etc.
(I start my analysis in the moment when the internal loop is used for the first time. Also bear in mind that the exact behaviour cannot be predicted as far as random numbers are involved. But the idea is that you are making the j counter back over and over by following an arbitrary rule).
What you want to accomplish exactly? What is this last correction (the one provoking the endless loop) meant to do?
If the only thing you intend to do is checking the previously stored values, you have to rely on a different variable (j2, for example) which will not affect any of the loops above:
int j2 = j;
for (int k = 0; k < j2; k++)
if (array[i, k] == array[i, j2])
j2--;
I'm just wondering if there is a simpler way of doing this:
for (int i = 0; i < 1; i++)
{
for (int j = 0; i < 8; j+2)
{
board[ i, j ] = 2;
board[( i + 1 ), j ] = 2;
board[( i + 2 ), j ] = 2;
}
}
What I'm trying to do is place checkers pieces on the actual checkers board. So this is to place the black pieces on the top.
P.S. If you could also give me some help on the bottom set of pieces(white).
Apart from fixing the loop you could otherwise explicitly place the pieces, makes it more readable
int[,] board = new[,]{{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1}};
Modulo will do the trick but i think that TonyS's anwser was my first reaction and I would prefer that insteed the one shown below.
char[,] board = new char[8,8];
private void InitializeBoard()
{
string BoardRepresentation = "";
//for every board cell
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
//initialize board cell
board[i, j] = '0';
if (j <= 2)//black top
{
//Modulo is the trick
if ((j - i) == 0 || ((j - i) % 2) == 0)
{
board[i, j] = 'B';
}
}
else if (j >= 5) //white bot
{
if ((j - i) == 0 || ((j - i) % 2) == 0)
{
board[i, j] = 'W';
}
}
}
}
for (int j = 0; j < 8; j++)
{
for (int i = 0; i < 8; i++)
{
BoardRepresentation += board[i, j] + " ";
}
BoardRepresentation += Environment.NewLine;
}
}
You missed to tell us what exactly is it that you want to achieve. I see several big errors in your code, so I'll assume that you don't have full grasp of how for loop works. I hope it's not too presumptuous that I'm trying to explain it here
For loop
For loop is used to execute same portion of code several times. How many times it will be executed depends on conditions you set. Most often, you will see it in this format:
for (int i = 0; i < n; i++)
{
// Some code
}
This for loop executed code within the brackets ({ and }) n times. This is not only way to define a loop. More thorough definition of a loop is following:
for (<initialization>; <condition>; <afterthought>)
Initialization - You can some variables needed for looping. This is executed once before code within the loop is executed first time. This is optional, and you can leave it empty and use variable declared before in condition.
Condition - This is executed before each execution of code within the loop. If condition expression evaluates to true, loop is executed. Once loop is executed and afterthought is executed, condition is evaluated again and again until it evaluates to false. Condition is also optional. If you leave it out, in C# loop will be executed again until you break the loop in a different way.
Afterthought - This is executed each time code within the loop is finished executing. This is usually used to increment a variable on which loop depends. This is also optional.
Fixing your code
I assume you wanted to mark fields in a 8x8 matrix like in a checkerboard, although this is not stated in your question. You could do it this way:
// For each row in a board (start with 0, go until 7, increase by 1)
for (int i = 0; i < 8; i++)
{
// start coloring the row. Determine which field within the row needs
// to be black. In first row, first field is black, in second second
// field is black, in third row first field is black again and so on.
// So, even rows have black field in first blace, odd rows have black
// on second place.
// We calculate this by determining division remained when dividing by 2.
int firstBlack = i % 2;
// Starting with calculated field, and until last field color fields black.
// Skip every second field. (start with firstBlack, go until 7, increase by 2)
for (int j = firstBlack; j < 8; j += 2)
{
// Color the field black (set to 2)
board[i][j] = 2;
}
}
You can see my comments inline.
Big errors in your code
// This loop would be executed only once. It goes from 0 to less than 1 and is increased
// after first execution. You might as well done it without the loop.
for (int i = 0; i < 1; i++)
{
// This doesn't make sense, because you use i in condition, and initialize
// and update j.
// Also, you are trying to update j, but you are not doing so. You are not
// assigning anything to you. You should do j+=2 to increase by two. Or you
// can do j = j + 2
for (int j = 0; i < 8; j+2)
{
// I didn't really understand what you were trying to achieve here
board[ i, j ] = 2;
board[( i + 1 ), j ] = 2;
board[( i + 2 ), j ] = 2;
}
}