optimization - 左倾红黑树的 F# 代码优化

标签 optimization f# tree

我一直致力于将 LLRBT 的 C# 实现移植到 F#,现在它可以正确运行。我的问题是我将如何优化它?

我的一些想法

  • 使用节点的可区分联合来删除 null 的使用
  • 删除 getter 和 setter
    • 不能同时拥有 null 属性和结构

完整源代码可以找到here 。 C# 代码取自 Delay's Blog .

当前表现
F# 已用时间 = 00:00:01.1379927 高度:26,计数:487837
C# 已用时间 = 00:00:00.7975849 高度:26,计数:487837

module Erik

let Black = true
let Red = false

[<AllowNullLiteralAttribute>]
type Node(_key, _value, _left:Node, _right:Node, _color:bool) =
    let mutable key = _key
    let mutable value = _value
    let mutable left = _left
    let mutable right = _right
    let mutable color = _color
    let mutable siblings = 0

    member this.Key with get() = key and set(x) = key <- x
    member this.Value with get() = value and set(x) = value <- x
    member this.Left with get() = left and set(x) = left <- x
    member this.Right with get() = right and set(x) = right <- x
    member this.Color with get() = color and set(x) = color <- x
    member this.Siblings with get() = siblings and set(x) = siblings <- x

    static member inline IsRed(node : Node) =
        if node = null then
            // "Virtual" leaf nodes are always black
            false
        else
            node.Color = Red

    static member inline Flip(node : Node) =
        node.Color <- not node.Color
        node.Right.Color <- not node.Right.Color
        node.Left.Color <- not node.Left.Color

    static member inline RotateLeft(node : Node) =
        let x = node.Right
        node.Right <- x.Left
        x.Left <- node
        x.Color <- node.Color
        node.Color <- Red
        x

    static member inline RotateRight(node : Node) =
        let x = node.Left
        node.Left <- x.Right
        x.Right <- node
        x.Color <- node.Color
        node.Color <- Red
        x

    static member inline MoveRedLeft(_node : Node) =
        let mutable node = _node
        Node.Flip(node)

        if Node.IsRed(node.Right.Left) then
            node.Right <- Node.RotateRight(node.Right)
            node <- Node.RotateLeft(node)
            Node.Flip(node)

            if Node.IsRed(node.Right.Right) then
                node.Right <- Node.RotateLeft(node.Right)
        node

    static member inline MoveRedRight(_node : Node) =
        let mutable node = _node
        Node.Flip(node)

        if Node.IsRed(node.Left.Left) then
            node <- Node.RotateRight(node)
            Node.Flip(node)
        node

    static member DeleteMinimum(_node : Node) =
        let mutable node = _node

        if node.Left = null then
            null
        else
            if not(Node.IsRed(node.Left)) && not(Node.IsRed(node.Left.Left)) then
                node <- Node.MoveRedLeft(node)

            node.Left <- Node.DeleteMinimum(node)
            Node.FixUp(node)

    static member FixUp(_node : Node) =
        let mutable node = _node

        if Node.IsRed(node.Right) then
            node <- Node.RotateLeft(node)

        if Node.IsRed(node.Left) && Node.IsRed(node.Left.Left) then
            node <- Node.RotateRight(node)

        if Node.IsRed(node.Left) && Node.IsRed(node.Right) then
            Node.Flip(node)

        if node.Left <> null && Node.IsRed(node.Left.Right) && not(Node.IsRed(node.Left.Left)) then
            node.Left <- Node.RotateLeft(node.Left)
            if Node.IsRed(node.Left) then
                node <- Node.RotateRight(node)
        node

type LeftLeaningRedBlackTree(?isMultiDictionary) =
    let mutable root = null
    let mutable count = 0        

    member this.IsMultiDictionary =
       Option.isSome isMultiDictionary

    member this.KeyAndValueComparison(leftKey, leftValue, rightKey, rightValue) =
        let comparison = leftKey - rightKey
        if comparison = 0 && this.IsMultiDictionary then
            leftValue - rightValue
        else
            comparison

    member this.Add(key, value) =
        root <- this.add(root, key, value)

    member private this.add(_node : Node, key, value) =
        let mutable node = _node

        if node = null then
            count <- count + 1
            new Node(key, value, null, null, Red)
        else
            if Node.IsRed(node.Left) && Node.IsRed(node.Right) then
                Node.Flip(node)

            let comparison = this.KeyAndValueComparison(key, value, node.Key, node.Value)

            if comparison < 0 then
                node.Left <- this.add(node.Left, key, value)
            elif comparison > 0 then
                node.Right <- this.add(node.Right, key, value)
            else
                if this.IsMultiDictionary then
                    node.Siblings <- node.Siblings + 1
                    count <- count + 1
                else
                   node.Value <- value

            if Node.IsRed(node.Right) then
                node <- Node.RotateLeft(node)

            if Node.IsRed(node.Left) && Node.IsRed(node.Left.Left) then
                node <- Node.RotateRight(node)

            node

最佳答案

我很惊讶有如此大的性能差异,因为这看起来像是一个简单的音译。我认为两者都是在“发布”模式下编译的?您是否单独运行这两个版本(冷启动),或者如果两个版本都在同一程序中,则颠倒两者的顺序(例如热缓存)?做过任何分析(有一个好的分析器)吗?比较内存消耗(甚至 fsi.exe 可以帮助解决)?

(我没有看到这种可变数据结构实现有任何明显的改进。)

关于optimization - 左倾红黑树的 F# 代码优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1719756/

相关文章:

algorithm - 遍历树的最优化算法(方法)是什么?

asynchronous - F# 异步挂起

arrays - 检查列表和数组是否相等 F#

tree - 是否可以使用 Java 8 Streams 构建 Tree 数据模型

c# - 映射 URL 或本地路径的数据结构

javascript - 推迟首屏 CSS 渲染突然无法通过 Google Pagespeed Insight 测试

sql - 我怎样才能摆脱这个查询中的 'ORA-01489: result of string concatenation is too long' ?

javascript - d3 节点内的 Angular 指令

python - 优化在 Python 中查找和替换大文件

c# - 如何在板(20x20)上进行图案/形状匹配/识别?