以前老师有讲过,《数据结构》这门课很重要,工作的过程中遇到的概率非常大。一点都不假,既然遇到了,就温习一下。
二叉树最经典了,后序遍历的规则是:先访问左节点,再访问右节点,最后访问根节点。那就以这个规则,推广至多叉树。
我们假设树的结构已经用PowerShell定义好了:
$Tree = @{ Name='差旅费' Child=@( @{ Name='机票费' Child=@( @{ Name='国内机票' }, @{ Name='国际机票' } ) }, @{ Name='火车费' }, @{ Name='酒店费' Child=@( @{ Name='一星级酒店' }, @{ Name='五星级酒店' }) }, @{ Name='招待费' Child=@( @{ Name='日本按摩' }, @{ Name='韩国大保健' } ) }, @{ Name='上网费' Child=@( @{ Name='看电影' }, @{ Name='访问《PowerShell中文博客:PSTips.NET》' }) } ) }
接下来演示整个思考的过程,凭着直觉先写出了第一个遍历函数:
function Traverse-Tree1{ param($root) $stack = New-Object System.Collections.Stack $stack.Push($root) while($stack.Count -gt 0){ $item = $stack.Pop() $item.Name if($item.Child.Count -gt 0){ $item.Child | foreach{ $stack.Push($_) } } } }
输出为:
差旅费 上网费 访问《PowerShell中文博客:PSTips.NET》 看电影 招待费 韩国大保健 日本按摩 酒店费 五星级酒店 一星级酒店 火车费 机票费 国际机票 国内机票
虽然每个节点都访问到了,但是原需求中还要求输出层级关系,并且只输出叶子节点,改动如下:
function Traverse-Tree2{ param($root) $stack = New-Object System.Collections.Stack $stack.Push($root) while($stack.Count -gt 0){ $item = $stack.Pop() if($item.Child.Count -gt 0){ $item.Child | foreach{ $_.Name = '{0}->{1}' -f $item.Name , $_.Name $stack.Push($_) } } else{ $item.Name } } }
输出为:
差旅费->上网费->访问《PowerShell中文博客:PSTips.NET》 差旅费->上网费->看电影 差旅费->招待费->韩国大保健 差旅费->招待费->日本按摩 差旅费->酒店费->五星级酒店 差旅费->酒店费->一星级酒店 差旅费->火车费 差旅费->机票费->国际机票 差旅费->机票费->国内机票
当我沾沾自喜准备收工时,发现节点的顺序不是期望的后序遍历。
此时,我意识到问题虽小,那是也马虎不得,应当静下心来下把算法在草稿纸上写出来,然后再考虑代码实现。
1. 根节点 入栈
2. 检查栈顶元素,
2.1 如果没有子节点,输出该节点,并出栈
2.2 如果有子节点,且所有的子节点都被访 问过,输出该节点,并出栈
2.3 否则标志该子节点被访问过,并将子节点压入堆栈
2.4 重复步骤2,直到栈为空
下面才是正解:
function Traverse-Tree3{ param($root) $stack = New-Object System.Collections.Stack # 1.根节点入栈 $stack.Push(@{Node=$root;Index=0}) while($stack.Count -gt 0){ # 2. 检查栈顶元素 $item = $stack.Peek() # 2.1 如果没有子节点,输出该节点,并出栈 # 2.2 如果有子节点,且所有的子节点都被访问过,输出该节点,并出栈 if(($item.Node.Child.Count -eq 0) -or ($item.Index -eq $item.Node.Child.Count)){ if($item.Node.Child.Count -eq 0) { $item.Node.Name } $null = $stack.Pop() } # 2.3 否则标志该子节点被访问过,并将子节点压入堆栈,重复2, else{ $child = @{Node = $item.Node.Child[$item.Index];Index=0} $child.Node.Name = '{0}->{1}' -f $item.Node.Name , $child.Node.Name $stack.Push($child) $item.Index = $item.Index+1 } # 2.4 重复步骤2,直到栈为空 } }
输出为:
差旅费->机票费->国内机票 差旅费->机票费->国际机票 差旅费->火车费 差旅费->酒店费->一星级酒店 差旅费->酒店费->五星级酒店 差旅费->招待费->日本按摩 差旅费->招待费->韩国大保健 差旅费->上网费->看电影 差旅费->上网费->访问《PowerShell中文博客:PSTips.NET》
本文链接: https://www.pstips.net/traverse-tree.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!