输出二叉树的方法

我们希望能够在屏幕上打印出树形的二叉树。二叉树以数组的形式存在。就像下面这样


我们为Array类增加了一个 heap_string 函数,它返回数组的二叉树结构。下面将描述这个函数的实现方法。

实现方法

我们的想法是,先在数组A的每个元素的前后增加若干个空格,然后再在适当的地方换行,就可以得到一棵树了。如下图所示
 

其规律就是,A[2]的宽度=A[4]的宽度+A[5]的宽度;A[1]的宽度=A[2]的宽度+A[3]的宽度。A[3]的宽度不太好办,因为它的下方没有孩子节点。这个问题可以通过向数组A增加若干个值为空格的节点,将数组变成一棵满二叉树来解决。

构造一棵满二叉树

我们将创建数组A的一个副本“out_heap”,它的元素都是String,并且是一棵满二叉树,ruby代码如下

 1 class  Array
 2    def  heap_string(space = '    ' )
 3      #  Prepares out_heap
 4      #  The out_heap is a full tree and every node is a String
 5     out_heap  =  Array.new
 6     out_heap.base_index  =   1
 7     
 8     self.each do  | v |
 9       out_heap  <<  v.to_s
10     end
11     
12     full_tree_size  =   2 ** (self.heap_height + 1 ) - 1
13     out_heap  +=  Array.new(full_tree_size - out_heap.length,  '   ' )
14     out_heap.heap_size  =  self.heap_size
15
16     
17
18   end
19 end

此后我们的所有操作都将针对out_heap。接下来,我们将为out_heap中的每个元素增加若干个空格。

追加空格

我们将以“左-右-中”的顺序遍历out_heap,即以out_heap[4]->out_heap[5]->out_heap[2]->out_heap[3]->out_heap[1]的顺序访问out_heap,依次计算出每个元素的宽度并插入空格。详细描述如下:
1. 如果是叶子,则在叶子的左右添加space。space默认等于两个空格。
2. 如果不是叶子,则节点的宽度等于两个孩子的宽度之和,并且居中显示。
对应的ruby代码如下
 1  class  Array
 2     def  heap_string(space = '    ' )
 3       #  Prepares out_heap
 4       #  The out_heap is a full tree and every node is a String
 5      
 6      
 7 
 8       #  Adds spaces to each node in out_heap
 9      out_heap.extend(HeapLRMEnumerator)
10      out_heap.each_index( 1 , out_heap.length) do  | i |
11        l  =  left(i)
12        r  =  right(i)
13        
14         if  l  >  out_heap.length  #  is leaf
15          out_heap[i]  =  space  +  out_heap[i]  +  space
16        elsif l  <=  out_heap.length  #  is not leaf
17          out_heap[i]  =  out_heap[i].center(out_heap[l].length + out_heap[r].length)
18        end
19      end
20    
21      
22 
23    end
24  end

到此out_heap中的值为 ["           A[1]           ", "      A[2]      ", "   A[3]   ", "  A[4]  ", "  A[5]  ", "     ", "     "]
使用“左-右-中”的顺序遍历数组是通过上面代码的第9行“out_heap.extend(HeapLRMEnumerator)”来实现的,HeapLRMEnumerator 是我们编写的一个以“左-右-中”的顺序遍历数组的迭代器,代码将在本文的最后给出。

生成连接线“/”和“\”

我们还需要生成节点之间的连接线。注意到连接线的宽度总是和父节点的宽度相同,但是我们不能象上面那样使用"/\".center(宽度)这样的语句,因为我们需要的不仅仅是居中,而是“分散剧中”---我们需要的是
“   /   \   ”而不是“   /\   ”。为此我们为String类追加了一个distribute_center()函数,可以实现这个效果(源代码在最后)。我们为out_heap中每个有孩子的节点生成连接线,保存到conn_lines数组中,ruby代码如下
 1  class  Array
 2     def  heap_string(space = '    ' )
 3       #  Prepares out_heap
 4       #  The out_heap is a full tree and every node is a String
 5      
 6      
 7 
 8       #  Adds spaces to each node in out_heap
 9     
10      
11 
12       #  Generates "/" and "\"
13      out_heap  =  out_heap.dup   #  back to ordered enumerator
14      out_heap.base_index  =   1
15      
16      conn_lines  =  Array.new
17      ( 1 ..out_heap.length).each do  | i |
18        l  =  left(i)
19        r  =  right(i)
20        conn_line_string  =   ""
21         if  l  <=  out_heap.heap_size   #  has left child
22          conn_line_string  <<   " / "
23        end
24         if  r  <=  out_heap.heap_size   #  has right chile
25          conn_line_string  <<   " \\ "
26        end
27        conn_lines[i]  =  conn_line_string.distribute_center(out_heap[i].length)
28      end
29 
30      
31    end
32  end

到此 conn_lines 中的内容为[nil, "        /        \\        ", "     /     \\    ", "          ", "        ", "        ", "     ", "     "]

合并

接下来我们把上面生成的所有的东西合并在一起,并加上换行符。
 1 class  Array
 2    def  heap_string(space = '    ' )
 3      #  Prepares out_heap
 4      #  The out_heap is a full tree and every node is a String
 5     
 6     
 7     
 8      #  Adds spaces to each node in out_heap
 9    
10     
11
12      #  Generates "/" and "\"
13    
14     
15
16      #  Combine out_heap and conn_lines
17     out_heap.each_index do  | i |
18       parent  =  parent(i)
19       
20        if  parent  >=   1   &&  leftest?(i)   #  is leftest and is not root
21         conn_lines_string  =   ""
22         (parenti).each do  | j |
23           conn_lines_string  <<  (conn_lines[j]  ||   "" )
24         end
25       
26         out_heap[i]  =   " \n "   +  conn_lines_string  +   " \n "   +  out_heap[i]
27       end
28     end
29     
30      return  out_heap.to_s
31   end


程序到此结束。

缺陷

由于我们是从下到上计算每个元素的宽度,所以如果A[2]超长的话,就会变成下面这样

如果是你,会怎么解决这个问题呢?

全部源代码

全部源代码和单元测试代码

转载于:https://www.cnblogs.com/1-2-3/archive/2007/08/27/871390.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值