有没有办法从 C# 字典中直接访问原始键对象(其中键是引用类型)?我在另一个网站(http://www.pcreview.co.uk/forums/get-original-key-object-dictionary-t3351718.html)上看到过这个问题,因为大多数响应者不明白为什么会这样是一个合理的问题/不是不良底层设计的症状,我在下面给出背景细节。
到目前为止,我的解决方法是:
(a) 遍历检查是否相等的键,这是 O(n) 复杂度:(
(b) 维护一个额外的实习生池(例如,另一个将键映射到自己的字典)。这使我们达到 O(1) 复杂性,但需要额外的内存,将项目添加到字典时需要额外的工作,未能正确协调的风险......这些都不是致命的,但它并不理想,如果Dictionary<> 提供了一种按键检索键的方法。
具体来说,我有一个表示状态图的 Dictionary<State, List<State>>:每个键表示状态机的状态,关联的值是可从那里直接到达的相邻状态列表。例如,状态可以表示棋盘的配置,而相邻状态将是单步可到达的配置。
我从初始状态开始填充状态图,构建邻居列表,然后递归调用每个邻居的填充例程。在每个阶段,算法都会检查邻居状态是否已经是字典中的键(否则我们永远不会完成)。State 是一个引用类型(即一个类),具有重写的 GetHashCode 和 Equals 方法。
从语义上讲,这很好用。但是现在邻居列表是状态的不同副本而不是原始副本,所以如果有 N 个状态,每个状态平均有 M 个邻居,我们在内存中有 NxM 个状态对象,而我们真的只想要 N 个状态对象和 NxM对 State 对象的引用。除了增加内存占用之外,它还会使相等测试变慢,因为您无法从 Equals() 中的引用相等快捷方式中受益。
从评论看来问题还不清楚,所以这里有一些伪代码可以更好地说明它:
public class StateGraphExample
{
public static void Main()
{
State initialState = State.GetInitialState();
var graph = new Dictionary<State, List<State>>();
BuildGraph(initialState, graph);
}
public static void BuildGraph(State state, Dictionary<State, List<State>> graph)
{
var neighbours = new List<State>();
foreach (State.Move move in state.GetValidMoves())
neighbours.Add(state.ApplyMove(move));
graph[state] = neighbours;
foreach (State neighbour in neighbours)
if (!graph.ContainsKey(neighbour))
BuildGraph(neighbour, graph);
}
public class State
{
//Lots of data members here...
public static State GetInitialState()
{ /* Return State object representing initial state... */ }
public class Move
{ /* Representation of a move that takes us from one State to another... */ }
public List<State.Move> GetValidMoves()
{ /* Return valid moves from this State object... */ }
public State ApplyMove(State.Move move)
{ /* Clones this State object, applies move to it and returns the result... */ }
public override int GetHashCode()
{ /* Compute hash... */ }
public override bool Equals(object obj)
{ /* Test equality... */ }
private State Clone()
{ /* Clone self... */ }
}
}