删除同一个键后,C#字典在最后一个索引中没有添加新项?

删除同一个键后,C#字典在最后一个索引中没有添加新项?,c#,C#,我只是在使用C#中的字典时发现了这种行为,在我从字典中删除一个键之后,然后我想使用相同的键进行添加,但新添加的键不在字典的最后一个索引中 Dictionary<string, byte> test = new Dictionary<string, byte>(); test.Add("c", 1); // [{"c", 1}] test.Add("b", 2); // [{"c", 1}, {"b", 2}] test.Add("a", 3); // [{"c",

我只是在使用C#中的
字典
时发现了这种行为,在我从字典中删除一个键之后,然后我想使用相同的键进行添加,但新添加的键不在字典的最后一个索引中

Dictionary<string, byte> test = new Dictionary<string, byte>();

test.Add("c", 1);  // [{"c", 1}]
test.Add("b", 2);  // [{"c", 1}, {"b", 2}]
test.Add("a", 3);  // [{"c", 1}, {"b", 2}, {"a", 3}]
test.Remove("b");  // [{"c", 1}, {"a", 3}]

test.Add("b", 2);  // [{"c", 1}, {"b", 2}, {"a", 3}] <= why this happen?
                   // [{"c", 1}, {"a", 3}, {"b", 2}] and not this?
字典测试=新建字典();
测试。添加(“c”,1);//[{“c”,1}]
测试。添加(“b”,2);//[{“c”,1},{“b”,2}]
测试。添加(“a”,3);//[{“c”,1},{“b”,2},{“a”,3}]
测试。删除(“b”);//[{“c”,1},{“a”,3}]

测试。添加(“b”,2);//[{“c”,1},{“b”,2},{“a”,3}]字典是哈希表。如果查看哈希表的定义,您会注意到哈希表是无序的

我已经有一段时间没有研究.NET dictionary实现的具体细节了,所以在我的故事的其余部分可能会有一些错误——但这是我从细节中记得的:

实现哈希表有很多不同的方案,但是.NET使用的方案与“开放寻址”算法类似,但也有一些不同。基本上,在列表(末尾)添加新项,哈希表(静态数组)在此列表中添加指针。这就是为什么它实际上似乎保持了秩序

在某些时候,由于修改或增长,数据将充满“垃圾”。在这一点上,实现将进行重新编译。如果我没记错的话,这也是它检查是否有太多冲突的点——如果是这样,它将使用一个随机素数将所有哈希值乘以(从而减少冲突的数量)。真的很优雅

由于开放寻址方案指向列表中的元素,因此列表中的顺序并不重要。当你列举一本字典时,你基本上看这个列表

您可能想知道为什么它不枚举哈希代码数组。好的,散列表通常被过度分配,数据被存储在另一个列表中。这仅仅意味着这一替代方案的效率要低得多。如果枚举哈希表,也可能会得到更一致的结果——但由于冲突,仍然无法得到完全一致的结果。(例如,如果A和B位于同一散列码上,则插入顺序将决定A是跟随B还是跟随B)


如果您正在寻找像“set union”这样需要一致排序的算法,我建议使用像
SortedDictionary
这样的容器。

字典是哈希表。如果查看哈希表的定义,您会注意到哈希表是无序的

我已经有一段时间没有研究.NET dictionary实现的具体细节了,所以在我的故事的其余部分可能会有一些错误——但这是我从细节中记得的:

实现哈希表有很多不同的方案,但是.NET使用的方案与“开放寻址”算法类似,但也有一些不同。基本上,在列表(末尾)添加新项,哈希表(静态数组)在此列表中添加指针。这就是为什么它实际上似乎保持了秩序

在某些时候,由于修改或增长,数据将充满“垃圾”。在这一点上,实现将进行重新编译。如果我没记错的话,这也是它检查是否有太多冲突的点——如果是这样,它将使用一个随机素数将所有哈希值乘以(从而减少冲突的数量)。真的很优雅

由于开放寻址方案指向列表中的元素,因此列表中的顺序并不重要。当你列举一本字典时,你基本上看这个列表

您可能想知道为什么它不枚举哈希代码数组。好的,散列表通常被过度分配,数据被存储在另一个列表中。这仅仅意味着这一替代方案的效率要低得多。如果枚举哈希表,也可能会得到更一致的结果——但由于冲突,仍然无法得到完全一致的结果。(例如,如果A和B位于同一散列码上,则插入顺序将决定A是跟随B还是跟随B)


如果您正在寻找像“set union”这样需要一致排序的算法,我建议使用像
SortedDictionary
这样的容器。

您可以在上面看到Dictionary类的实现代码

如您所见,该实现使用了一种跟踪条目数组中自由位置列表的技术,当添加新值时,首先使用自由条目


框架中有一个非泛型类,我相信它总是在列表的末尾添加新项。请记住,访问该IDictionary实现的平均值通常为O(n),而当前使用的通用词典的平均值为O(1)。

您可以在上面看到Dictionary类的实现代码

如您所见,该实现使用了一种跟踪条目数组中自由位置列表的技术,当添加新值时,首先使用自由条目


框架中有一个非泛型类,我相信它总是在列表的末尾添加新项。请记住,访问该IDictionary实现的平均值通常为O(n),而您当前使用的通用词典的平均值为O(1)。

词典不按顺序排列。在内部,
字典
是一个哈希表。哈希表不保留顺序,因此您的观察是正确的。实际问题是:为什么您关心字典中的顺序,因为它没有任何顺序。如果您要查找顺序,为什么不列出一个列表。我相信列表是有序的,字典不是有序的。在内部,
字典
是一个哈希表。哈