红黑树包含太多黑色节点和太少的红色节点

时间:2013-12-25 15:39:40

标签: algorithm f# functional-programming red-black-tree

这是我在这里提出的问题

Difficulty in writing Red Black Tree in F#

根据以前的输入,我创建了这个程序。

open System;

type Color = | R | B 

type tree = 
    | Node of int * Color * tree * tree
    | Leaf

let blackHeight tree = 
    let rec innerBlackHeight accm = function
        | Leaf -> accm + 1
        | Node(_, B, l, r) -> List.max [(innerBlackHeight (accm + 1) l); (innerBlackHeight (accm + 1) r)]
        | Node(_, R, l, r) -> List.max [(innerBlackHeight accm l); (innerBlackHeight accm r)]        
    innerBlackHeight 0 tree    

let isTreeBalanced tree = 
    let rec isBlackHeightSame = function
        | Node(n, c, l, r) -> 
            if (blackHeight l) = (blackHeight r) then 
                true && (isBlackHeightSame l) && (isBlackHeightSame r)
            else 
                false
        | Leaf -> true
    let isRootBlack = function
        | Node(n, c, _, _) -> 
            if c = B then 
                true 
            else 
                false
        | _ -> false
    let rec twoConsequtiveReds = function
        | Leaf -> true
        | Node(_, R, Node(_, R, _, _), _) -> false
        | Node(_, R, _, Node(_, R, _, _)) -> false
        | Node(_, _, l, r) -> (twoConsequtiveReds l) && (twoConsequtiveReds r)

    ((isBlackHeightSame tree) && (isRootBlack tree) && (twoConsequtiveReds tree))

let balance  = function 
    | Node (gpn, B, Node(pn, R, Node(cn, R, a, b), c), d) -> Node(pn, R, Node(cn, B, a, b), Node(gpn, B, c, d))
    | Node (gpn, B, a, Node(pn, R, b, Node(cn, R, c, d))) -> Node(pn, R, Node(gpn, B, a, b), Node(cn, B, c, d))
    | Node (gpn, B, Node(pn, R, a, Node(cn, R, b, c)), d) -> Node(cn, R, Node(pn, B, a, b), Node(gpn, B, c, d))
    | Node (gpn, B, a, Node(pn, R, Node(cn, R, b, c), d)) -> Node(cn, R, Node(gpn, B, a, b), Node(pn, B, c, d))    
    | Node (n, c, l, r) -> Node(n, c, l, r)
    | _ -> failwith "unknown pattern"

let rec insert x tree = 
    let rec insertInner = function
        | Node(n, c, l, r) when x < n -> balance (Node(n, c, insertInner l, r))
        | Node(n, c, l, r) when x > n -> balance (Node(n, c, l, insertInner r))
        | Node(n, c, l, r) as node when x = n -> node
        | Leaf -> Node(x, R, Leaf, Leaf)
        | _ -> failwith "unknown pattern"
    match (insertInner tree) with
    | Node(n, _, l, r) -> Node(n, B, l, r)
    | t -> t

let rec findLowest = function
    | Node(n, _, Leaf, _) -> n
    | Node(_, _, l, _) -> findLowest l
    | _ -> failwith "Unknown pattern"

let rec countNodes = function
    | Node(_, c, l, r) -> 
        let (x1, y1, z1) = countNodes l
        let (x2, y2, z2) = countNodes r
        if c = B then
            (1 + x1 + x2, y1 + y2, z1 + z2)
        else
            (x1 + x2, 1 + y1 + y2, z1 + z2)
    | Leaf -> (0, 0, 1)

let rec delete x tree = 
    let rec innerDelete = function
        | Node(n, c, l, r) when x < n -> balance (Node(n, c, innerDelete l, r))
        | Node(n, c, l, r) when x > n -> balance (Node(n, c, l, innerDelete r))
        | Node(n, c, Leaf, Leaf) when x = n -> Leaf
        | Node(n, c, l, Leaf) when x = n -> balance l
        | Node(n, c, Leaf, r) when x = n -> balance r
        | Node(n, c, l, r) when x = n ->  balance (Node((findLowest r), c, l, r))
        | _ -> failwith "unexpected pattern"
    match (innerDelete tree) with
    | Node(n, _, l, r) -> Node(n, B, l, r)
    | t -> t

let generateNums n = 
    seq {for i in 0 .. n - 1 -> i}

[<EntryPoint>]
let main args = 
    let mutable tree = Leaf
    for i in generateNums 100000 do 
        tree <-insert i tree    
    printfn "%A" tree
    printfn "%i" (blackHeight tree)
    printfn "%b" (isTreeBalanced tree)
    let (bc, rc, lc) = countNodes tree
    printfn "black nodes %i red nodes %i leaf nodes %i" bc rc lc
    0

我面临的问题是

  1. 对于0到99999的树,它会生成一棵树,其中包含99994个黑色节点,6个红色节点和100001个叶节点。
  2. 这是正常的吗?那棵树的红色节点很少?

    我编写了一个函数,根据3个规则验证树是否有效(root总是黑色,所有分支的黑色高度相同,红色节点没有红色子节点),我的方法说生成的树确实有效。

    1. 黑色节点太多的问题是某些分支充满黑色节点,如果我尝试删除一个节点,那么旋转无助于平衡树,并且该分支的黑色高度总是较少比树的其他分支。
    2. 所以我的问题是......红黑树的红色节点太少是正常的吗?那么在删除的情况下如何保持树的平衡?

1 个答案:

答案 0 :(得分:1)

没有“太多黑节点”这样的事情。没有红色节点就意味着树是最平衡的。将新的红色节点引入全黑树会增加其不平衡(首先)。

删除全黑树中的黑色节点时,请遵循删除算法,以确保保留属性。