我的问题是我收到了Index was out of range
异常,我想确切地知道发生了什么,以及导致错误的特定数组和索引是什么。我只需逐步完成我的程序即可找到它,因为它使用访问运算符[]
的次数是数百万。那么有什么方法可以让我的节目再次回归"抛出异常时进入调试模式?我无法弄清楚如何解决这个问题,除非通过可能需要数小时的蛮力。
这是一个完整的代码转储,如果有帮助:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace StringSet
{
class StringSet
{
private List<List<string>> _Buckets;
public int NumStrings { get; private set; }
public StringSet ( )
{
this._Buckets = new List<List<string>>();
this.NumStrings = 0;
}
public StringSet ( string[] S )
{
// better way to do this?
this._Buckets = new List<List<string>>();
foreach ( string s in S ) this._Buckets.Add(new List<string>());
foreach ( string s in S ) { this.Insert(s); }
}
private int _GetBucketNumber ( string s, List<List<string>> Buckets )
{
// s: string whose index to look up
// Buckets: source buckets
// disallow empty or NULL strings
if ( String.IsNullOrEmpty(s) ) { throw new ArgumentException("Cannot add empty or NULL string to set"); }
if ( Buckets.Count == 0 ) { throw new ArgumentException("Tried to call _GetBucketNumber on empty bucket list"); }
// Bernstein hash
// http://www.eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
int result = (int)s[0];
for ( int i = 1; i < s.Length; ++i ) { result = 33 * result + (int)s[i]; }
return result % Buckets.Count;
}
private void _RehashIfNecessary ( )
{
// if the number of strings in the set exceeds the number of buckets,
// increase the number of buckets to either double its current size
// or the largest number of buckets possible, whichever is smaller
if ( this.NumStrings > this._Buckets.Count )
{
List<List<string>> NewBuckets = new List<List<string>>(Math.Min(this._Buckets.Count * 2, Int32.MaxValue));
foreach ( List<string> Bucket in this._Buckets )
{
foreach ( string s in Bucket )
{
NewBuckets[this._GetBucketNumber(s, NewBuckets)].Add(s);
}
}
this._Buckets = NewBuckets;
}
}
public void Insert ( string s )
{
// disallow empty or NULL strings
if ( String.IsNullOrEmpty(s) ) { throw new ArgumentException("Cannot add empty or NULL string to set"); }
// Get bucket that string belongs in
int k = this._GetBucketNumber(s, this._Buckets);
if (k >= this._Buckets.Count) { Console.WriteLine("Found problem! GetBucketNumber return {0}, whichs is bigger or equal to than this._Buckets.Count={1}", k, this._Buckets.Count); }
List<string> Bucket = this._Buckets[this._GetBucketNumber(s,this._Buckets)];
// Add if not already there
if ( Bucket.IndexOf(s) == -1 ) { Bucket.Add(s); }
++NumStrings; _RehashIfNecessary();
}
public bool Contains ( string s )
{
// returns true or false depending on whether s is a
// string currently in the set
return (this._Buckets[this._GetBucketNumber(s,this._Buckets)].IndexOf(s) != -1);
}
public void RunPerformanceTest ( )
{
// tests string hash set against regular List<string>
// in terms of lookup
// create list of all elements in hash set
List<string> ListVersion = new List<string>(),
Copy = new List<string>();
foreach ( List<string> Bucket in this._Buckets )
{
foreach ( string Str in Bucket )
{
ListVersion.Add(Str);
Copy.Add(Str);
}
}
// calculate average time to look up all elements
Stopwatch Watch = new Stopwatch();
long tList = 0, tHset = 0; // ms
foreach ( string Str in Copy )
{
// measure time to look up string in ordinary list
Watch.Start();
if ( ListVersion.Contains(Str) ) { }
Watch.Stop();
tList += Watch.ElapsedTicks;
// now measure time to look up same string in my hash set
Watch.Reset();
Watch.Start();
if ( this.Contains(Str) ) { }
Watch.Stop();
tHset += Watch.ElapsedTicks;
Watch.Reset();
}
int n = Copy.Count;
Console.WriteLine("Average ticks to look up in List: {0}", tList / n);
Console.WriteLine("Average ticks to look up in hashset: {0}", tHset / n);
}
public void Print ( )
{
for ( int i = 0; i < this._Buckets.Count; ++i )
{
Console.WriteLine("Bucket {0}: {1}", i, string.Join(",",this._Buckets[i].ToArray()));
}
}
}
class Program
{
static void Main ( string[] args )
{
try
{
List<string> Words = new List<string>();
Console.WriteLine("Reading dictionary words from text file into hash set ...");
System.IO.StreamReader file = new System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory + "testfiles\\dictionary.txt");
string line;
while ( (line = file.ReadLine()) != null )
{
Words.Add(line);
}
Console.WriteLine("DONE!");
StringSet TestSet = new StringSet(Words.ToArray());
Console.WriteLine("Running performance test ...");
TestSet.RunPerformanceTest();
Console.WriteLine("DONE!");
}
catch ( Exception E )
{
Console.WriteLine("Exception occured: {0}", E.Message);
}
Console.Read(); // just to keep console open
}
}
}