ค้นหาว่าต้นไม้เป็นต้นไม้ค้นหาแบบทวิภาคใน Haskell หรือไม่


10
  type BSTree a = BinaryTree a

  data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
                      deriving Show

  flattenTree :: BinaryTree a -> [a]
  flattenTree  tree = case tree of
      Null -> []
      Node left val right -> (flattenTree left) ++ [val] ++ (flattenTree right)

  isBSTree :: (Ord a) => BinaryTree a -> Bool
  isBSTree btree = case btree of
      Null -> False
      tree -> (flattenTree tree) == sort (flattenTree tree)

สิ่งที่ฉันต้องการจะทำคือการเขียนฟังก์ชั่นเพื่อตรวจสอบว่าต้นไม้ที่กำหนดเป็นต้นไม้ค้นหาแบบไบนารี่หรือไม่วิธีการของฉันคือการจัดกลุ่มค่าทั้งหมดในรายการและนำเข้าData.Listแล้วเรียงลำดับรายการเพื่อค้นหาว่ามีค่าเท่ากันหรือไม่ ซับซ้อนเล็กน้อย เราสามารถทำสิ่งนี้ได้โดยไม่ต้องนำเข้าโมดูลอื่นหรือไม่?


ฉันจะไม่นิยามflattenTreeก่อน คุณสามารถกลับมาFalseก่อนได้หากโหนดละเมิดคุณสมบัติการค้นหาโดยไม่ต้องเข้าไปสำรวจทรีย่อยทั้งหมดที่ถูกรูทที่โหนดนั้น
chepner

@chepner ปัญหาอยู่กับsortไม่ได้flattenTreeซึ่งขี้เกียจพอ
Will Ness

ใช่นั่นเกิดขึ้นกับฉันหลังจากดูคำตอบอื่น ๆ
chepner

คำตอบ:


13

นี่คือวิธีการทำโดยไม่ทำให้ต้นไม้แบน

จากคำจำกัดความที่นี่

data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
     deriving Show

จะเห็นได้ว่าการเคลื่อนที่ของต้นไม้จากซ้ายไปขวาไม่สนใจNodeและวงเล็บให้ลำดับสลับกันของNulls และa s นั่นคือระหว่างค่าทุกสองค่าจะมีNullค่า

แผนของฉันคือการตรวจสอบว่าทรีย่อยแต่ละตัวตรงตามข้อกำหนดที่เหมาะสม: เราสามารถปรับแต่งข้อกำหนดในแต่ละทรีNodeโดยจดจำค่าที่เราอยู่ระหว่างแล้วทดสอบNullพวกเขาในแต่ละ เนื่องจากมีค่าNullระหว่างคู่ของค่าตามลำดับเราจะทดสอบว่าคู่ตามลำดับ (จากซ้ายไปขวา) ทั้งหมดจะไม่ลดลง

ความต้องการคืออะไร? มันเป็นขอบเขตล่างและบนที่หลวมบนค่าในต้นไม้ ในการแสดงความต้องการรวมถึงที่อยู่ทางซ้ายสุดและขวาสุดเราอาจขยายการสั่งซื้อใด ๆ กับBotทอมและTopองค์ประกอบดังนี้:

data TopBot a = Bot | Val a | Top deriving (Show, Eq, Ord)

ตอนนี้ให้เราตรวจสอบว่าต้นไม้ที่กำหนดตอบสนองความต้องการของการเป็นทั้งในลำดับและระหว่างขอบเขตที่กำหนด

ordBetween :: Ord a => TopBot a -> TopBot a -> BinaryTree a -> Bool
  -- tighten the demanded bounds, left and right of any Node
ordBetween lo hi (Node l x r) = ordBetween lo (Val x) l && ordBetween (Val x) hi r
  -- check that the demanded bounds are in order when we reach Null
ordBetween lo hi Null         = lo <= hi

ต้นไม้ค้นหาแบบทวิภาคเป็นต้นไม้ที่อยู่ในการสั่งซื้อและระหว่างและBotTop

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordBetween Bot Top

การคำนวณค่า extremal จริงในแต่ละทรีย่อย, bubbling พวกมันออกไปข้างนอก, ให้ข้อมูลมากกว่าที่คุณต้องการ, และเป็นปริศนาในกรณีขอบซึ่งทรีย่อยซ้ายหรือขวาว่างเปล่า การบำรุงรักษาและตรวจสอบข้อกำหนดผลักดันพวกเขาเข้าด้านในค่อนข้างสม่ำเสมอ


6

นี่คือคำใบ้: สร้างฟังก์ชั่นเสริม

isBSTree' :: (Ord a) => BinaryTree a -> BSTResult a

โดยBSTResult aนิยามว่าเป็น

data BSTResult a
   = NotBST             -- not a BST
   | EmptyBST           -- empty tree (hence a BST)
   | NonEmptyBST a a    -- nonempty BST with provided minimum and maximum

คุณควรจะสามารถดำเนินการซ้ำ ๆ โดยใช้ประโยชน์จากผลลัพธ์ใน subtrees เพื่อขับเคลื่อนการคำนวณโดยเฉพาะอย่างยิ่งขั้นต่ำและสูงสุด

ตัวอย่างเช่นถ้าคุณมีtree = Node left 20 rightด้วยisBSTree' left = NonEmptyBST 1 14และisBSTree' right = NonEmptyBST 21 45แล้วควรจะเป็นisBSTree' treeNonEmptyBST 1 45

ในกรณีเดียวกันยกเว้นสำหรับเราแทนควรจะมีtree = Node left 24 rightisBSTree' tree = NotBST

การแปลงผลลัพธ์Boolเป็นเรื่องเล็กน้อย


1
หรือกำหนด Monoid ที่ชัดเจนสำหรับBSTResult aและพับเข้าไป :) (หรือแม้ว่าจะไม่ใช่ Monoid ที่ชอบด้วยกฎหมาย .... )
Will Ness

(แต่ฉันคิดว่าถูกต้องตามกฎหมายแล้ว)
Will Ness

3

ใช่คุณไม่จำเป็นต้องเรียงลำดับรายการ คุณสามารถตรวจสอบว่าทุกองค์ประกอบน้อยกว่าหรือเท่ากับองค์ประกอบถัดไป นี้จะมีประสิทธิภาพมากขึ้นเนื่องจากเราสามารถทำเช่นนี้ในO (n)ในขณะที่การประเมินรายการที่เรียงลำดับสมบูรณ์ใช้เวลาO (n log n) n)

เราสามารถตรวจสอบสิ่งนี้ด้วย:

ordered :: Ord a => [a] -> Bool
ordered [] = True
ordered xa@(_:xs) = and (zipWith (<=) xa xs)

ดังนั้นเราสามารถตรวจสอบว่าต้นไม้ไบนารีเป็นต้นไม้ค้นหาแบบไบนารีด้วย:

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordered . flattenTree

ฉันคิดว่าใครสามารถอ้างว่าNullตัวเองเป็นต้นไม้ค้นหาแบบไบนารีเนื่องจากเป็นต้นไม้ที่ว่างเปล่า นี่จึงหมายความว่าสำหรับทุก ๆ โหนด (ไม่มีโหนด) องค์ประกอบในทรีย่อยด้านซ้ายจะน้อยกว่าหรือเท่ากับค่าในโหนดและองค์ประกอบในทรีย่อยด้านขวาล้วนมีค่ามากกว่าหรือเท่ากับค่าในโหนด .


1

เราสามารถดำเนินการจากซ้ายไปขวาบนต้นไม้ดังนี้:

isBSTtreeG :: Ord a => BinaryTree a -> Bool
isBSTtreeG t = gopher Nothing [Right t]
    where
    gopher  _   []                        =  True
    gopher  x   (Right Null:ts)           =  gopher x ts
    gopher  x   (Right (Node lt v rt):ts) =  gopher x (Right lt:Left v:Right rt:ts)
    gopher Nothing   (Left v:ts)          =  gopher (Just v) ts
    gopher (Just y)  (Left v:ts)          =  y <= v && gopher (Just v) ts

แรงบันดาลใจจากJohn McCarthygopherจอห์นแมคคาร์ของ

รายการ push-down ที่ชัดเจนสามารถถูกกำจัดได้ด้วยการส่งต่อเนื่อง

isBSTtreeC :: Ord a => BinaryTree a -> Bool
isBSTtreeC t = gopher Nothing t (const True)
    where
    gopher  x   Null           g  =  g x 
    gopher  x   (Node lt v rt) g  =  gopher x lt (\case
                                       Nothing -> gopher (Just v) rt g
                                       Just y  -> y <= v && gopher (Just v) rt g)

การบำรุงรักษาเพียงองค์ประกอบเดียวที่ใหญ่ที่สุดจนถึงก็เพียงพอแล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.