<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      如何寫一顆60行的紅黑樹(in Haskell)

      如何用Haskell寫一顆紅黑樹

      同步更新于Candy?的新家

      Candy?在上學期的數算課上學了紅黑樹,但是他一直沒寫過。

      最近他入門了一下Haskell,得知用Haskell可以很方便實現各種樹結構,于是就去學了一下如何用Haskell寫紅黑樹,發現只要不到60行(包括空行和類型簽名)!

      下面是一個簡單的小教程。

      定義類型

      和普通二叉樹一樣噠,只不過加上了一個顏色信息

      data Tree a = Nil | Node Color (Tree a) a (Tree a) deriving (Show, Eq)
      data Color = R | B deriving (Show, Eq)
      

      輔助函數

      • 將樹根染黑:
      makeBlack :: Tree a -> Tree a
      makeBlack Nil = Nil
      makeBlack (Node _ l x r) = Node B l x r
      
      • 將樹根染紅:
      makeRed :: Tree a -> Tree a
      makeRed Nil = Nil
      makeRed (Node _ l x r) = Node R l x r
      

      插入操作

      一般的紅黑樹插入不太方便用純函數式來寫,Okasaki在1999年提出了一種新的插入方法,將插入統一為:

      • 首先默認插入紅色節點,然后從下向上進行balance操作;
      • balance操作會處理當前子樹的children和grandchildren出現雙紅的情況,并且會將當前子樹的根變紅(balance操作并不會改變rank)

      插入操作的框架很簡單,需要注意的是最后要讓整棵樹的根變黑:

      insert :: (Ord a) => a -> Tree a -> Tree a
      insert x = makeBlack . ins 
        where ins Nil = Node R Nil x Nil
              ins t@(Node c l y r) | x < y     = balance $ Node c (ins l) y r
                                   | x > y     = balance $ Node c l y (ins r)
                                   | otherwise = t
      

      balance操作要處理四種情況:

      rbt1

      可以方便的用pattern matching來實現:

      balance :: Tree a -> Tree a
      balance (Node B (Node R (Node R a x b) y c) z d) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B (Node R a x (Node R b y c)) z d) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B a x (Node R (Node R b y c) z d)) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B a x (Node R b y (Node R c z d))) = Node R (Node B a x b) y (Node B c z d)
      balance t@(Node c x l r) = t
      

      刪除操作

      插入操作只要處理“雙紅”,刪除操作還要處理“黑色節點數相等”,比較麻煩。

      這里采用了Stefan Kahrs在2001年提出的方法,主要特點是:

      • 不將帶刪除節點與后繼交換
      • 維持一個新的invariant
        • 從黑根子樹中刪除節點,該子樹高度會-1
        • 從紅根子樹中刪除節點,該子樹高度不變

      我們有balanceL和balanceR兩個操作,分別處理“左子樹比右子樹短1”和“右子樹比左子樹短1”的情況,將整棵樹的高度變成較短那個的狀態。

      刪除操作的框架如下:

      delete :: Ord a => a -> Tree a -> Tree a
      delete x = makeBlack . del
        where
          del Nil = Nil
          del t@(Node _ l y r) | x < y     = delL t
                               | x > y     = delR t
                               | otherwise = app l r
          delL (Node _ l@(Node B _ _ _) y r) = balanceL $ Node B (del l) y r
          delL (Node _ l y r)                = Node R (del l) y r
          delR (Node _ l y r@(Node B _ _ _)) = balanceR $ Node B l y (del r)
          delR (Node _ l y r)                = Node R l y (del r)
      

      以待插入節點將插入左子樹為例:

      • 當前節點y的左子樹為黑根時,會在刪除后將y染黑并進行balanceL操作
      • 當前節點y的左子樹為紅根時,會在刪除后將y染紅

      容易發現,這樣操作是可以維持新的invariant的(枚舉當前節點顏色情況證明即可)

      由于delete中在balanceL/R之前會染黑,balanceL/R只要處理根為黑的情況即可,有三種情況:

      rbt2同樣用pattern matching來實現:

      balanceL :: Tree a -> Tree a 
      balanceL (Node B (Node R a x b) y r) = Node R (Node B a x b) y r
      balanceL (Node B l y (Node B a z b)) = balance $ Node B l y (Node R a z b)
      balanceL (Node B l y (Node R (Node B a u b) z c)) = Node R (Node B l y a) u (balance $ Node B b z (makeRed c))
      
      balanceR :: Tree a -> Tree a 
      balanceR (Node B l y (Node R a x b)) = Node R l y (Node B a x b)
      balanceR (Node B (Node B a z b) y r) = balance $ Node B (Node R a z b) y r
      balanceR (Node B (Node R c z (Node B a u b)) y r) = Node R (balance $ Node B (makeRed c) z a) u (Node B b y r)
      

      app會合并兩個子樹,有三種情況:

      rbt3

      同樣用pattern matching來實現:

      app :: Tree a -> Tree a -> Tree a
      app Nil t = t
      app t Nil = t 
      app (Node R a x b) (Node R c y d) = 
        case app b c of
          Node R b' z c' -> Node R (Node R a x b') z (Node R c' y d)
          s -> Node R a x (Node R s y d)
      app (Node B a x b) (Node B c y d) =
        case app b c of
          Node r b' z c' -> Node R (Node B a x b') z (Node B c' y d)
          s -> balanceL $ Node B a x (Node B s y d)
      app (Node R a x b) t = Node R a x (app b t)
      app t (Node R a x b) = Node R (app t a) x b
      

      完整代碼

      只要60行!

      data Tree a = Nil | Node Color (Tree a) a (Tree a) deriving (Show, Eq)
      data Color = R | B deriving (Show, Eq)
      
      makeBlack :: Tree a -> Tree a
      makeBlack Nil = Nil
      makeBlack (Node _ l x r) = Node B l x r
      
      makeRed :: Tree a -> Tree a
      makeRed Nil = Nil
      makeRed (Node _ l x r) = Node R l x r
      
      insert :: (Ord a) => a -> Tree a -> Tree a
      insert x = makeBlack . ins 
        where ins Nil = Node R Nil x Nil
              ins t@(Node c l y r) | x < y     = balance $ Node c (ins l) y r
                                   | x > y     = balance $ Node c l y (ins r)
                                   | otherwise = t
      
      balance :: Tree a -> Tree a
      balance (Node B (Node R (Node R a x b) y c) z d) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B (Node R a x (Node R b y c)) z d) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B a x (Node R (Node R b y c) z d)) = Node R (Node B a x b) y (Node B c z d)
      balance (Node B a x (Node R b y (Node R c z d))) = Node R (Node B a x b) y (Node B c z d)
      balance t@(Node c x l r) = t
      
      delete :: Ord a => a -> Tree a -> Tree a
      delete x = makeBlack . del
        where
          del Nil = Nil
          del t@(Node _ l y r) | x < y     = delL t
                               | x > y     = delR t
                               | otherwise = app l r
          delL (Node _ l@(Node B _ _ _) y r) = balanceL $ Node B (del l) y r
          delL (Node _ l y r)                = Node R (del l) y r
          delR (Node _ l y r@(Node B _ _ _)) = balanceR $ Node B l y (del r)
          delR (Node _ l y r)                = Node R l y (del r)
      
      balanceL :: Tree a -> Tree a 
      balanceL (Node B (Node R a x b) y r) = Node R (Node B a x b) y r
      balanceL (Node B l y (Node B a z b)) = balance $ Node B l y (Node R a z b)
      balanceL (Node B l y (Node R (Node B a u b) z c)) = Node R (Node B l y a) u (balance $ Node B b z (makeRed c))
      
      balanceR :: Tree a -> Tree a 
      balanceR (Node B l y (Node R a x b)) = Node R l y (Node B a x b)
      balanceR (Node B (Node B a z b) y r) = balance $ Node B (Node R a z b) y r
      balanceR (Node B (Node R c z (Node B a u b)) y r) = Node R (balance $ Node B (makeRed c) z a) u (Node B b y r)
      
      app :: Tree a -> Tree a -> Tree a
      app Nil t = t
      app t Nil = t 
      app (Node R a x b) (Node R c y d) = 
        case app b c of
          Node R b' z c' -> Node R (Node R a x b') z (Node R c' y d)
          s -> Node R a x (Node R s y d)
      app (Node B a x b) (Node B c y d) =
        case app b c of
          Node r b' z c' -> Node R (Node B a x b') z (Node B c' y d)
          s -> balanceL $ Node B a x (Node B s y d)
      app (Node R a x b) t = Node R a x (app b t)
      app t (Node R a x b) = Node R (app t a) x b
      

      其他API

      一些其他常規操作的API:

      tree2List :: Tree a -> [a]
      tree2List Nil = []
      tree2List (Node c l x r) = tree2List l ++ [x] ++ tree2List r
      
      list2Tree :: Ord a => [a] -> Tree a
      list2Tree = foldl (flip insert) Nil 
      
      search :: (Ord a) => a -> Tree a -> Bool
      search _ Nil = False
      search x (Node _ l y r) 
        | x == y    = True
        | x < y     = search x l
        | otherwise = search x r
      
      successor :: Ord a => a -> Tree a -> a
      successor x Nil = x
      successor x (Node _ l y r) 
        | x <  y = let t = successor x l in if x == t then y else t
        | x >= y = successor x r
      

      PS:因為沒有維護size信息所以沒法求第k小QwQ,不過加上size信息應該也不難寫。

      參考資料

      另外,Matt Might提出了一種更加簡潔、函數式的方法,詳情參閱他的博客

      posted @ 2020-02-11 17:55  Candy?  閱讀(1385)  評論(0)    收藏  舉報
      主站蜘蛛池模板: AV老司机AV天堂| 精品中文人妻在线不卡| 日韩成人无码影院| 无码国产精品一区二区av| 丰满少妇被猛烈进入av久久| 国产睡熟迷奷系列网站| 国产精品一区二区久久毛片| 午夜成人性爽爽免费视频| 亚洲午夜福利网在线观看| 亚洲国产成人资源在线| 午夜精品区| 国产精品一区二区在线欢| 亚洲国产精品成人精品无码区在线| 无码国产精品一区二区av| 99久久精品费精品国产一区二| 久久99久久99精品免观看| 激情自拍校园春色中文| 中文字幕在线日韩| 麻豆aⅴ精品无码一区二区| 国产免费无遮挡吸奶头视频| 欧美饥渴熟妇高潮喷水| 丰满少妇内射一区| 国产短视频一区二区三区| 99中文字幕精品国产| 成人中文在线| 中文字幕无码乱码人妻系列蜜桃| 精品亚洲国产成人性色av| 欧美丰满熟妇bbbbbb| 国产资源精品中文字幕| 天天爽天天摸天天碰| 国产午夜亚洲精品不卡下载| 化隆| 国产精品高清一区二区三区| 粗壮挺进邻居人妻无码| 溆浦县| 高清国产一区二区无遮挡| 国产成人精品中文字幕| 欧美性猛交xxxx乱大交丰满| 久久精品网站免费观看| 产综合无码一区| 成在线人视频免费视频|