前序中序后序遍历_Haskell-前序中序遍历重建二叉树/Maze迷宫

a2c747fedc64c785955f260ed46cd23f.png

[TOC]

问题解析(对问题的分析、解题思路与解题方法):

第2题、迷宫问题 以一个MxN的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。

设 计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通 路的结论。

(1) 根据二维数组,输出迷宫的图形。

(2) 探索迷宫的四个方向:RIGHT为向右,DOWN向下,LEFT向左,UP向 上,只输出从入口到出口的一条行走路径,而非全部路径。

[测试数据] 左上角(1,1)为入口,右下角(8,9)为出口。

0 0 1 0 0 0 1 0

0 0 1 0 0 0 1 0

0 0 1 0 1 1 0 1

0 1 1 1 0 0 1 0

0 0 0 1 0 0 0 0

0 1 0 0 0 1 0 1

0 1 1 1 1 0 0 1

1 1 0 0 0 1 0 1

1 1 0 0 0 0 0 0

[实现提示] 回溯法

第3题、构建二叉树 给定一棵二叉树的先根序列和中根序列(以字符串形式给出,串中每个字符 表示一个结点),编写程序构建该二叉树,输出二叉树的树形。

[测试数据] 输入:先根序列ABDFCEGH,中根序列BFDAGEHC

输出:

二叉树树形

数据结构选择(包括改进或给出)、算法设计:

  1. 第二题

分别用了C++和Haskell函数式编程语言(参考文章1345),源码见,Haskell很短。

主要讲讲Haskell实现吧。

下面注释写进去代码里面吧。

module Maze where
import Data.Array
solveMaze maze startPoint endPoint = map reverse $ solve startPoint [[]] where
    solve pointVisiting pathsToEndpoint | pointVisiting == endPoint   = map (pointVisiting:) pathsToEndpoint
                                                                   | otherwise = concat [solve pointAdjacent (map (pointVisiting:) pathsToEndpoint) | 
                                        pointAdjacent <- adjacent pointVisiting, not $ visited pointAdjacent pathsToEndpoint]
    adjacent (x, y) = [(x', y') | (x', y') <- [(x-1, y), (x+1, y), (x, y-1), (x, y+1)], 
                                  inRange (bounds maze) (x', y'), maze ! (x', y') == 0]
    visited pointVisiting pathsToEndpoint = any (elem pointVisiting) pathsToEndpoint
{-
数组path头插法效率高,所以基本都要reserse。
sloveMaze:: Array (a1, b) a2 -> (a1, b) -> (a1, b) -> [[(a1, b)]]
算法思路其实就是列表生成器遍历右左下上临近点,然后把满足合取条件“没访问过的临近点^不超出迷宫范围的点^迷宫位置==0没有障碍的点”不断地加入pathsToEndpoint
visited函数判断点是否在已访问过的路径上,即判断是否在pathsToEndpoint里。
-}
mz1=      [ [0,0,1,0,0,0,1,0],
            [0,0,1,0,0,0,1,0],
            [0,0,1,0,1,1,0,1],
            [0,1,1,1,0,0,1,0],
            [0,0,0,1,0,0,0,0],
            [0,1,0,0,0,1,0,1],
            [0,1,1,1,1,0,0,1],
            [1,1,0,0,0,1,0,1],
            [1,1,0,0,0,0,0,0]]
mz0=       [[0,0],
            [0,0]]
maze1  = listArray ((1,1), (9, 8)) . concat
test1 = [solveMaze (maze1 mz1) (1,1) (9,8)]
test0 = [solveMaze ( (listArray ((1,1), (2, 2)) . concat) mz0) (1,1) (2,2)]
main :: IO()
main  =  print test1
--main = print test0

{-
下面全部是注释
maze mz
array ((1,1),(9,8)) [((1,1),0),((1,2),0),((1,3),1),((1,4),0),((1,5),0),((1,6),0),((1,7),1),((1,8),0),((2,1),0),((2,2),0),((2,3),1),((2,4),0),((2,5),0),((2,6),0),((2,7),1),((2,8),0),((3,1),0),((3,2),0),((3,3),1),((3,4),0),((3,5),1),((3,6),1),((3,7),0),((3,8),1),((4,1),0),((4,2),1),((4,3),1),((4,4),1),((4,5),0),((4,6),0),((4,7),1),((4,8),0),((5,1),0),((5,2),0),((5,3),0),((5,4),1),((5,5),0),((5,6),0),((5,7),0),((5,8),0),((6,1),0),((6,2),1),((6,3),0),((6,4),0),((6,5),0),((6,6),1),((6,7),0),((6,8),1),((7,1),0),((7,2),1),((7,3),1),((7,4),1),((7,5),1),((7,6),0),((7,7),0),((7,8),1),((8,1),1),((8,2),1),((8,3),0),((8,4),0),((8,5),0),((8,6),1),((8,7),0),((8,8),1),((9,1),1),((9,2),1),((9,3),0),((9,4),0),((9,5),0),((9,6),0),((9,7),0),((9,8),0)]



*Maze Data.Array> test1
[[
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)]
]]

*Maze Data.Array> test2=[solveMaze(tmp mz1)(1,1)(3,3)]
*Maze Data.Array> test2
[[]]

命令行执行
>ghci Maze.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Maze             ( Maze.hs, interpreted )
Ok, one module loaded.
*Maze> test1
[[[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)]]]
-}
  1. 第三题

用了C++和Haskell函数式编程语言。

下面注释写进去代码绑定的名字里面了。

第一个函数reconstruct返回a左子树和a结点右边序列递归下去,reconstruct'函数则是递归处理a左子树和其他的列表字符串。

先序:中左右,中序:左中右。

head ifInorderArrayRightOfa == a时,说明递归出口。

module Reconstruct  where
data Tree a
    = Leaf
    | Node a (Tree a)(Tree a) deriving Show 

reconstruct :: Eq a=> ([a],[a]) -> Tree a
reconstruct ([],[])= Leaf
reconstruct (a:preorderArrayNoa,inorderArray)= let (treeLefta,preorderArrayRightOfa,inorderArrayRightOfa) = reconstruct' a (preorderArrayNoa,inorderArray)
           in Node a treeLefta (reconstruct(preorderArrayRightOfa,inorderArrayRightOfa))

reconstruct' :: Eq a=>a -> ([a],[a])->(Tree a,[a],[a])
reconstruct' a (preorderArrayGiven@(~(b:preorderArrayGivenNob)),ifInorderArrayRightOfa)
    | head ifInorderArrayRightOfa == a = (Leaf,preorderArrayGiven,tail ifInorderArrayRightOfa)
    | otherwise   = let (treeLeftOfb,pre_tmp,in_tmp)=reconstruct' b (preorderArrayGivenNob,ifInorderArrayRightOfa)
                        (treeRightOfb,preorderArray_Right,inorderArray_Right)=reconstruct' a (pre_tmp,in_tmp)
                   in (Node b treeLeftOfb treeRightOfb, preorderArray_Right,inorderArray_Right)

answer = reconstruct (['A','B','D','F','C','E','G','H'],['B','F','D','A','G','E','H','C'])

preorder(Leaf) = []
preorder(Node n t0 t1) = [n] ++ (preorder t0) ++ (preorder t1)
test_pre=preorder (answer)

inorder(Leaf) = []
inorder(Node n t0 t1) = (inorder t0) ++ [n] ++ (inorder t1)
test_in=inorder(answer)

postorder(Leaf) = []
postorder(Node n t0 t1) = (postorder t0) ++ (postorder t1) ++ [n]
test_post=postorder(answer)


{-
*Main> answer
Node 'A' (Node 'B' Leaf (Node 'D' (Node 'F' Leaf Leaf) Leaf)) (Node 'C' (Node 'E' (Node 'G' Leaf Leaf) (Node 'H' Leaf Leaf)) Leaf)
*Main> test_pre
"ABDFCEGH"
*Main> test_in
"BFDAGEHC"
*Main> test_post
"FDBGHECA"

-}


prettyprint :: Show a => Tree a -> [Char]
prettyprint (Leaf)
    = "Empty root."
-- unlines concats a list with newlines
prettyprint (Node node left right) = unlines (prettyprint_helper (Node node left right))
prettyprint_helper (Node node left right)
    = (show node) : (prettyprint_subtree left right)
        where
            prettyprint_subtree left right =
                ((pad "right- " "|  ") (prettyprint_helper right))
                    ++ ((pad "left- " "   ") (prettyprint_helper left))
            pad first rest = zipWith (++) (first : repeat rest)
prettyprint_helper (Leaf)
    = []
main :: IO ()
main = putStrLn $ prettyprint (answer)
{-

*Main> putStrLn $ prettyprint (answer)
'A'
+- 'C'
|  `- 'E'
|     +- 'H'
|     `- 'G'
`- 'B'
   +- 'D'
   |  `- 'F'
-}

{-


>ghci Reconstruct.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Reconstruct.hs, interpreted )
Ok, one module loaded.
*Main>  putStrLn $ prettyprint (answer)
'A'
right- 'C'
|  left- 'E'
|     right- 'H'
|     left- 'G'
left- 'B'
   right- 'D'
   |  left- 'F'



-}

手动eval演算草稿。

cf54ea0eb1abd0d43b711a7c289e0d38.png

注意,下图的例子举了图中的一颗小树,因为递归深度太多的话写不完。

f293f6933bc873719bbfb6b2d848e5ff.png

第二第三题主要是Haskell解析起来有点长,有空写篇博客解析也可以,不过Haskell的好处是代码短,贴近数学语言,无缝对接翻译成数学语言(参考文章2 6 7)。

Haskell代码本身就可以当成算法英文说明书,只是刚好程序代码文字凑巧能运行出代码罢了。

测试方法、测试数据与测试结果:

见代码注释部分,见说明,每个都有测试用例,如果不看代码,没有编译环境可以直接先看*.exe

程序的使用说明和效果图

第一题 C++程序注释写明,不多说了。

第二题

deploy>ghc -main-is Maze Maze.hs -o Maze-haskell
[1 of 1] Compiling Maze             ( Maze.hs, Maze.o )
Linking Maze-haskell.exe ...

deploy> Maze-haskell.exe
[[[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)]]]
>ghci Maze.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Maze             ( Maze.hs, interpreted )
Ok, one module loaded.
*Maze> test1
[[[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)]]]

第三题

>ghci Reconstruct.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Reconstruct.hs, interpreted )
Ok, one module loaded.
*Main>  putStrLn $ prettyprint (answer)
'A'
right- 'C'
|  left- 'E'
|     right- 'H'
|     left- 'G'
left- 'B'
   right- 'D'
   |  left- 'F'

编译成exe的话是这样子的

deploy>ghc -main-is Reconstruct Reconstruct.hs -o Reconstruct-haskell
[1 of 1] Compiling Reconstruct      ( Reconstruct.hs, Reconstruct.o )
Linking Reconstruct-haskell.exe ...

deploy>Reconstruct-haskell.exe
'A'
right- 'C'
|  left- 'E'
|     right- 'H'
|     left- 'G'
left- 'B'
   right- 'D'
   |  left- 'F'

系列效果图

C++

3af071a57d3344ac8ed17cc164c3872e.png

e472f727bc0289174bdee66128a82083.png

Haskell

c378d1b35774e2ad5dbb3bc376765faf.png

1e03c700c09c2212d1f226836a84d7ba.png

C++程序使用codeblock开发,

直接用codeblock能编译,

mingGW也能编译,

G++ *.cpp也能编译。

Haskell使用windows下的Haskell Plaform

WinGHC能够直接编译运行

也能GHCi调试运行

或者ghc *.hs编译可以运行。

源代码文件作者用Emacs编辑时,发现用Emacs看中文注释会乱码,还很卡,不过写小文件方便。

Haskell简单的英文注释格式是:

“—一行注释”

“{-一段注释-}”

(对程序进行分析、评价运行效果,总结遇到的问题及解决办法)

第二题,用了C++和Haskell函数式编程语言,源码见上,Haskell很短,但是很难想出来代码的意思,而且让我学会很多GHC-Win的Debug技巧。

下图WinGHC里排版不好,整理下换行可见一共有多少种迷宫算法求解方案。

[[
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)]
]]
module Maze where

import Data.Array

solveMaze maze startPoint endPoint = map reverse $ solve startPoint [[]] where
    solve pointVisiting pathsToEndpoint | pointVisiting == endPoint   = map (pointVisiting:) pathsToEndpoint
                  | otherwise = concat [solve pointAdjacent (map (pointVisiting:) pathsToEndpoint) | 
                                        pointAdjacent <- adjacent pointVisiting, not $ visited pointAdjacent pathsToEndpoint]
    adjacent (x, y) = [(x', y') | (x', y') <- [(x-1, y), (x+1, y), (x, y-1), (x, y+1)], 
                                  inRange (bounds maze) (x', y'), maze ! (x', y') == 0]
    visited pointVisiting pathsToEndpoint = any (pointVisiting `elem`) pathsToEndpoint


mz1=      [ [0,0,1,0,0,0,1,0],
            [0,0,1,0,0,0,1,0],
            [0,0,1,0,1,1,0,1],
            [0,1,1,1,0,0,1,0],
            [0,0,0,1,0,0,0,0],
            [0,1,0,0,0,1,0,1],
            [0,1,1,1,1,0,0,1],
            [1,1,0,0,0,1,0,1],
            [1,1,0,0,0,0,0,0]]
mz0=       [[0,0],
            [0,0]]

maze1  = listArray ((1,1), (9, 8)) . concat
test1 = [solveMaze (maze1 mz1) (1,1) (9,8)]

test0 = [solveMaze ( (listArray ((1,1), (2, 2)) . concat) mz0) (1,1) (2,2)]


main :: IO()
main  =  print test1
--main = print test0
{-
下面全部是注释
maze mz
array ((1,1),(9,8)) [((1,1),0),((1,2),0),((1,3),1),((1,4),0),((1,5),0),((1,6),0),((1,7),1),((1,8),0),((2,1),0),((2,2),0),((2,3),1),((2,4),0),((2,5),0),((2,6),0),((2,7),1),((2,8),0),((3,1),0),((3,2),0),((3,3),1),((3,4),0),((3,5),1),((3,6),1),((3,7),0),((3,8),1),((4,1),0),((4,2),1),((4,3),1),((4,4),1),((4,5),0),((4,6),0),((4,7),1),((4,8),0),((5,1),0),((5,2),0),((5,3),0),((5,4),1),((5,5),0),((5,6),0),((5,7),0),((5,8),0),((6,1),0),((6,2),1),((6,3),0),((6,4),0),((6,5),0),((6,6),1),((6,7),0),((6,8),1),((7,1),0),((7,2),1),((7,3),1),((7,4),1),((7,5),1),((7,6),0),((7,7),0),((7,8),1),((8,1),1),((8,2),1),((8,3),0),((8,4),0),((8,5),0),((8,6),1),((8,7),0),((8,8),1),((9,1),1),((9,2),1),((9,3),0),((9,4),0),((9,5),0),((9,6),0),((9,7),0),((9,8),0)]



*Maze Data.Array> test1
[[
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),             (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(2,1),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(3,2), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)],

[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (4,5),(4,6),(5,6),(5,7),(6,7),      (7,7),(8,7),(9,7),(9,8)],
[(1,1),(1,2),(2,2),(2,1), (3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5), (5,6),(5,7),(6,7),                  (7,7),(8,7),(9,7),(9,8)]
]]

*Maze Data.Array> test2=[solveMaze(tmp mz1)(1,1)(3,3)]
*Maze Data.Array> test2
[[]]

命令行执行
>ghci Maze.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Maze             ( Maze.hs, interpreted )
Ok, one module loaded.
*Maze> test1
[[[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(2,1),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(3,2),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(4,5),(4,6),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)],[(1,1),(1,2),(2,2),(2,1),(3,1),(4,1),(5,1),(5,2),(5,3),(6,3),(6,4),(6,5),(5,5),(5,6),(5,7),(6,7),(7,7),(8,7),(9,7),(9,8)]]]

-}

第三题,用了C++和Haskell函数式编程语言,源码见上,Haskell真的是很本质的抽象,感觉更加贴近算法本身逻辑。

命令行执行

>ghci Reconstruct.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Reconstruct.hs, interpreted )
Ok, one module loaded.
*Main>  putStrLn $ prettyprint (answer)
'A'
right- 'C'
|  left- 'E'
|     right- 'H'
|     left- 'G'
left- 'B'
   right- 'D'
   |  left- 'F'

代码

module Reconstruct  where
data Tree a
    = Leaf
    | Node a (Tree a)(Tree a) deriving Show 

reconstruct :: Eq a=> ([a],[a]) -> Tree a
reconstruct ([],[])= Leaf
reconstruct (a:x,y)= let (t,x',y') = rec a (x,y)
           in Node a t (reconstruct(x',y'))
rec :: Eq a=>a -> ([a],[a])->(Tree a,[a],[a])
rec a (x@(~(b:x1)),y)
    | head y == a = (Leaf,x,tail y)
    | otherwise   = let (t1,x',y')=rec b (x1,y)
                        (t2,x'',y'')=rec a (x',y')
                   in (Node b t1 t2, x'',y'')
answer = reconstruct (['A','B','D','F','C','E','G','H'],['B','F','D','A','G','E','H','C'])

preorder(Leaf) = []
preorder(Node n t0 t1) = [n] ++ (preorder t0) ++ (preorder t1)
test_pre=preorder (answer)

inorder(Leaf) = []
inorder(Node n t0 t1) = (inorder t0) ++ [n] ++ (inorder t1)
test_in=inorder(answer)

postorder(Leaf) = []
postorder(Node n t0 t1) = (postorder t0) ++ (postorder t1) ++ [n]
test_post=postorder(answer)


{-
*Main> answer
Node 'A' (Node 'B' Leaf (Node 'D' (Node 'F' Leaf Leaf) Leaf)) (Node 'C' (Node 'E' (Node 'G' Leaf Leaf) (Node 'H' Leaf Leaf)) Leaf)
*Main> test_pre
"ABDFCEGH"
*Main> test_in
"BFDAGEHC"
*Main> test_post
"FDBGHECA"

-}

prettyprint :: Show a => Tree a -> [Char]
prettyprint (Leaf)
    = "Empty root."
-- unlines concats a list with newlines
prettyprint (Node node left right) = unlines (prettyprint_helper (Node node left right))

prettyprint_helper (Node node left right)
    = (show node) : (prettyprint_subtree left right)
        where
            prettyprint_subtree left right =
                ((pad "right- " "|  ") (prettyprint_helper right))
                    ++ ((pad "left- " "   ") (prettyprint_helper left))
            pad first rest = zipWith (++) (first : repeat rest)
prettyprint_helper (Leaf)
    = []
main :: IO ()
main = putStrLn $ prettyprint (answer)
{-

*Main> putStrLn $ prettyprint (answer)
'A'
+- 'C'
|  `- 'E'
|     +- 'H'
|     `- 'G'
`- 'B'
   +- 'D'
   |  `- 'F'
-}

{-


>ghci Reconstruct.hs
GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( Reconstruct.hs, interpreted )
Ok, one module loaded.
*Main>  putStrLn $ prettyprint (answer)
'A'
right- 'C'
|  left- 'E'
|     right- 'H'
|     left- 'G'
left- 'B'
   right- 'D'
   |  left- 'F'



-}

参考文章

编程实现方法与核心代码:

第二题C++代码

#include <iostream>

using namespace std;

int success = 0;
/******************寻找路径函数*******************************/
int findpath(int i,int j ,int endRow,int endCol,int** maze,int n ,int m);
/****************走迷宫maze:N*M*********************************/

void showMaze(int startRow,int startCol,int endRow,int endCol,int** maze,int n,int m){
    cout<<"迷宫示意图如下所示:"<<endl;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maze[i][j]==1){
                cout<<"█";
            }else{
                cout<<"  ";
            }
        }
        cout<<endl;
    }
    if (findpath(startRow,startCol,endRow,endCol,maze,n,m)==0){
        cout<<"没有出口"<<endl;
    }else {
        cout<<""<<endl;
        for (int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(maze[i][j]==1){
                    cout<<"█";
                }else if(maze[i][j]==2){
                    cout<<"◇";
                }else{
                    cout<<"  ";
                }
            }
            cout<<endl;
        }
    }
}


/******************i,j当前位置startRow,startCol起点坐标,endRow,endCol终点位置*******************************/

/*********************展示迷宫函数showMaze****************************/
 int findpath(int i,int j,int endRow,int endCol,int** maze ,int n,int m){
     maze[i][j]=2;
     if (i==endRow && j==endCol){
        success=1;
        return success;
     }else {
/***************************寻找出口路径findPath**********************/

/*****************其中,j表示当前位置坐标,endRow,endCol表示出口路径********************************/


/************************递归检查当前格子的相邻四个方向上的格子是否能走*************************/
         if (i<n-1 && j<m-2 && maze[i][j+1] == 0&& success!=1)
            findpath(i,j+1,endRow,endCol,maze,n,m);//right
         if (i<n-2 && j<m-1 && maze[i+1][j] == 0&& success!=1)
            findpath(i+1,j,endRow,endCol,maze,n,m);//down
         if (i<n-1 && j>1 && maze[i][j-1] == 0&& success!=1)
            findpath(i,j-1,endRow,endCol,maze,n,m);//left
         if (i>1 && j<m-1 && maze[i-1][j] == 0&& success!=1)
            findpath(i-1,j,endRow,endCol,maze,n,m); //up
     if(success !=1)
        maze[i][j]=0;//0没走过,1不能走,2走过了
     return success;
     }
 }

/*********************测试主函数main****************************/


int main()
{
    cout << "请输入迷宫的行数N和列数Mn" << endl;
    int n,m;
    cin>>n>>m;
    int** maze = new int* [n];
    for(int i=0;i<n;i++){
        maze[i]=new int[m];
    }
    cout<<"请输入迷宫,1表示墙壁,0表示行走的通道"<<endl;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>maze[i][j];
        }
    }
    int startRow,startCol,endRow,endCol;
    cout<<"请输入迷宫的入口坐标:"<<endl;
    cin>>startRow>>startCol;
    cout<<"请输入迷宫的出口坐标:"<<endl;
    cin>>endRow>>endCol;
    showMaze(startRow,startCol,endRow,endCol,maze,n,m);
    return 0;

}
/*
请输入迷宫的行数N和列数M

4 4
请输入迷宫,1表示墙壁,0表示行走的通道
1 1 1 1
1 0 0 1
1 1 0 1
1 1 1 1
请输入迷宫的入口坐标:
1 1
请输入迷宫的出口坐标:
2 2
迷宫示意图如下所示:
 #  #  #  #
 #        #
 #  #     #
 #  #  #  #

 #  #  #  #
 #  @  @  #
 #  #  @  #
 #  #  #  #


 请输入迷宫的行数N和列数M

11 10
请输入迷宫,1表示墙壁,0表示行走的通道
1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 1 0 1
1 0 0 1 0 0 0 1 0 1
1 0 0 1 0 1 1 0 1 1
1 0 1 1 1 0 0 1 0 1
1 0 0 0 1 0 0 0 0 1
1 0 1 0 0 0 1 0 1 1
1 0 1 1 1 1 0 0 1 1
1 1 1 0 0 0 1 0 1 1
1 1 1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
请输入迷宫的入口坐标:
1 1
请输入迷宫的出口坐标:
9 8
注:这里PDF是8 9 行列式M行N列,和一般习惯的不一样,编程总忘记,看着很难受,我写的时候把行列换回来。
迷宫示意图如下所示:
 #  #  #  #  #  #  #  #  #  #
 #        #           #     #
 #        #           #     #
 #        #     #  #     #  #
 #     #  #  #        #     #
 #           #              #
 #     #           #     #  #
 #     #  #  #  #        #  #
 #  #  #           #     #  #
 #  #  #                    #
 #  #  #  #  #  #  #  #  #  #

 #  #  #  #  #  #  #  #  #  #
 #  @  @  #           #     #
 #     @  #           #     #
 #  @  @  #     #  #     #  #
 #  @  #  #  #        #     #
 #  @  @  @  #  @  @  @     #
 #     #  @  @  @  #  @  #  #
 #     #  #  #  #     @  #  #
 #  #  #           #  @  #  #
 #  #  #              @  @  #
 #  #  #  #  #  #  #  #  #  #

*/

第三题C++代码

/*
*已知前序遍历序列和中序遍历序列建立二叉树
*并求其后序遍历序列和层序遍历序列
*/
#include <iostream>
#include <string>
#include <queue>
#include <string.h>
#include <cstdlib>
#include <math.h>

//二叉树节点结构定义
struct BIN_NODE {
    char data;
    BIN_NODE *leftChild, *rightChild;
};


#define MAX(a,b) (((a)>(b))?(a):(b))

using namespace std;

int PrintTree_h_height;
char PrintTree_h_buffer[6][128];
int PrintTree_h_x;


int PrintTree_h_treeHeight(BIN_NODE* tree){
    if (tree == NULL) return 0;
    int heightLeft = PrintTree_h_treeHeight(tree->leftChild);
    int heightRight = PrintTree_h_treeHeight(tree->rightChild);
    return MAX(heightLeft, heightRight) + 1;
}

void PrintTree_h_corePrintTree(BIN_NODE* tree, int level){
    if (tree == NULL){
        PrintTree_h_x += (pow(2, PrintTree_h_height - level) - 1);
        return;
    }
    char(*a)[128] = PrintTree_h_buffer;
    PrintTree_h_corePrintTree(tree->leftChild, level + 1);
    a[level][PrintTree_h_x++] = tree->data;
    PrintTree_h_corePrintTree(tree->rightChild, level + 1);
}

#define INF 127

void printTree(BIN_NODE* tree){
    if (tree == NULL) return;
    char(*a)[128] = PrintTree_h_buffer;
    for (int i = 0; i<6; i++){
        for (int j = 0; j<128; j++){
            a[i][j] = INF;
        }
    }
    //先获取树高度
    PrintTree_h_height = PrintTree_h_treeHeight(tree);
    if (PrintTree_h_height > 6){
        cout << "树超过6层,无法打印" << endl;
        return;
    }
    PrintTree_h_corePrintTree(tree, 0);
    for (int i = 0; i < 6; i++){
        for (int j = 0; j < 128; j++){
            if (a[i][j] == INF) cout << " ";
            else cout << a[i][j];
        }
        cout << endl;
    }
}

char *preSequence = "ABDFCEGH";
char* inSequence = "BFDAGEHC";
//树根定义
BIN_NODE *tree;
//存储下一层节点的队列
std::queue<BIN_NODE *> memoryNextLevel;

//函数声明
void PrintBinTreeByPostOrder(BIN_NODE *subTree);        //后序打印二叉树数据域
void PrintBinTreeByLevelOrder(BIN_NODE *subTree);       //层序打印二叉树数据域
//通过前序、中序序列建立二叉树
void postorder(BIN_NODE*  t);
void traverse_level(BIN_NODE *root);
BIN_NODE * CreateBinTreeByPreInOrder(char* preSeq, char* InSeq, int subStrLen);

int main()
{
    int groupsAmount = 1;
    //std::cin >> groupsAmount;
    while (groupsAmount--) {
        //std::cin >> preSequence >> inSequence;
        tree = CreateBinTreeByPreInOrder(preSequence, inSequence, strlen(inSequence));
        postorder(tree);
        std::cout << std::endl;
        traverse_level(tree);//层级输出
        std::cout << std::endl;
        printTree(tree);

    }
    return 0;
}
//层次遍历
void traverse_level(BIN_NODE *root)
{
    if (root == 0) {
        return;
    }
    std::queue<BIN_NODE*>  qnodes;
    std::vector<int>       num_nodes; // num_nodes[i] : 第i层结点总数

    num_nodes.push_back(1);     // 第0层结点个数
    num_nodes.push_back(0);

    int n = 0, depth = 0;
    for (qnodes.push(root); !qnodes.empty(); qnodes.pop()) {
        BIN_NODE*temp = qnodes.front();

        std::cout << temp->data << " ";

        if (temp->leftChild) {
            qnodes.push(temp->leftChild);
            num_nodes[depth+1]++;
        }

        if (temp->rightChild) {
            qnodes.push(temp->rightChild);
            num_nodes[depth+1]++;
        }

        // 当前层最后一个节点
        if (++n == num_nodes[depth]) {
            n = 0;
            depth++;
            num_nodes.push_back(0);
            std::cout << std::endl;
        }
    }
}

//二叉树的后序遍历
void postorder(BIN_NODE*  t)
{
    if(t)
    {
        postorder(t->leftChild);
        postorder(t->rightChild);
        std::cout<<t->data<<std::endl;
    }
}

BIN_NODE * CreateBinTreeByPreInOrder(char* preSeq, char* InSeq, int subStrLen) {
    if (0 == subStrLen) {
        return NULL;
    }
    BIN_NODE *node = new BIN_NODE;
    if (node == NULL) {
        std::cerr << "error" << std::endl;
        exit(1);
    }
    node->data = *preSeq;
    //前序相应元素在中序中的下标索引值
    int rootIndex = 0;
    //求解这个索引值
    for (; rootIndex < subStrLen; rootIndex ++) {
        if (InSeq[rootIndex] == *preSeq) {
            break;
        }
    }
    node->leftChild = CreateBinTreeByPreInOrder(preSeq + 1, InSeq, rootIndex);
    node->rightChild = CreateBinTreeByPreInOrder(preSeq + rootIndex + 1,
        InSeq + rootIndex + 1, subStrLen - (rootIndex + 1));
    return node;
}

github有源码,知乎编辑器还是人用的吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值