【问题标题】:What is the ideal collection type for an adjecency list of a Graph implemented in .NET?在 .NET 中实现的 Graph 的邻接列表的理想集合类型是什么?
【发布时间】:2017-02-19 20:09:25
【问题描述】:

根据 Sedgewick 的算法书,他使用来自 Java 的 Bag 集合来实现图的邻接列表。它非常有意义,因为在 O(1) 中搜索并允许从顶点到另一个顶点的重复边。 可以使用列表,但它们在 O(n) 中的搜索速度很慢,所以我会避免它。

不幸的是 .NET 没有它。有 Wintellect 之类的实现,但它们不是可移植的(或 .NET 标准兼容)。 我应该改用什么?

【问题讨论】:

  • Dictionary<T, List<T>> 够吗?
  • @Enigmativity,你能详细说明一下吗?是否就像我将 Vertex 的第一个实例作为键放在 Dictionary 中一样,并将那个和下一个实例添加到 List 中?
  • 如果你有一组顶点(T 类型)组成图,那么键是一个顶点,List<T> 是键顶点连接到的所有顶点.那么Dictionary<T, List<T>> 就是一个有向循环图。
  • 不,那样不会有效率。您刚刚使用 List 作为邻接列表。在您的情况下,搜索两个顶点是否是邻居将花费 O(n) 时间,其中 n 是邻居的数量。使用袋子,您可以像常数时间一样更好地回答相同的问题。
  • 我不知道在这种情况下是否存在可以使所有操作O(1)的结构。但是我认为您应该明确说明您希望成为 O(1) 的操作,以便更容易回答您的问题。 (即添加边、删除边、检查节点邻接、计算两个相邻节点之间的边等。无论您的情况如何)。

标签: .net algorithm collections f#


【解决方案1】:

经过一番思考,我将自己的 Bag 实现为 Dictionary 这就像一个多组或一个包。这是我在 F# 中的实现:

type Bag<'T when 'T : equality>() =
    let dict = Dictionary<'T,int>()
    let mutable count = 0

    member x.Add = (x:>ICollection<'T>).Add

    member x.Remove = (x:>ICollection<'T>).Remove

    member x.Count = (x:>ICollection<'T>).Count

    member x.Clear = (x:>ICollection<'T>).Clear

    member x.ItemCount item =
        match dict.TryGetValue item with
            | true, itemCount -> itemCount
            | _ -> 0

    interface ICollection<'T> with

        member x.Add item =
            count <- count + 1
            let itemCount =
                match dict.TryGetValue item with
               | true, itemCount -> itemCount
               | _ -> 0
            dict.[item] <- itemCount + 1

        member x.Clear() = dict.Clear()

        member x.Contains item = dict.ContainsKey item

        member x.CopyTo(array, arrayIndex) =
            x
            |> Seq.take(array.Length - arrayIndex)
            |> Seq.iteri (fun i item ->  array.[i + arrayIndex] <- item)

        member x.Count = count

        member x.GetEnumerator()  =
            (x :> ICollection<'T>).GetEnumerator() :> Collections.IEnumerator

        member x.GetEnumerator() =
            let seq =
                let innerSeq (kvp : KeyValuePair<'T,int>) =
                     Seq.init kvp.Value (fun _ -> kvp.Key)
                dict |> Seq.map innerSeq |> Seq.collect id
            seq.GetEnumerator()

        member x.IsReadOnly = false

        member x.Remove item =
            match dict.TryGetValue item with
            | true, 1 ->
                count <- count - 1
                dict.Remove item
            | true, itemCount ->
                count <- count - 1 
                dict.[item] <- itemCount - 1
                true
            | _ -> false

【讨论】:

  • 我不清楚为什么您使用 List&lt;T&gt; 而不仅仅是 int 作为字典的值 - 您需要维护的只是计数,您不需要添加该项目的多个副本。
猜你喜欢
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
  • 2011-05-01
  • 1970-01-01
  • 2020-09-28
相关资源
最近更新 更多