Merge sort problem - c#

I'm making a menu of all kinds of sorting algorithm and now I'm stuck at merge sort.
I encountered an error after clicking the execute button. I entered 5 numbers in TextBox1 and another set of 5 numbers in TextBox2. It says that index was outside the bounds of the array. I indicated on the codes where it appeared. Any ideas what is the problem?
private void ExeButton_Click(object sender, EventArgs e)
{
string[] numsInString = EntNum.Text.Split(' '); //split values in textbox
string[] numsInString1 = EntNum1.Text.Split(' ');
for (int j = 0; j < numsInString.Length; j++)
{
a[j] = int.Parse(numsInString[j]);
}
for (int j = 0; j < numsInString1.Length; j++)
{
b[j] = int.Parse(numsInString1[j]);
}
{
sortArray();
Display();
}
}
public void sortArray()
{
m_sort(0, 10 - 1);
}
public void m_sort(int left, int right)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
m_sort(left, mid);
m_sort(mid + 1, right);
merge(left, mid + 1, right);
}
}
public void merge(int left, int mid, int right)
{
int i, left_end, num_elements, tmp_pos;
left_end = mid - 1;
tmp_pos = left;
num_elements = right - left + 1;
while ((left <= left_end) && (mid <= right))
{
if (a[left] <= a[mid]) //index was outside the bounds of the the array
{
b[tmp_pos] = a[left];
tmp_pos = tmp_pos + 1;
left = left + 1;
}
else
{
b[tmp_pos] = a[mid];
tmp_pos = tmp_pos + 1;
mid = mid + 1;
}
}
while (left <= left_end)
{
b[tmp_pos] = a[left];
left = left + 1;
tmp_pos = tmp_pos + 1;
}
while (mid <= right)
{
b[tmp_pos] = a[mid];
mid = mid + 1;
tmp_pos = tmp_pos + 1;
}
for (i = 0; i < num_elements; i++)
{
a[right] = b[right];
right = right - 1;
}
}
private void ClearButton_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
}
public void Display()
{
int i;
String numbers = "";
for (i = 0; i < 10; i++)
numbers += a[i].ToString() + " ";
numbers += b[i].ToString() + " ";
richTextBox1.AppendText(numbers + "\n");
}

Regarding your concrete question: a is an array of 5 elements with the indexes 0, 1, 2, 3, 4, so a[4] is the last element. You start with m_sort(0, 10 - 1) = m_sort(0, 9);. In m_sort() you compute
mid = (right + left) / 2 = (9 + 0) / 2 = 4
and call
merge(left, mid + 1, right) = merge(0, 4 + 1, 9) = merge(0, 5, 9).
In merge(int left, int mid, int right) you evaluate:
if (a[left] <= a[mid]) i.e. if (a[0] <= a[5])
so you access a[5] which is out of bounds.
I think your merge sort can be simplified considerably. You might look at the many resources on the Web or in a textbook on algorithms.

Here is an example of a way to simplify the merge, assuming each list is sorted with element 0 having the highest value:
int c[] = new int[a.Length + b.Length];
int aPos = 0;
int bPos = 0;
for(int i = 0; i < c.Length; i++)
{
if(a[APos] > b[bPos])
{
c[i] = a[Apos];
if(aPos < aPos.Length - 1)
aPos++;
}
else
{
c[i] = b[bPos];
if(bPos < bPos.Length - 1)
bPos++;
}
}

// array of integers to hold values
private int[] a = new int[100];
private int[] b = new int[100];
// number of elements in array
private int x;
// Merge Sort Algorithm
public void sortArray()
{
m_sort( 0, x-1 );
}
public void m_sort( int left, int right )
{
int mid;
if( right > left )
{
mid = ( right + left ) / 2;
m_sort( left, mid );
m_sort( mid+1, right );
merge( left, mid+1, right );
}
}
public void merge( int left, int mid, int right )
{
int i, left_end, num_elements, tmp_pos;
left_end = mid - 1;
tmp_pos = left;
num_elements = right - left + 1;
while( (left <= left_end) && (mid <= right) )
{
if( a[left] <= a[mid] )
{
b[tmp_pos] = a[left];
tmp_pos = tmp_pos + 1;
left = left +1;
}
else
{
b[tmp_pos] = a[mid];
tmp_pos = tmp_pos + 1;
mid = mid + 1;
}
}
while( left <= left_end )
{
b[tmp_pos] = a[left];
left = left + 1;
tmp_pos = tmp_pos + 1;
}
while( mid <= right )
{
b[tmp_pos] = a[mid];
mid = mid + 1;
tmp_pos = tmp_pos + 1;
}
for( i = 0; i < num_elements; i++ )
{
a[right] = b[right];
right = right - 1;
}
}

Related

How can I prevent my Quicksort Algorithm from throwing a StackOverflowException

Im trying to write a quicksort algorithm in C#, and I've been getting System.StackOverflowExceptions for the last while and can't figure out why.
Here is my Class:
class quicksort : sortalgorithm
{
int pivotIndex = -1;
int pivotSwapped = 0;
Random rand = new Random();
public quicksort(int[] arr)
{
if (arr.Length < 5)
{
throw new Exception("Array has too few Entries");
}
toSort = arr;
}
protected override int sort()
{
if (pivotIndex == -1) getPivot();
int indexL = getIndexLeft();
int indexR = getIndexRight();
if (indexR != -1 && indexL != -1 && indexL != toSort.Length-1)
{
swap(indexL, indexR);
}
if (indexL > indexR)
{
Console.WriteLine("Index thingy");
swap(toSort.Length - 1, indexL);
pivotSwapped++;
if (pivotSwapped == toSort.Length - 1)
{
return 1;
}
else
{
Console.WriteLine("new piv");
pivotSwapped++;
getPivot();
sort();
return -1;
}
}
else
{
sort();
return -1;
}
}
private void swap(int i, int j)
{
int temp = toSort[i];
toSort[i] = toSort[j];
toSort[j] = temp;
}
private void getPivot()
{
pivotIndex = rand.Next(0, toSort.Length - 1);
swap(toSort.Length - 1, pivotIndex);
}
private int getIndexLeft() // Larger then Pivot Starting: Left
{ //Error Here
int itemFromLeft = -1;
for (int i = 0; i < toSort.Length - 1; i++)
{
if (toSort[i] >= toSort[toSort.Length - 1])
{
itemFromLeft = i;
i = toSort.Length + 1;
}
}
//Console.WriteLine(itemFromLeft);
return itemFromLeft;
}
private int getIndexRight()// Smaller then Pivot Starting: Right
{
int itemFromRight = -1;
for (int i = toSort.Length - 1; i >= 0; i--)
{
if (toSort[i] < toSort[toSort.Length - 1])
{
itemFromRight = i;
i = -1;
}
}
//Console.WriteLine(itemFromRight);
return itemFromRight;
}
}
I hope that someone can help me.
P.S. the class sortalgorithm in this case only has the the array toSort.
My Console output always looks a bit like this:
[4, 28, 62, 33, 11] // The unsorted array
Index thingy
new piv
Index thingy
new piv
Index thingy
new piv
Process is terminated due to `StackOverflowException`.
a stack overflow error usually happens when you have a error in your recursion , ie a function keeps calling itself until there is no room left in the stack to hold all the references,
the only obvious candidate is
**sort();**
return -1;
}
}
else
{
**sort();**
return -1;
}
so either one or the other recursive calls is probably incorrect and needs removing and i suspect the issue will be resolved
EDIT:
as you are unable to debug your code
this is what a quick sort should look like
public int sort()
{
qsort(0, toSort.Length - 1);
return 0;
}
private void qsort( int left, int right)
{
if (left < right)
{
int pivot = Partition( left, right);
if (pivot > 1)
{
qsort( left, pivot - 1);
}
if (pivot + 1 < right)
{
qsort( pivot + 1, right);
}
}
}
private int Partition( int left, int right)
{
int pivot = toSort[left];
while (true)
{
while (toSort[left] < pivot)
{
left++;
}
while (toSort[right] > pivot)
{
right--;
}
if (left < right)
{
if (toSort[left] == toSort[right]) return right;
int temp = toSort[left];
toSort[left] = toSort[right];
toSort[right] = temp;
}
else
{
return right;
}
}
}
Note that if left >= right do nothing
This simple implementation of Hoare partition scheme demonstrates how to avoid stack overflow by recursing on the smaller partition, and looping back for the larger partition, an idea used in the original quicksort. Stack space complexity is limited to O(log2(n)), but worst case time complexity is still O(n^2).
static public void Quicksort(int [] a, int lo, int hi)
{
while(lo < hi){ // while partition size > 1
int p = a[(lo + hi) / 2];
int i = lo, j = hi;
i--; // Hoare partition
j++;
while (true)
{
while (a[++i] < p) ;
while (a[--j] > p) ;
if (i >= j)
break;
int t = a[i];
a[i] = a[j];
a[j] = t;
}
i = j++; // i = last left, j = first right
if((i - lo) <= (hi - j)){ // if size(left) <= size(right)
Quicksort(a, lo, i); // recurse on smaller partition
lo = j; // and loop on larger partition
} else {
Quicksort(a, j, hi); // recurse on smaller partition
hi = i; // and loop on larger partition
}
}
}

Creating an isosceles triangle in C3

The code below only makes a right angle triangle, how would I make it into an isosceles triangle?
int height = 4;
string star = "";
for (int i = 0; int i < height; i++)
{
star += "*";
Console.WriteLine(star);
}
Console.ReadLine();
This only displays a right angle triangle. What I attempted to make was a pyramid.
Here you have a cleaner code:
int numberoflayer = 4;
int empty;
int number;
for (int i = 1; i <= numberoflayer; i++)
{
for (empty = 1; empty <= (numberoflayer - i); empty++)
Console.Write(" ");
for (number = 1; number <= i; number++)
Console.Write('*');
for (number = (i - 1); number >= 1; number--)
Console.Write('*');
Console.WriteLine();
}
This draws your christmas tree:
int height = 4;
for (int i = 0; i < height; i++)
{
int countSpaces = (int)Math.Ceiling((height * 2 / 2d) - i);
int countStars = 1 + (i * 2);
string line = new string(' ', countSpaces) + new string('*', countStars);
Console.WriteLine(line);
}
Dirty code but there you go
int height = 4;
string empty = " ";
String star = "";
for(int i = 0; i<height; i++)
{
star += " *";
empty = empty.Length > 0 ? empty.Remove(0,1) : " ";
Console.WriteLine(empty + star);
}
Console.ReadLine();

Reversing my MergeSort Algorithm

Basically I've got a merge sort in my code to order a group of numbers in a text file. I've given the option through a menu to allow the user to sort these numbers in ascending and descending order. At the moment I only have it one way and I can't for the life of me figure out how to reverse it. It's probably something really simple. Here's my code:
Methods
static public void mergemethod(int [] numbers, int left, int mid, int right)
{
int [] temp = new int[144];
int i, left_end, num_elements, tmp_pos;
left_end = (mid - 1);
tmp_pos = left;
num_elements = (right - left + 1);
while ((left <= left_end) && (mid <= right))
{
if (numbers[left] <= numbers[mid])
temp[tmp_pos++] = numbers[left++];
else
temp[tmp_pos++] = numbers[mid++];
}
while (left <= left_end)
temp[tmp_pos++] = numbers[left++];
while (mid <= right)
temp[tmp_pos++] = numbers[mid++];
for (i = 0; i < num_elements; i++)
{
numbers[right] = temp[right];
right--;
}
}
static public void sortmethod(int [] numbers, int left, int right)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
sortmethod(numbers, left, mid);
sortmethod(numbers, (mid + 1), right);
mergemethod(numbers, left, (mid+1), right);
}
}
Where it's used.
private static void SortVolume(int sortingAD)
{
if (sortingAD == 1)
{
int[] numbers = Array.ConvertAll(Volume, int.Parse);
int len = 144;
Console.WriteLine("\nAscending order: To return, press any key");
sortmethod(numbers, 0, len - 1);
for (int i = 0; i < 144; i++)
Console.WriteLine(numbers[i]);
}
else if (sortingAD == 2)
{
//This is where the reverse code will go(?)
}
Console.ReadKey();
MainMenu(true);
}
Thanks.

MergeSort Implementation in C#

Currently studying algorithm analysis, and instead of blindly running off of pseudo-code from my textbook, I'm implementing each algorithm in C#. This is the psuedo-code:
MERGE-SORT(A,p,r)
1 if p < r
2 q = (p+r)/2
3 MERGE-SORT(A,p,q)
4 MERGE-SORT(A,q+1,r)
5 MERGE(A,p,q,r)
MERGE(A,p,q,r)
1 n1 = q - p + 1
2 n2 = r - q
3 let L[1..n1+1] and R[1..n2+1] be new arrays
4 for i = 1 to n1
5 L[i] = A[p+i-1]
6 for j = 1 to n2
7 R[j] = A[q+j]
8 L[n1+1] = INF
9 R[n1+1] = INF
10 i = 1
11 j = 1
12 for k = p to r
13 if L[i] <= R[j]
14 A[k] = L[i]
15 i = i + 1
16 else
17 A[k] = R[j]
18 j = j + 1
This is my code:
static void Main(string[] args)
{
int[] unsortedArray = new int[] { 5, 2, 7, 4, 1, 6, 8, 3, 9, 10 };
MergeSort(ref unsortedArray, 1, unsortedArray.Length);
foreach (int element in unsortedArray)
{
Console.WriteLine(element);
}
Console.Read();
}
private static void MergeSort(ref int[] unsortedArray, int leftIndex, int rightIndex)
{
if (leftIndex < rightIndex)
{
int middleIndex = (leftIndex + rightIndex) / 2;
//Sort left (will call Merge to produce a fully sorted left array)
MergeSort(ref unsortedArray, leftIndex, middleIndex);
//Sort right (will call Merge to produce a fully sorted right array)
MergeSort(ref unsortedArray, middleIndex + 1, rightIndex);
//Merge the sorted left & right to finish off.
Merge(ref unsortedArray, leftIndex, middleIndex, rightIndex);
}
}
private static void Merge(ref int[] unsortedArray, int leftIndex, int middleIndex, int rightIndex)
{
int lengthLeft = middleIndex - leftIndex + 1;
int lengthRight = rightIndex - middleIndex;
int[] leftArray = new int[lengthLeft + 1];
int[] rightArray = new int[lengthRight + 1];
for (int i = 0; i < lengthLeft; i++)
{
leftArray[i] = unsortedArray[leftIndex + i - 1];
}
for (int j = 0; j < lengthRight; j++)
{
rightArray[j] = unsortedArray[middleIndex + j];
}
leftArray[lengthLeft] = Int32.MaxValue;
rightArray[lengthRight] = Int32.MaxValue;
int iIndex = 0;
int jIndex = 0;
for (int k = leftIndex; k < rightIndex; k++)
{
if (leftArray[iIndex] <= rightArray[jIndex])
{
unsortedArray[k] = leftArray[iIndex];
iIndex++;
}
else
{
unsortedArray[k] = rightArray[jIndex];
jIndex++;
}
}
}
I'm not sure where I'm messing things up -- I tried to follow the pseudo-code as well as I could, but my output is funky (i.e. repeated values and not properly sorted).
Debugging this didn't help me figure out the problem either (recursive solutions get too messy).
Where am I going wrong, and how do I fix it?
As correctly pointed out in the comments, C# array indexing is zero-based, while your pseudo code is one-based.
That being said, here's the errors:
1) Main method
MergeSort(ref unsortedArray, 1, unsortedArray.Length);
has to be changed to:
MergeSort(ref unsortedArray, 0, unsortedArray.Length - 1);
2) Merge method
leftArray[i] = unsortedArray[leftIndex + i - 1];
has to be change to:
leftArray[i] = unsortedArray[leftIndex + i];
3) Merge method
rightArray[j] = unsortedArray[middleIndex + j];
has to be change to:
rightArray[j] = unsortedArray[middleIndex + j + 1];
4) Merge method
for (int k = leftIndex; k < rightIndex; k++)
has to be change to:
for (int k = leftIndex; k <= rightIndex; k++)
BTW, the ref keyword in your code is not really necessay, since you're just modifying the values inside the array and not creating a new instance of it .
private static void Merge(int[]A, int[]aux, int lo, int mid, int hi)
{
for (int k = lo; k <= hi; k++)
aux[k] = A[k];
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid) A[k] = aux[j++];
else if (j > hi) A[k] = aux[i++];
else if (aux[j] < aux[i]) A[k] = aux[j++];
else A[k] = aux[i++];
}
}
private static void Sort(int[] A, int[] aux, int lo, int hi)
{
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
Sort(A, aux, lo, mid);
Sort(A, aux, mid + 1, hi);
if (A[mid + 1] > A[mid]) return;
Merge(A, aux, lo, mid, hi);
}
public static void Sort(int[] A)
{
int[] aux = new int[A.Length];
Sort(A, aux, 0, A.Length - 1);
}
A Simple Merge Sort Implementation.
https://github.com/bharathkumarms/AlgorithmsMadeEasy/blob/master/AlgorithmsMadeEasy/MergeSort.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace AlgorithmsMadeEasy
{
class MergeSort
{
public void MergeSortMethod()
{
var input = System.Console.ReadLine();
string[] sInput = input.Split(' ');
int[] numbers = Array.ConvertAll(sInput, int.Parse);
int len = numbers.Length;
MergeSort_Recursive(numbers, 0, len - 1);
for (int i = 0; i < len; i++)
{
Console.Write(numbers[i] + " ");
}
Console.ReadLine();
}
static public void MergeSort_Recursive(int[] numbers, int left, int right)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
MergeSort_Recursive(numbers, left, mid);
MergeSort_Recursive(numbers, (mid + 1), right);
DoMerge(numbers, left, (mid + 1), right);
}
}
static public void DoMerge(int[] numbers, int left, int mid, int right)
{
int[] temp = new int[numbers.Length];
int i, left_end, num_elements, tmp_pos;
left_end = (mid - 1);
tmp_pos = left;
num_elements = (right - left + 1);
while ((left <= left_end) && (mid <= right))
{
if (numbers[left] <= numbers[mid])
temp[tmp_pos++] = numbers[left++];
else
temp[tmp_pos++] = numbers[mid++];
}
while (left <= left_end)
temp[tmp_pos++] = numbers[left++];
while (mid <= right)
temp[tmp_pos++] = numbers[mid++];
for (i = 0; i < num_elements; i++)
{
numbers[right] = temp[right];
right--;
}
}
}
}
/*
Sample Input:
6 5 3 2 8
Calling Code:
MergeSort ms = new MergeSort();
ms.MergeSortMethod();
*/

Out of memory and overflow exceptions creating small array

I am new to C# and XNA. Have just managed to write a class that generates a triangular grid.
But there is one problem. I can get maximum 27 nodes length triangle.
At 28 it throws Out of memory exception and at 31 -overFlow exception.
I don't understand how it overflows or out of memory... Tried to
calculate all those memory values but they look very tiny.
It is only array of nodes affected by variable. Node class is not very big:
float x; 4 B
float y; 4 B
float z; 4 B
int[] con; int[6] 4*6=24 B
byte pass; 1 B
Color col; 32 b= 4 B
Total: 41B
sequence sum of nodes needed to create triangle is n(n+1)/2
out of memory at 28
28*29/2=406 nodes
total memory:
41*406 = 16646 B = 16.26 kB
Overflows at 31: 496 nodes is 19.9 kB
I did read articles about "out of memory exceptions", that structures size is bigger than it seems and that out of memory happens at sizes of 500MB... there is no way my small triangle would reach such huge size.
This is my whole class:
class TriMatrix
{
int len;
int Lenght;
Node[] node;
VertexPositionColor[] vertex;
public class Node
{
public float x;
public float y;
public float z;
public int[] con;
public byte pass;
public Color col;
public Node(byte passable)
{
pass = passable;
if (pass > 0)
{ col = Color.Green; }
else
{ col = Color.DarkRed; }
x = 0;
z = 0;
con = new int[6];
}
}
public TriMatrix(int lenght)
{
len = lenght;
Lenght = 0;
byte pass;
Random rnd = new Random();
for (int i = 0; i <= len; i++)
{
Lenght += Lenght + 1;
}
node = new Node[Lenght];
int num = 0;
for (int i = 0; i < len; i++)
{
for (int j = 0; j <= i; j++)
{
if (rnd.Next(0, 5) > 0) { pass = 1; } else { pass = 0; }
node[num] = new Node(pass);
node[num].x = (float)i - (float)j / 2.0f;
node[num].y = 0;
node[num].z = (float)j * 0.6f;
if (i < len - 1) { node[num].con[0] = num + i; } else { node[num].con[0] = -1; node[num].col = Color.Violet; }
if (i < len - 1) { node[num].con[1] = num + i + 1; } else { node[num].con[1] = -1; }
if (j < i) { node[num].con[2] = num + 1; } else { node[num].con[2] = -1; node[num].col = Color.Violet; }
if (j < i) { node[num].con[3] = num - i; } else { node[num].con[3] = -1; }
if (i > 0) { node[num].con[4] = num - i - 1; } else { node[num].con[4] = -1; }
if (i > 0) { node[num].con[5] = num - 1; } else { node[num].con[5] = -1; }
if (j == 0) { node[num].col = Color.Violet; }
num++;
}
}
}
public void Draw(Effect effect, GraphicsDevice graphics)
{
VertexPositionColor[] verts = new VertexPositionColor[3];
int num = 0;
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j <= i; j++)
{
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 1].x, node[num + i + 1].y, node[num + i + 1].z), node[num + i + 1].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
if ( j < i)
{
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + 1].x, node[num + 1].y, node[num + 1].z), node[num + 1].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
}
}
num++;
}
}
}
}// endclass
I assume that your bug lies in this loop (taking the liberty to correct your spelling):
for (int i = 0; i <= len; i++)
{
Length += Length + 1;
}
Within the loop, you are incrementing the value of Length by itself plus one. This effectively means that you are doubling the value of Length for each iteration, resulting in exponential growth.
During the first few iterations, the values of Length will be: 1, 3, 7, 15, 31, 63, …. We can generalize this sequence such that, at iteration i, the value of Length will be 2i+1−1. At iteration 28, this would be 536,870,911. At iteration 31, this would be 4,294,967,295.
Edit: As you mentioned in the comment below, the correct fix for computing the number of elements in a triangular grid of length len would be:
for (int i = 1; i <= len; i++)
{
Length += i;
}
This is equivalent to the summation 1 + 2 + 3 + … + len, which computes what is known as the triangular number. It may be succinctly computed using the formula:
Length = len * (len + 1) / 2;
The reason that this number grows so large is that it is a square relation; for a side of length n, you need an area of approximately half of n².

Categories