📜  C# 创建哈希表链表 - C# (1)

📅  最后修改于: 2023-12-03 14:39:45.386000             🧑  作者: Mango

C#创建哈希表链表

哈希表是一个使用哈希函数来映射键值对的数据结构。而哈希链表则是一个使用链表来解决哈希冲突的哈希表。在C#中,可以通过使用泛型类Dictionary<TKey, TValue>来创建一个哈希表。这个类已经在内部实现了哈希链表,我们只需要提供键和值的类型就行了。

创建一个简单的哈希表

我们可以使用Dictionary<TKey, TValue>类来创建一个简单的哈希表。代码如下:

Dictionary<string, int> hashTable = new Dictionary<string, int>();
hashTable.Add("apple", 3);
hashTable.Add("banana", 5);
hashTable.Add("pear", 1);

在上面的代码中,我们创建了一个Dictionary<string, int>对象,它使用string作为键的类型,int作为值的类型。然后,我们使用Add方法向哈希表中添加了三个键值对。

查询哈希表中的值

我们可以使用哈希表中的键来查询它对应的值。代码如下:

int value = 0;
if (hashTable.TryGetValue("apple", out value))
{
    Console.WriteLine("The value of apple is {0}", value);
}
else
{
    Console.WriteLine("The apple is not found.");
}

在上面的代码中,我们使用TryGetValue方法来获取键为“apple”的值。这个方法将会返回一个布尔值,表示哈希表中是否找到了这个键。如果找到了,它将会返回true,并将这个值赋给value变量。否则,它将会返回false,我们需要自己来处理这种情况。

遍历哈希表

我们也可以遍历哈希表中的所有键值对。代码如下:

foreach (KeyValuePair<string, int> pair in hashTable)
{
    string key = pair.Key;
    int value = pair.Value;
    Console.WriteLine("The value of {0} is {1}", key, value);
}

在上面的代码中,我们使用foreach循环来遍历哈希表中的所有键值对。每次循环中,我们都可以使用pair.Key和pair.Value属性来分别获取当前键值对的键和值。

创建一个自定义的哈希表

如果我们需要创建一个自定义的哈希表,我们可以实现一个泛型类HashTable<TKey, TValue>。我们需要提供两个类型参数,一个表示键的类型,另一个表示值的类型。代码如下:

public class HashTable<TKey, TValue>
{
    private LinkedList<KeyValuePair<TKey, TValue>>[] buckets;
    private const int defaultCapacity = 16;
    private int count = 0;

    public HashTable()
    {
        buckets = new LinkedList<KeyValuePair<TKey, TValue>>[defaultCapacity];
    }

    public HashTable(int capacity)
    {
        buckets = new LinkedList<KeyValuePair<TKey, TValue>>[capacity];
    }

    public int Count 
    { 
        get { return count; } 
    }

    public TValue this[TKey key]
    {
        get
        {
            int bucketIndex = GetBucketIndex(key);
            LinkedList<KeyValuePair<TKey, TValue>> bucket = buckets[bucketIndex];
            if (bucket != null)
            {
                foreach (KeyValuePair<TKey, TValue> pair in bucket)
                {
                    if (pair.Key.Equals(key))
                    {
                        return pair.Value;
                    }
                }
            }

            throw new KeyNotFoundException();
        }

        set
        {
            int bucketIndex = GetBucketIndex(key);
            if (buckets[bucketIndex] == null)
            {
                buckets[bucketIndex] = new LinkedList<KeyValuePair<TKey, TValue>>();
            }

            bool keyFound = false;
            foreach (KeyValuePair<TKey, TValue> pair in buckets[bucketIndex])
            {
                if (pair.Key.Equals(key))
                {
                    pair.Value = value;
                    keyFound = true;
                    break;
                }
            }

            if (!keyFound)
            {
                LinkedListNode<KeyValuePair<TKey, TValue>> node = new LinkedListNode<KeyValuePair<TKey, TValue>>(new KeyValuePair<TKey, TValue>(key, value));
                buckets[bucketIndex].AddLast(node);
                count++;
            }
        }
    }

    private int GetBucketIndex(TKey key)
    {
        int hashcode = key.GetHashCode();
        int bucketIndex = hashcode % buckets.Length;
        return bucketIndex;
    }
}

在上面的代码中,我们定义了一个HashTable<TKey, TValue>类,它包含了一个buckets数组和一个count变量。buckets数组用来存储我们的键值对,而count变量用来记录哈希表中有多少个键值对。

我们还实现了一个GetBucketIndex方法来计算一个键对应的桶的索引。这个方法将会使用键的哈希码来计算,然后取模来获得一个索引值。

在我们的HashTable<TKey, TValue>类中,我们还实现了一个this索引器,用来获取或设置指定键的值。在这个索引器中,我们使用GetBucketIndex方法来获取这个键对应的桶的索引。然后,我们使用buckets数组来获取这个桶。如果这个桶为空,则说明哈希表中没有这个键。如果这个桶不为空,则说明哈希表中可能存在这个键。我们遍历这个桶中的所有键值对,看看是否存在对应的键。如果存在,则返回对应的值。如果不存在,则抛出一个KeyNotFoundException异常。

如果我们设置了一个不存在的键,我们首先需要通过GetBucketIndex方法来获取对应的桶的索引。然后,我们需要检查这个桶是否为空。如果这个桶为空,我们需要创建一个新的链表,并将其放到这个桶中。然后,我们遍历这个桶中的所有键值对,看看是否存在对应的键。如果存在,则使用新的值来替换旧的值。如果不存在,则将这个键值对添加到这个链表中,并将count加一。

总结

哈希表链表是一个非常常用的数据结构,它可以用来高效地存储大量的键值对。在C#中,我们可以使用泛型类Dictionary<TKey, TValue>来创建一个哈希表,也可以通过实现HashTable<TKey, TValue>类来创建一个自定义的哈希表。无论我们使用哪种方法,我们都需要知道如何遍历哈希表中的所有键值对,以及如何获取或设置指定键的值。