I am attempting an insertion sort algorithm in c# and struggling to fix this error message:
"System.IndexOutOfRangeException' occurred in algorithmsAssignment.exe"
As soon as it reaches the while loop, the code breaks and gives me the message. Any help would be appreciated
(I have had to do string.compare as I'm using a 2D array string.
static void insertionSort(int columnSort, bool accendingOrder)
{
int column = columnSort - 1;
int i, j;
for (i = 1; i < dataArray.GetLength(1); i++)
{
string key = dataArray[column, i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && string.Compare(dataArray[column, j - 1],
dataArray[j, column]) > 0)
{
dataArray[column, j + 1] = dataArray[column, j];
j = j - 1;
}
dataArray[column, j + 1] = key;
}
}
In your first for iteration: ( i = 1 )
string key = dataArray[column, i];
j = i - 1;
// J value is 0
while (j >= 0 && string.Compare(dataArray[column, j - 1], //Here, j - 1 = -1, since j = 0
....
....
I bet there is your index out of range, since index -1 can't exist.
Cheers
You will get error for i=1 because you have this conditions:
j = i - 1; //j=0 for i=1
and wrong condition in while loop
while (j >= 0 && string.Compare(dataArray[column, j - 1],
dataArray[j, column]) > 0)
this condition in while loop dataArray[column, j - 1] will throw IndexOutOfRange exception because
j-1=-1 for j=0
Related
I don't know what to do, my program is not working
I need to sort a two-dimensional array by the first elements of a row in descending order by rearranging the rows
(need to sort string without sort item)
Let's say I'm given an array:
1 2 3
4 5 6
7 8 9
As a result of the program, I need to get:
7 8 9
4 5 6
1 2 3
`
using System;
namespace BubbleSort
{
internal class Program
{
static void Main(string[] args)
{
//Объявление массива и его размерности
const int n = 3;
int bubble;
int[,] A =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 },
};
//Алгоритм пузырьковой сортировки
for (int i = 0; i < n; i++)
{
for(int j = 0; j < n - 1; j++)
{
if (A[i, 0] < A[i++, 0])
{
for(j = 0; j < n-1; j++)
{
bubble = A[i, j];
A[i, j] = A[i, j+1];
A[i, j+1] = bubble;
}
}
}
}
//Вывод массива
for (int y = 0; y < n; y++)
{
for (int x = 0; x < n; x++)
{
Console.Write(A[y, x] + " ");
}
Console.WriteLine();
}
}
}
}
`
From the code in your comments, I'm not sure why you have a nested loop for swapping the values since a single loop will do. I've removed that here.
If you refer to the pseudocode implementation on Wikipedia, you'll see that you need to keep running multiple passes across the array until everything is sorted. You can do this like so:
bool swapped;
do
{
swapped = false; // reset swapped
for (int i = 0; i < n - 1; i++) // loop through all but the last row
{
if (A[i, 0] < A[i + 1, 0]) // determine if this row needs to be swapped with the next row
{
swapped = true; // mark swapped
for (int j = 0; j < n; j++) // swap each item in row i with each item in row i+1
{
int tmp = A[i, j];
A[i, j] = A[i + 1, j];
A[i + 1, j] = tmp;
}
}
}
}
while (swapped); // if we swapped anything, we need to make another pass to ensure the array is sorted
We can also do away with the need for n by using .GetUpperBound(dimension) which returns a value between 0 and n - 1 (where n is the count of items in the array in that dimension). Because the result is effectively n - 1, I've modified the loop conditions slightly:
bool swapped;
do
{
swapped = false;
for (int i = 0; i < A.GetUpperBound(0); i++)
{
if (A[i, 0] < A[i + 1, 0])
{
swapped = true;
for (int j = 0; j <= A.GetUpperBound(1); j++)
{
int tmp = A[i, j];
A[i, j] = A[i + 1, j];
A[i + 1, j] = tmp;
}
}
}
}
while (swapped);
We can also refer to the "Optimizing bubble sort" section of the Wikipedia page and implement that instead, which will make our code run more optimally:
int n = A.GetUpperBound(0); // get the initial value of n
do
{
int newn = 0; // default newn to 0, so if no items are visited, it will remain 0 and the loop will exit
for (int i = 0; i < n; i++)
{
if (A[i, 0] < A[i + 1, 0])
{
for (int j = 0; j <= A.GetUpperBound(1); j++)
{
int tmp = A[i, j];
A[i, j] = A[i + 1, j];
A[i + 1, j] = tmp;
}
newn = i; // store the current (highest) value of i swapped
}
}
n = newn; // set the value of n to the highest value of i swapped
}
while (n > 0); // loop until n == 0
The logic here (as explained on Wikipedia) is that by the end of the first pass, the last item is in the correct position. By the end of the second pass, the second-to-last and last items are in the correct position, and so on. So each time, we can visit one less item. When we have 0 items to visit, we have 0 items to swap, and the sort is complete.
You can see this optimised version in this YouTube visualisation.
I think the line
if (A[i, 0] < A[i++, 0])
should read
if (A[i, 0] < A[i+ 1, 0])
This question already has answers here:
How is a StackOverflowException detected?
(6 answers)
Closed 1 year ago.
void OpenClean( int i, int j) {
bnt[i, j] = new Button();
if (!bnt[i,j].Enabled) return;
bnt[i, j].Enabled = false;
bnt[i,j].BackColor = Color.Aquamarine;
bnt[i, j].Text = data[i, j].ToString();
if (data[i, j] == 0) {
if (i > 0 && j > 0 && data[i - 1, j - 1] == 0) OpenClean(i - 1, j - 1);
if (i > 0 && data[i - 1, j] == 0) OpenClean(i - 1, j);
if (i > 0 && j < 8 && data[i - 1, j + 1] == 0) OpenClean(i - 1, j + 1);
if (j > 0 && data[i, j - 1] == 0) OpenClean(i, j - 1);
if (j < 8 && data[i, j + 1] == 0) OpenClean(i, j + 1);
if (i < 8 && j > 0 && data[i + 1, j - 1] == 0) OpenClean(i + 1, j - 1);
if (i < 8 && data[i + 1, j] == 0) OpenClean(i + 1, j);
if (i < 8 && j < 8 && data[i + 1, j + 1] == 0) OpenClean(i + 1, j + 1);
}
It tells me Process is terminated due to StackOverflowException.
Because of my limited experience,I didn't find an effective way.
This question has been bothering me for a long time.
Please help or try to give me some ideas how to solve it.
Thanks in advance!
You never set data[i, j] to a value other than 0. Therefore, the recursion never stops. You must set the inspected cells to a different value so that they will not get inspected again and again and again ...
You also create a new button with bnt[i, j] = new Button(); instead of inspecting the existing button. Therefore you will never see a button with Enabled == false, since the default value for Enabled is true.
It is better to base the logic on the model (i.e. data[,]) and to use the UI (the controls) only for display.
const int Inspected = -1;
void OpenClean( int i, int j) {
...
if (data[i, j] == 0) {
data[i, j] = Inspected; // <====== This stops the endless recursion!
if (i > 0 && j > 0 && data[i - 1, j - 1] == 0) OpenClean(i - 1, j - 1);
...
}
}
And, btw., you are testing for 0 twice. Before calling OpenClean and inside OpenClean again. Just do it once.
void OpenClean( int i, int j) {
if (data[i, j] == 0) { // This one does the job.
data[i, j] = Inspected; // <======
// bnt[i, j] = new Button(); <=== drop this!
// if (!bnt[i,j].Enabled) return; <=== drop this! We test data instead.
bnt[i, j].Enabled = false;
bnt[i,j].BackColor = Color.Aquamarine;
bnt[i, j].Text = data[i, j].ToString();
if (i > 0 && j > 0) OpenClean(i - 1, j - 1);
if (i > 0 ) OpenClean(i - 1, j);
if (i > 0 && j < 8) OpenClean(i - 1, j + 1);
if ( j > 0) OpenClean(i, j - 1);
if ( j < 8) OpenClean(i, j + 1);
if (i < 8 && j > 0) OpenClean(i + 1, j - 1);
if (i < 8 ) OpenClean(i + 1, j);
if (i < 8 && j < 8) OpenClean(i + 1, j + 1);
}
}
If you do the range test at the beginning of OpenClean, you can get rid of all the other range tests.
void OpenClean( int i, int j) {
if (i > 0 && i < 8 && j > 0 && j < 8 && data[i, j] == 0) { // This one does the job.
data[i, j] = Inspected; // <======
bnt[i, j].Enabled = false;
bnt[i,j].BackColor = Color.Aquamarine;
bnt[i, j].Text = data[i, j].ToString();
OpenClean(i - 1, j - 1);
OpenClean(i - 1, j);
OpenClean(i - 1, j + 1);
OpenClean(i, j - 1);
OpenClean(i, j + 1);
OpenClean(i + 1, j - 1);
OpenClean(i + 1, j);
OpenClean(i + 1, j + 1);
}
}
Using the C# 9.0 patterns, you can simplify the condition somewhat
if (i is > 0 and < 8 && j is > 0 and < 8 && data[i, j] == 0)
if (Int32.Parse(strTotals) == 0 && nTotalCount != 0)
{
nTotalCount = 0;
for (int j = 0; j < 66; j++)
{
if (GameHistoryPicBox1[j].InvokeRequired)
{
GameHistoryPicBox1[j].BeginInvoke(new MethodInvoker(() =>
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2; // Line4
}));
}
else
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2;
}
}
}
I have been checking nTotalCount value by using thread.
If nTotalCount is zero, then I must clean all game picture box image.
So I was implement above code.
Unfortunately, I got the error:
An unhandled exception of type 'System.IndexOutOfRangeException'
on Line 2 and 4.
And the j value was 66.
Is it possible that j value could be 66?
This is because of how closures work. Your lambda expression that you're creating and passing to the MethodInvoker references the j variable by reference. Thus when this piece of code is being executed (which can be almost any time, as it's asynchronous) the j variable can have any value from 0 to 66. And it can be 66 after the loop has finished.
A quick fix is to make a copy of j:
int index = j;
GameHistoryPicBox1[index].BeginInvoke(new MethodInvoker(() =>
{
if ((index + index / 6) % 2 == 0)
GameHistoryPicBox1[index].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[index].Image = Properties.Resources.al2; // Line4
}));
You can read more about this here.
The variable j is being passed into the closure, and because the call is asynchronous, it is actually executed at some point after the loop completes. You cannot be sure what the value of j will be when the delegate is executed.
Try passing the value of j in as a parameter to the delegate, like this:
GameHistoryPicBox1[j].BeginInvoke(new Action<int>((x) =>
{
if ((x + x / 6) % 2 == 0)
GameHistoryPicBox1[x].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[x].Image = Properties.Resources.al2;
}), j);
You've been bitten by the loop-variable-in-a-closure-bug.
Instead of
for (int j = 0; j < 66; j++)
{
//blahblahblah
}
write
for (int jj = 0; jj < 66; jj++)
{
int j = jj;
//blahblahblah
}
Hi i'm using the levenshtein algorithm to calculate the difference between two strings, using the below code. It currently provides the total number of changes which need to be made to get from 'answer' to 'target', but i'd like to split these up into the types of errors being made. So classifying an error as a deletion, substitution or insertion.
I've tried adding a simple count but i'm new at this and don't really understand how the code works so not sure how to go about it.
static class LevenshteinDistance
{
/// <summary>
/// Compute the distance between two strings.
/// </summary>
public static int Compute(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
}
Thanks in advance.
I have the following implementation, but I want to add a threshold, so if the result is going to be greater than it, just stop calculating and return.
How would I go about that?
EDIT: Here is my current code, threshold is not yet used...the goal is that it is used
public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
{
// Return trivial case - where they are equal
if (string1.Equals(string2))
return 0;
// Return trivial case - where one is empty
if (String.IsNullOrEmpty(string1) || String.IsNullOrEmpty(string2))
return (string1 ?? "").Length + (string2 ?? "").Length;
// Ensure string2 (inner cycle) is longer
if (string1.Length > string2.Length)
{
var tmp = string1;
string1 = string2;
string2 = tmp;
}
// Return trivial case - where string1 is contained within string2
if (string2.Contains(string1))
return string2.Length - string1.Length;
var length1 = string1.Length;
var length2 = string2.Length;
var d = new int[length1 + 1, length2 + 1];
for (var i = 0; i <= d.GetUpperBound(0); i++)
d[i, 0] = i;
for (var i = 0; i <= d.GetUpperBound(1); i++)
d[0, i] = i;
for (var i = 1; i <= d.GetUpperBound(0); i++)
{
for (var j = 1; j <= d.GetUpperBound(1); j++)
{
var cost = string1[i - 1] == string2[j - 1] ? 0 : 1;
var del = d[i - 1, j] + 1;
var ins = d[i, j - 1] + 1;
var sub = d[i - 1, j - 1] + cost;
d[i, j] = Math.Min(del, Math.Min(ins, sub));
if (i > 1 && j > 1 && string1[i - 1] == string2[j - 2] && string1[i - 2] == string2[j - 1])
d[i, j] = Math.Min(d[i, j], d[i - 2, j - 2] + cost);
}
}
return d[d.GetUpperBound(0), d.GetUpperBound(1)];
}
}
This is Regarding ur answer this: Damerau - Levenshtein Distance, adding a threshold
(sorry can't comment as I don't have 50 rep yet)
I think you have made an error here. You initialized:
var minDistance = threshold;
And ur update rule is:
if (d[i, j] < minDistance)
minDistance = d[i, j];
Also, ur early exit criteria is:
if (minDistance > threshold)
return int.MaxValue;
Now, observe that the if condition above will never hold true! You should rather initialize minDistance to int.MaxValue
Here's the most elegant way I can think of. After setting each index of d, see if it exceeds your threshold. The evaluation is constant-time, so it's a drop in the bucket compared to the theoretical N^2 complexity of the overall algorithm:
public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
{
...
for (var i = 1; i <= d.GetUpperBound(0); i++)
{
for (var j = 1; j <= d.GetUpperBound(1); j++)
{
...
var temp = d[i,j] = Math.Min(del, Math.Min(ins, sub));
if (i > 1 && j > 1 && string1[i - 1] == string2[j - 2] && string1[i - 2] == string2[j - 1])
temp = d[i,j] = Math.Min(temp, d[i - 2, j - 2] + cost);
//Does this value exceed your threshold? if so, get out now
if(temp > threshold)
return temp;
}
}
return d[d.GetUpperBound(0), d.GetUpperBound(1)];
}
You also asked this as a SQL CLR UDF question so I'll answer in that specific context: you best optmiziation won't come from optimizing the Levenshtein distance, but from reducing the number of pairs you compare. Yes, a faster Levenshtein algorithm will improve things, but not nearly as much as reducing the number of comparisons from N square (with N in the millions of rows) to N*some factor. My proposal is to compare only elements who have the length difference within a tolerable delta. On your big table, you add a persisted computed column on LEN(Data) and then create an index on it with include Data:
ALTER TABLE Table ADD LenData AS LEN(Data) PERSISTED;
CREATE INDEX ndxTableLenData on Table(LenData) INCLUDE (Data);
Now you can restrict the sheer problem space by joining within an max difference on lenght (eg. say 5), if your data's LEN(Data) varies significantly:
SELECT a.Data, b.Data, dbo.Levenshtein(a.Data, b.Data)
FROM Table A
JOIN Table B ON B.DataLen BETWEEN A.DataLen - 5 AND A.DataLen+5
Finally got it...though it's not as beneficial as I had hoped
public static int DamerauLevenshteinDistance(string string1, string string2, int threshold)
{
// Return trivial case - where they are equal
if (string1.Equals(string2))
return 0;
// Return trivial case - where one is empty
if (String.IsNullOrEmpty(string1) || String.IsNullOrEmpty(string2))
return (string1 ?? "").Length + (string2 ?? "").Length;
// Ensure string2 (inner cycle) is longer
if (string1.Length > string2.Length)
{
var tmp = string1;
string1 = string2;
string2 = tmp;
}
// Return trivial case - where string1 is contained within string2
if (string2.Contains(string1))
return string2.Length - string1.Length;
var length1 = string1.Length;
var length2 = string2.Length;
var d = new int[length1 + 1, length2 + 1];
for (var i = 0; i <= d.GetUpperBound(0); i++)
d[i, 0] = i;
for (var i = 0; i <= d.GetUpperBound(1); i++)
d[0, i] = i;
for (var i = 1; i <= d.GetUpperBound(0); i++)
{
var im1 = i - 1;
var im2 = i - 2;
var minDistance = threshold;
for (var j = 1; j <= d.GetUpperBound(1); j++)
{
var jm1 = j - 1;
var jm2 = j - 2;
var cost = string1[im1] == string2[jm1] ? 0 : 1;
var del = d[im1, j] + 1;
var ins = d[i, jm1] + 1;
var sub = d[im1, jm1] + cost;
//Math.Min is slower than native code
//d[i, j] = Math.Min(del, Math.Min(ins, sub));
d[i, j] = del <= ins && del <= sub ? del : ins <= sub ? ins : sub;
if (i > 1 && j > 1 && string1[im1] == string2[jm2] && string1[im2] == string2[jm1])
d[i, j] = Math.Min(d[i, j], d[im2, jm2] + cost);
if (d[i, j] < minDistance)
minDistance = d[i, j];
}
if (minDistance > threshold)
return int.MaxValue;
}
return d[d.GetUpperBound(0), d.GetUpperBound(1)] > threshold
? int.MaxValue
: d[d.GetUpperBound(0), d.GetUpperBound(1)];
}