导致所有这些错误的原因包括此代码中的ArgumentException?

时间:2016-04-06 05:34:29

标签: c# .net visual-studio data-structures

我试图编写一个相当简单的字符串哈希集的实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringSet
{

    class StringSet
    {

        private List<List<string>> _Buckets;
        private int _numStrings;

        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); ++_numStrings; }
        }

        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"); }

            // XOR characters together and mod by length of buckets
            char c = s[0];
            for ( int i = 1; i < s.Length; ++i ) { c ^= s[i]; }
            return (int)c % 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
            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 Print ( )
        {
            for ( int i = 0; i < this._Buckets.Count; ++i )
            {
                Console.WriteLine("Bucket {0}: {1}", i, this._Buckets[i].ToArray().ToString());
            }
        }

    }

    class Program
    {
        static void Main ( string[] args )
        {
            string[] strs = new string[] { "apple", "potato", "car", "cat", "dog", "sheep", "Trump" };
            try
            {
                StringSet TestSet = new StringSet(strs);
                TestSet.Print();
            }
            catch ( Exception E )
            {
                Console.WriteLine("Exception occured: {0}", E.Message);
            }
        }
    }
}

我得到了大量的错误

'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\12.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Users\Me\Documents\Visual Studio 2013\Projects\StringSet\StringSet\bin\Debug\StringSet.vshost.exe'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The thread 0x1164 has exited with code 259 (0x103).
The thread 0x1594 has exited with code 259 (0x103).
The thread 0x1588 has exited with code 0 (0x0).
The thread 0x1744 has exited with code 0 (0x0).
The thread 0xc88 has exited with code 259 (0x103).
'StringSet.vshost.exe' (CLR v4.0.30319: StringSet.vshost.exe): Loaded 'C:\Users\Me\Documents\Visual Studio 2013\Projects\StringSet\StringSet\bin\Debug\StringSet.exe'. Symbols loaded.
A first chance exception of type 'System.ArgumentException' occurred in StringSet.exe
The thread 0x780 has exited with code 259 (0x103).
The thread 0x1170 has exited with code 259 (0x103).
The program '[4252] StringSet.vshost.exe' has exited with code 0 (0x0).

没有跟踪到一行代码而且没有被try - catch抓住,所以我不知道这里出了什么问题。有帮助吗?

另外,我想知道当它完整的代码行加倍时它的大小加倍

List<List<string>> NewBuckets = new List<List<string>>(Math.Min(this._Buckets.Count * 2, Int32.MaxValue));

是最好的方式,或者是否有更聪明的&#34;保持哈希集足够大的方法。因为,如果该集合是10,000个元素并且只会增长到10,001,那么将它扩展到20,000就太大了(9,999浪费了桶),但是没有办法预测它需要多大。对?平均而言,将尺寸增加10%或100%在时间和空间方面都是有效的。

另外,如何防止

溢出
this._Buckets.Count * 2

???我想改变它,以便它Int32.MaxValue如果它溢出。

4 个答案:

答案 0 :(得分:1)

主要问题

首先,您没有“大量错误列表”。如果你仔细阅读,你会发现只有一个:

  

StringSet.exe

中出现'System.ArgumentException'类型的第一次机会异常

其次,您的try-catch确实捕获了该异常。您没有看到控制台输出的原因(可能)是Visual Studio在调试模式下运行应用程序时立即关闭控制台。但是如果你在catch块中放置一个断点,调试器就会命中它。

事实上,抛出的ArgumentException是你自己的一个:

  

试图在空桶列表中调用_GetBucketNumber

堆栈跟踪显示在_RehashIfNecessary的调用中发生这种情况。这样做,因为当你在该方法中NewBuckets[this._GetBucketNumber(s, NewBuckets)].Add(s);时,NewBuckets确实仍然是空的。

List<T> constructor that takes a capacity argument初始化List类的新实例,该实例为空且具有指定的初始容量。因此NewBuckets仍然需要填充适量的List<string>

附带问题

  

我想知道当它完整时我的设备大小加倍,我的代码行是最好的方法,或者是否有“更聪明”的方式

可能有也可能没有更聪明的方式。正如你自己所说,你根本不知道收藏会变得多大。这在大多数情况下都是如此,但并非总是如此。

事实证明,对于许多语言的许多标准容器来说,将某种形式的存储大小加倍是足够的。这是事实,因为扩展存储可能只是分配一个全新的内存块并将所有旧数据复制到它。

在现代个人电脑,笔记本电脑或服务器上,内存基本上是免费的(你要在哈希表中放多少项,真的吗?)而分配新内存和复制数据的动作则不然。因此,除非您正在使用特殊约束,否则扩展时StringSet的大小会加倍。

  

另外,如何防止this._Buckets.Count * 2溢出?我想改变它,如果它溢出就是Int32.MaxValue。

有几种方法。您可以将所有计算转换为Int64,同时保留结果Int32。但是可能会有点侵入性的东西可能是这样的:

class StringSet
{
    private const int HalfOfInt32Max = Int32.MaxValue / 2;
    /* snip */
    private Int32 NewMax(int oldMax)
    {
        if (oldMax < HalfOfInt32Max)
        {
            return oldMax * 2;
        }
        return Int32.MaxValue;
    }
}

然后使用NewMax(this._Buckets.Count);

答案 1 :(得分:0)

_RehashIfNecessary()方法中出现错误。您创建一个新的Buckets列表,并使用新的bucket-list调用方法_GetBucketNumber,其中getBucketNumber-Method中的计数为0.当Buckets.Count等于0时,您将抛出异常。

this._Buckets.Count * 2上的溢出问题:

//Ternary-Expression
List<List<string>> NewBuckets = new List<List<string>>(Int32.MaxValue / 2 < this._Buckets.Count ? Int32.MaxValue : this._Buckets.Count * 2);

//Classic if-else
List<List<string>> NewBuckets = null;
if (Int32.MaxValue / 2 < this._Buckets.Count)
    NewBuckets = new List<List<string>>(Int32.MaxValue);
else
    NewBuckets = new List<List<string>>(this._Buckets.Count * 2);

答案 2 :(得分:0)

缺少

NewBuckets初始化

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));

        // this is missing.
        foreach ( var s in this._Buckets )
        {
            NewBuckets.Add(new List<string>());
        }

        foreach ( List<string> Bucket in this._Buckets )
        {
            foreach ( string s in Bucket )
            {                       
                NewBuckets[this._GetBucketNumber(s, NewBuckets)].Add(s);
            }
        }
        this._Buckets = NewBuckets;
    }
}

检查Working Code

答案 3 :(得分:0)

尝试此操作并将其修改后的内容写回_RehashIfNecessary并打印

class StringSet
{

    private List<List<string>> _Buckets;
    private int _numStrings;

    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); ++_numStrings; }
    }

    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"); }

        // XOR characters together and mod by length of buckets
        char c = s[0];
        for (int i = 1; i < s.Length; ++i)
        {
            c ^= s[i];
        }
        return (int)c % 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>>(_numStrings++);
            foreach (List<string> Bucket in this._Buckets)
            {
                NewBuckets.Add(new List<string>(Bucket));
            }
            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
        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 Print()
    {
        int j;
        //checking the bucket
        for (int i = 0; i < this._Buckets.Count; i++)
        {
            if (_Buckets[i].Count == 0)
                Console.Write($"Bucket {i}: Empty!");
            else
            {
                Console.Write("Bucket {0}: ", i);
                //Checking items within the bucket
                for (j = 0; j < _Buckets[i].Count; j++)
                {
                    Console.Write($"[{this._Buckets[i].ToArray().GetValue(j).ToString()}] ");
                }
            }
            Console.WriteLine();
        }
    }

}

class Program
{
    static void Main(string[] args)
    {
        string[] strs = new string[] { "apple", "potato", "car", "cat", "dog", "sheep", "Trump" };

        StringSet TestSet = new StringSet(strs);
        TestSet.Print();

        Console.Read();
    }
}

回信..