从Haskell中的二叉树中获取第N个元素

时间:2016-02-25 21:14:12

标签: haskell tree

所以,从逻辑上讲,我看到这是如何工作的,但是,我找不到工作的Haskell语法来表达逻辑。这是我对嵌套警卫的尝试,显然这不是一个受支持的功能:

data Tree a where
  Nil :: Tree a
  Node :: Ord a => Tree a -> a -> Tree a -> Tree a

-- Get the nth top element of a sorted binary tree:
getNthElement :: Int -> Tree a -> Either Int a
getNthElement _ Nil = Left 0
getNthElement n (Node l v r)
  | (Right x) <- rightRecurse = rightRecurse
  | (Left nr) <- rightRecurse, nr == n = Right v
  | (Left nr) <- rightRecurse
    | (Right x) <- leftRecurse = leftRecurse
    | (Left nl) <- leftRecurse = Left $ nl + nr + 1
    where leftRecurse = getNthElement (n-nr-1) l in
  where rightRecurse = getNthElement n r

2 个答案:

答案 0 :(得分:1)

感谢bheklilr,案例表达解决了这个问题。工作代码是:

## app.R ##
library(shiny)
library(shinydashboard)
library(shinyjs)

ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
        actionButton(inputId = "btn_data", label = "Download"),
        conditionalPanel(condition = "output.setupComplete",
            box( title = "box1" ),
            box( title = "box2" ),
            box( title = "boc3" )
        ),
        conditionalPanel(condition = "!output.setupComplete",
                         box( title = "loading"))
    )
)

server <- function(input, output) { 

    rv <- reactiveValues()
    rv$setupComplete <- FALSE

    ## simulate data load
    observe({

        if(input$btn_data){

            df <- data.frame(id = seq(1,200),
                             val = rnorm(200, 0, 1))

            ## Simulate the data load
            Sys.sleep(5)
            ## set my condition to TRUE
            rv$setupComplete <- TRUE
        }

        ## the conditional panel reads this output
        output$setupComplete <- reactive({
            return(rv$setupComplete)
        })
        outputOptions(output, 'setupComplete', suspendWhenHidden=FALSE)

    })
}

shinyApp(ui, server)

答案 1 :(得分:0)

这就是我写它的方式(我已将所有内容放在self-contained gist以防你想玩它)。 State Int monad处理计数器的线程,Maybe替代选择正确的值。我认为这种算法更具可读性。

我们从一堆导入和您对Tree的定义开始:

{-# LANGUAGE GADTs #-}

module NthElement where

import Data.Functor
import Control.Applicative
import Control.Monad
import Control.Monad.Trans.State

data Tree a where
  Nil :: Tree a
  Node :: Ord a => Tree a -> a -> Tree a -> Tree a

然后我们得出主要定义:getNthElement运行有状态计算,如果我们返回Nothing,它会放置被访问节点的数量(原始数量减去最终Int状态),否则它会返回它找到的值。

getNthElement :: Int -> Tree a -> Either Int a
getNthElement k t = maybe (Left $ k - s) Right mv where

  (mv , s) = go t `runState` k

  go :: Tree a -> State Int (Maybe a)

有状态计算本身是对算法的高级描述的直接翻译:

  • 如果我们找到Nil,则没有值返回(因此我们失败了)

    go Nil          = return Nothing
    
  • 如果我们找到Node,那么我们要查找的第n个值是在正确的子树中,如果在探索到正确的子树后计数器是0,则在中间,或者在左子树的某处:

    go (Node l v r) = do
      rv <- go r
      k  <- get
      () <- put $ k - 1
      lv <- go l
      return $ rv <|> (v <$ guard (k == 0)) <|> lv
    

有了这个定义,我们就不会立即开始做不需要的工作(我们写的是lv <- go l,当时可能已经找到了值!)。然而,懒惰在我们这边,并说服自己确实没问题,我们可以定义一个左无限树并观察getNthElement总是返回一个值:

leftInfTree :: Tree Int
leftInfTree = foldr (\ k ih -> Node ih k Nil) Nil [1..]

在ghci中测试:

*NthElement> getNthElement 10 leftInfTree 
Right 11