二叉树 迭代 前 中 后

Data structures and algorithms are the heart and soul of computer science and software. One cannot learn programming without understanding how data is organized in code and how to manipulate it.

数据结构和算法是计算机科学和软件的灵魂。 如果不了解数据如何以代码形式组织以及如何操纵它,就无法学习编程。

One such data structure is a binary tree:

一种这样的数据结构是二叉树:

Oh no not that kind of tree, I mean this one:

哦,不是那种树,我是说这棵树:

In simple terms, a tree is network of ‘nodes’. A node is an object whose properties include the data itself and pointers to its ‘children’. For a binary tree, the maximum number of children each node can have is 2. A binary tree will have a root node and at most two children. Each child is just a pointer to another tree object or it can be nil. Using a hash, this can be visualized as:

简单来说,树是“节点”的网络。 节点是一个对象,其属性包括数据本身和指向其“子代”的指针。 对于二叉树,每个节点最多可以有2个子节点。一棵二叉树将有一个根节点,最多两个孩子。 每个孩子只是一个指向另一个树对象的指针,也可以为nil。 使用哈希,可以将其可视化为:

tree = {:data        => 1,:left_child  => [another_tree] || nil,:right_child => [another_tree_again] || nil
}

Before we go into height computations let us first find some uses for binary trees.

在进行高度计算之前,让我们首先找到二叉树的一些用途。

If you observe the directories or file structure in your computer, it follows a (albeit the more general) tree structure. Each folder can contain files (the data) and a number of other directories (which are not necessarily data in themselves but rather just addresses of such data contained within those sub directories). There are other use cases for binary trees that discussed better by other articles:

如果您观察计算机中的目录或文件结构,则它遵循(尽管更通用)树形结构。 每个文件夹可以包含文件(数据)和许多其他目录(它们本身不一定是数据,而只是那些子目录中包含的此类数据的地址)。 其他文章还讨论了二进制树的其他用例:

In Quora

在Quora

Stack Overflow

堆栈溢出

Binary trees are a vast subject and there are so many things that I can write about them (such as the different ways to search through them — a future article perhaps?). However, here I will be very specific — computing the height of a binary tree.

二叉树是一个广阔的主题,我可以写很多关于它们的东西(例如搜索它们的不同方法,也许是将来的文章?)。 但是,在这里我将非常具体-计算二叉树的高度。

The first thing to understand in relation to this, is that we can represent a binary tree using an array. But even though that’s possible, there are a number of ways to lay down each node and associate them (as an element in an array) to their respective left and right children.

与此相关的第一件事是,我们可以使用数组表示二叉树。 但是,即使有可能,也有很多方法可以放置每个节点并将它们(作为数组中的元素)关联到各自的左,右子级。

For simplicity we’ll use the “breadth-first” method of flattening the tree. In ‘breadth-first’ we place the data contained in each node starting from the root. Then we go to the next lower level, laying down each node’s data from left to right. We go through all the levels until the lowest one.

为简单起见,我们将使用“宽度优先”的方法来展平树。 在“广度优先”中,我们从根开始放置每个节点中包含的数据。 然后我们进入下一个较低级别,从左到右放置每个节点的数据。 我们遍历所有级别,直到最低级别。

If a sub tree has no left or right child then such child can be represented as 0, as long as the sub tree isn’t in the lowest level in the binary tree.

如果子树没有左或右子级,则只要子树不在二叉树的最低级别,该子级就可以表示为0。

tree = [1, 7, 5, 2, 6, 0, 9, 3, 7, 5, 11, 0, 0, 4, 0] (T0)* array representation of Figure2

Numerically, we can compute the positions of the left and right children of each node:

从数值上讲,我们可以计算每个节点左右子节点的位置:

left child of tree[i] is at index 2*i + 1 (T1)right child of tree[i] is at index 2*i + 2 (T2)

As we can see from figure 2 we can tell how tall a tree is — that is we just need to count how many nodes there are from the root down to the lowest element (including the root and the lowest element) along the longest branch. But when it’s already in array form, how do we know how tall it is?

从图2中可以看出,我们可以判断一棵树有多高-也就是说,我们只需要计算从树根到沿最长分支的最低元素(包括根和最低元素)的节点数。 但是,当它已经处于数组形式时,我们如何知道它的高度呢?

First we must have a general formula for the height of any tree:

首先,我们必须对任何树的高度都有一个通用公式:

height = 1 + max of(left_child_height, right_child_height) (T3)

For multilevel trees then we can conclude that in order to compute the height of any sub-tree (and the tree itself) we first must compute the heights of the left and right children and then find the higher between the two. In computing the heights of these two children we need to compute the heights of their respective children and so on.

对于多级树,我们可以得出结论,为了计算任何子树(和树本身)的高度,我们必须首先计算左右子节点的高度,然后在两者之间找到较高的子节点。 在计算这两个孩子的身高时,我们需要计算他们各自的孩子的身高,依此类推。

Having this we can now begin to outline an algorithm for computing the height of multilevel binary trees. There are two methods we can take, one is using iterations or loops, and the other, because of the repetitive nature of the steps (previous paragraph), is using recursion. I will follow up this article with a discussion on how to use recursion to do this. However, that would be too easy. So let’s learn the hard way first: we’ll do this using iteration.

有了这个,我们现在可以开始概述一种用于计算多层二叉树的高度的算法。 我们可以采用两种方法,一种是使用迭代或循环,另一种是由于步骤的重复性(上一段),所以使用了递归。 我将在本文的后续部分讨论如何使用递归执行此操作。 但是,那太容易了。 因此,让我们首先学习困难的方法:我们将使用迭代来实现。

迭代法 (Iterative Method)

We will use the tree array T0 above to illustrate this process

我们将使用上面的树数组T0来说明此过程

Step 0: Declare a heights array which will store the heights of each sub tree.

步骤0:声明一个heights数组,该数组将存储每个子树的高度。

heights = [] (S0.1)

Step 1: Iterate through the array — since we need to compute the heights of the descendants first, we iterate from the last element. And instead of using each method directly in the tree array we will use it for the indices of each element.

步骤1:遍历数组-由于我们需要首先计算后代的高度,因此我们从最后一个元素进行遍历。 与其直接在树数组中使用each方法,我们不如将其用于每个元素的索引。

(tree.length - 1).downto(0) do |i| (S1.1)

Step 2: For each element, find initial height — if the element is zero (meaning it’s actually a nil node) then initial height is 0, else it is 1.

步骤2:对于每个元素,找到初始高度-如果元素为零(意味着它实际上是一个零节点),则初始高度为0,否则为1。

initial_height = tree[i] == 0 ? 0 : 1 (S2.1)

Step 3: Find height of left child — inside heights array, if the element has a left child then the height of this child is equal to:

步骤3:查找左子节点的heights -在heights数组中,如果元素中有左子heights ,则该子节点的高度等于:

left_child_height = heights[left_child_index] (S3.1)

In the above, the left_child_index can be computed as follows:

在上面的代码中, left_child_index计算公式如下:

left_child_index = heights.length - i - 1 (S3.2)

I came up with S3.2 through a little trial and error. In the simulation that will follow these series of steps I will make mention of it.

我通过一些反复试验提出了S3.2 。 在遵循这些系列步骤的模拟中,我会提到它。

To summarize though, I initially intended to unshift each descendant’s heights into heights so that the heights of each element would have the same indices as the element itself has on trees. But as I’ll later note, using unshift for this will be taxing resource wise for large array inputs.

总之,虽然,我最初打算unshift每个后代的高度为heights ,使每个元素的高度将具有相同的指数作为元素本身对trees 。 但是,正如我稍后会指出的那样,为此使用unshift将对大型数组输入增加资源方面的负担。

So then I decided to use push. Each height will then be ordered in reverse compared to their corresponding elements’ order in tree. So that the height, let’s say of tree[0] will ultimately be located in heights[-1].

因此,我决定使用push 。 与tree相应元素的顺序相比,每个高度的顺序将相反。 假设tree[0] heights[-1]最终位于heights[-1]

If the element in question has no left child then left_child_index should be nil. To ensure that we catch this scenario:

如果所讨论的元素没有左子元素,则left_child_index应该为nil 。 为了确保我们能抓住这种情况:

left_child_index = nil if tree[2*i + 1].nil? (S3.3)

Putting S3.2 and S3.3 together using a ternary:

使用三元数将S3.2S3.3放在一起:

left_child_index = tree[2*i + 1].nil? ? nil : heights.length - i -1 (S3.4)

Therefore, the height of the left child will have to be 0 if left child is nil. The full formula for left_child_height then is:

因此,如果left child为nil则left child的高度必须为0。 那么left_child_height的完整公式为:

left_child_height = left_child_index.nil? ? 0 : heights[left_child_index] (S3.5)

Step 4: Find height of right child — finding the height of the right child of a sub tree follows the same logic as Step 3. Since we are filling up heights array from left to right (using push) and we are iterating tree from right to left, the height of the right child of any sub tree will always be pushed first to heights. Therefore, the left child of any element will be at position left_child_index -1 inside heights (if right child is not nil in tree). Taking these into consideration and following the logic of Step 3:

步骤4:查找右子节点的高度-查找子树的右子节点的高度遵循与步骤3相同的逻辑。由于我们从左到右填充了heights数组(使用push ),并且从右迭代了tree向左移,任何子树的右孩子的高度将始终先推到heights 。 因此,任何元素的左子元素都将位于heights内的left_child_index -1位置(如果right子元素在tree不是nil )。 考虑这些因素并遵循步骤3的逻辑:

right_child_index = tree[2*i + 2].nil? nil : left_child_index - 1 (S4.1)
right_child_height = right_child_index.nil? ? 0 : heights[right_child_index] (S4.2)

Step 5: Find element’s total height — After finding the heights of the left and right children of the element in question (at i index in Ltree), we can now find that element’s total height:

步骤5:查找元素的总高度—找到所讨论元素的左右子元素的高度(在L tree i索引处)后,我们现在可以找到该元素的总高度:

total_height = initial_height + [left_child_height, right_child_height].max (S5.1)

Numerically speaking, if the element is 0 and it happens to have any child(ren) inside tree then such child(ren) will also be 0. Hence, its total_height will also be 0. Such is the case with element at i = 5 in T0 above:

从数字上讲,如果元素为0且恰好在树内有任何子级,则该子级也将为0。因此,其total_height也将为0。元素在i = 5在上面的T0

left  rightchild child
tree = [1, 7, 5, 2, 6, 0,  9, 3, 7, 5, 11, 0,   0,   4, 0] i=5                i=11 i=12element in question
(T0 here repeated)
total_height = 0 + [0,0].max = 0 (S5.2)

But for the element at i = 4, the height is:

但是对于i = 4的元素,高度为:

left   rightchild  child
tree = [1, 7, 5, 2, 6, 0,  9, 3, 7,   5,    11,     0, 0, 4, 0] i=4               i=9  i=10element in question
total_height = 1 + [1,1].max = 2 (S5.3)

In S5.3 and S5.4 above we just used visual inspection to compute the heights of the right and left children of the element in question. But this illustrates how our algorithm works. Now after computing for the total_height we simply:

在上面的S5.3S5.4 ,我们只是使用视觉检查来计算所讨论元素的左右子元素的高度。 但这说明了我们的算法是如何工作的。 现在,在计算了total_height之后,我们简单地:

Step 6: Push total_height into heights — As I noted before, using the push method is more efficient, especially for large arrays.

步骤6:将 total_height推入heights —如前所述,使用push方法更有效,尤其是对于大型阵列。

heights.push(total_height) (S6.1)

Once we have iterated through all elements in the tree array, we will have an array heights composed of the heights of each sub tree in the binary tree. It should look like this:

一旦遍历了tree数组中的所有元素,我们将拥有一个由二叉树中每个子树的heights组成的数组heights 。 它看起来应该像这样:

heights(after full iteration) = [0, 1, 0, 0, 1, 1, 1, 1, 2, 0, 2, 2, 3, 3, 4] (S6.2)

Step 7: Return height of the binary tree — If our goal is just find out the height of the mother tree (meaning from the root down to the lowest-rightmost node) then we simply:

第7步:返回二叉树的高度—如果我们的目标只是找出母树的高度(即从根到最右端的最低节点),那么我们只需:

return heights[-1] (S7.1)
*Note if this is the last line in the method then the 'return' keyword is redundant (in Ruby at least)

However, a lot of times we may be interested to compute for the heights of any of the sub trees. In that case we simply return the heights array itself and then anyone using the program can simply include any index to find the height of a specific branch in the tree.

但是,很多时候我们可能会对计算任何子树的高度感兴趣。 在那种情况下,我们只返回heights数组本身,然后任何使用该程序的人都可以简单地包含任何索引来找到树中特定分支的高度。

The full method below:

完整方法如下:

def binary_tree_height(tree_array)#0 Declare a heights array which will store the heights of each sub treeheights = []#1 Iterate through the tree_array starting from last element down to first(tree_array.length - 1).downto(0) do |i|#2 For each element, find initial heightinitial_height = tree_array[i] == 0 ? 0 : 1# 3 Find height of left childleft_child_index = tree_array[2*i + 1].nil? ? nil : heights.length - i - 1 #index of left child's height in heightsleft_child_height = left_child_index.nil? ? 0 : heights[left_child_index] # 4 Find height of right childright_child_index = tree_array[2*i + 2].nil? ? nil : left_child_index - 1 #index of right child's height in heightsright_child_height = right_child_index.nil? ? 0 : heights[right_child_index]# 5 Find element's total heighttotal_height = initial_height + [left_child_height,right_child_height].max# 6 Push total height to heights arrayheights.push(total_height)endputs heights[-1]
end

Let’s test this algorithm out.

让我们测试一下该算法。

Let us suppose we run binary_tree_height(tree). Computing for the heights of tree[14] down to tree[7] is pretty straightforward (they will either be 0 or 1 since they are all at the lowest level of tree) so we won’t simulate them anymore here. We will assume we are already in that part of the iteration when i will be equal to 6. Therefore, at this juncture:

让我们假设我们运行binary_tree_height(tree).tree[14]tree[7]的高度的计算非常简单(由于它们都位于tree的最低级别,因此它们将为0或1),因此在此不再赘述。 我们将假设当i等于6时,我们已经处于迭代的那一部分。因此,在此关头:

i = 6 (F1)
tree[6] = 9 (F2)
heights = [0, 1, 0, 0, 1, 1, 1, 1] (heights.length at this point is 8) (F3)

Now, we can see that tree[6] is equal to 9 (and not 0). Therefore:

现在,我们可以看到tree[6]等于9(而不是0)。 因此:

initial_height = 1 (F4)

As promised, here is how I came up with the formula for the indices of the left and right children.

如所承诺的,这是我想到左,右子项索引的公式的方法。

So I began with a heights array already filled with the heights of the lowest elements as shown in F3. Since I’m now working with tree[6] (which is 9) then its left and right children are tree[13] and tree[14]; whose corresponding heights are in heights[1] and heights[0], respectively. If that’s not clear enough, we know we push starting from tree[14] — this will become heights[0]. We then compute for and push the height of tree[13] — this will be heights[1]. Relating the indices:

因此,我首先从一个heights数组开始,上面已经填充了最低元素的高度,如图F3所示。 由于我现在正在使用tree[6] (即9),因此它的左右两个子元素分别是tree[13]tree[14] ; 其相应的高度分别为heights[1]heights[0] 。 如果这还不够清楚,我们知道我们从tree[14]开始推送-这将成为heights[0] 。 然后,我们计算并推入tree[13]的高度-这将是heights[1] 。 相关索引:

index of left child in trees = 13
index of left child's height in heights = LEFT_INDEX =1
index of right child in trees = 14
index of right child's height in heights = RIGHT_INDEX = 0
current index of element in question = MOTHER_INDEX = 6
current length of heights array = LENGTH = 8
LEFT_INDEX = 1 = 8 - 6 - 1 = LENGTH - MOTHER_INDEX - 1
RIGHT_INDEX = 0 = 8 - 6 - 2 = LENGTH - MOTHER_INDEX - 2
(or simply LEFT_INDEX -1 ) (F5)

We can now apply this logic to all elements, so then in code we compute for the height of tree[6] as follows:

现在,我们可以将此逻辑应用于所有元素,因此,在代码中,我们可以计算出tree[6]的高度,如下所示:

Computing for tree[6]'s left child's height:
from code at S3.4:
left_child_index = tree[2*i + 1].nil? ? nil : heights.length - i - 1
Since tree[2*6 + 1] = tree[13] = 4 is not nil then:
left_child_index = 8 - 6 - 1 = 1
from code at S3.5:
left_child_height = left_child_index.nil? ? 0 : heights[left_child_index]
So then:
left_child_height = heights[1] = 1

Following the same for tree[6]’s right child’s height:

遵循tree[6]的右孩子的身高:

from code at S4.1:
right_child_index = tree[2*i + 2].nil? nil : left_child_index - 1
Since tree[2*6 + 2] = tree[14] = 4 and is not nil:
right_child_index = left_child_index -1 = 1 -1 = 0 -> !nil?
and from code at S4.2:
right_child_height = right_child_index.nil? ? 0 : heights[right_child_index]
Therefore: right_child_height = heights[0] = 0

Now we can find the total height of tree[6]:

现在我们可以找到tree[6]的总高度tree[6]

total_height (tree[6]) = 1 + [1,0].max = 1 + 1 = 2

We can then push this total_height into heights:

然后,我们可以将total_height推入heights

heights.push(2), such that:
heights = [0, 1, 0, 0, 1, 1, 1, 1, 2]

And the same thing goes on until we work on tree[0] and the final heights array should be:

直到我们处理tree[0]且最终的heights数组应为:

heights = [0, 1, 0, 0, 1, 1, 1, 1, 2, 0, 2, 2, 3, 3, 4]

And returning heights[-1] (or heights[heights.length -1], whichever we prefer), we determine that the height of tree is 4. We can verify this visually in both figures 1 and 2 above.

然后返回heights[-1] (或heights[heights.length -1] ,无论我们喜欢哪个),我们确定tree的高度为4 。 我们可以在上面的图1和图2中直观地验证这一点。

It took us 7 steps to come up with the answer. With this size of tree array the operation took around 0.024 milliseconds to finish. It takes half the time (only 0.012 milliseconds) for the same thing to be accomplished using recursion.

我们花了7个步骤得出答案。 使用这种大小的tree数组,操作大约需要0.024毫秒才能完成。 使用递归可以完成相同的事情,只花费一半的时间(仅0.012毫秒)。

As a preview on how to do this recursively, we can simply do something like:

作为有关如何递归执行此操作的预览,我们可以简单地执行以下操作:

def tree_height_recursive(tree_array, index = 0)return 0 if tree_array[index].nil? or tree_array[index] == 0left_child_height = recursive_tree_height(tree_array, 2*index + 1)right_child_height = recursive_tree_height(tree_array, 2*index +2)total_height = 1 + [left_child_height, right_child_height].max
end

We see that recursion probably will only take us at most 4 steps to do the same task. And it saves us half of the time and less resources used.

我们看到递归可能最多只需要4个步骤就可以完成相同的任务。 而且它为我们节省了一半的时间,并减少了资源消耗。

One secret for learning algorithms is hard work and practice. It also helps if you work collaboratively with others. I actually did the above not alone but with my coding partner. I previously wrote about how learning this way is so much more productive and effective.

学习算法的一个秘诀是努力工作和实践。 如果您与他人合作,也将有所帮助。 实际上,我不仅是与编码合作伙伴一起完成上述操作。 之前,我曾写过关于以这种方式学习如何提高生产力和效率的文章。

Here is my repository on the different data structures and algorithms that I’ve worked on.

这是我存储的有关不同数据结构和算法的存储库 。

Follow me on Twitter | Github

Twitter上 关注我 | Github

翻译自: https://www.freecodecamp.org/news/how-to-calculate-a-binary-trees-height-using-array-iteration-in-ruby-63551c6c65fe/

二叉树 迭代 前 中 后

二叉树 迭代 前 中 后_如何在Ruby中使用数组迭代计算二叉树的高度相关推荐

  1. typescript中函数_如何在TypeScript中合成Canvas动画

    typescript中函数 by Changhui Xu 徐昌辉 如何在TypeScript中合成Canvas动画 (How to Compose Canvas Animations in TypeS ...

  2. javascript中索引_如何在JavaScript中找到数字在数组中所属的索引

    javascript中索引 Sorting is a very important concept when writing algorithms. There are all kinds of so ...

  3. 在linux中的文件中查找_如何在Linux中查找文件

    在linux中的文件中查找 如果您是Windows用户或OSX的非超级用户,则可能使用GUI查找文件. 您可能还会发现界面有限,令人沮丧或两者兼而有之,并且学会了精于组织事物并记住文件的确切顺序. 您 ...

  4. m 文件 dll matlab 中调用_如何在matlab中调用python程序

    现在python很火,很多代码都是python写的,如果你和我一样,习惯了使用matlab,还想在matlab中调用Python的代码,应该怎么办呢?其中一条思路:首先在matlab中调用系统脚本命令 ...

  5. scala中捕获异常_如何在Scala中引发异常?

    scala中捕获异常 Scala的例外 (Exceptions in Scala) Exceptions are cases or events that occur in the program a ...

  6. ruby字符串截取字符串_如何在Ruby中附加字符串?

    ruby字符串截取字符串 There are multiple ways to do the required but we will study about three of them. 有多种方法 ...

  7. scala集合中添加元素_如何在Scala中获得列表的第一个元素?

    scala集合中添加元素 清单 (List) A list is a linear data structure. It is a collection of elements of the same ...

  8. ruby hash添加数据_如何在Ruby中向Hash添加元素?

    ruby hash添加数据 Before going through the ways to add elements to the hash instances, let us understand ...

  9. error:lnk2005 已经在*.obj中定义_如何在 Spring 中自定义 scope

    大家对于 Spring 的 scope 应该都不会默认.所谓 scope,字面理解就是"作用域"."范围",如果一个 bean 的 scope 配置为 sing ...

最新文章

  1. OpenCV 【四】————Watershed Algorithm(图像分割)——分水岭算法的原理及实现
  2. dispatch js实现_详解vuex中action何时完成以及如何正确调用dispatch的思考
  3. vbs 服务器获取输入信息,取得服务器上用户组列表脚本之VBS版
  4. python:字典,元组
  5. Java黑皮书课后题第3章:**3.29(几何:两个圆)编写程序,提示用户输入两个圆的中心坐标和各自的半径值,然后判断圆是在第一个圆内,还是和第一个圆重叠
  6. Android 通过腾讯WebService API获取 地址经纬度
  7. CodeCraft-20 (Div. 2) D. Nash Matrix 构造 + dfs
  8. Pandas知识点-比较操作
  9. CSS外边距合并(塌陷/margin越界)
  10. 关于用C#调用C++的dll中的函数,获取字符串返回值的一些细节
  11. vue调用企业微信API详细过程
  12. 每日excel学习之排序与筛选
  13. 教程|教你如何给你的头像添加一个好看的国旗
  14. 机械键盘知识漫谈(一)- 初级篇
  15. git clone时需要密码
  16. lumia535 刷Android,附教程:看看你的Lumia手机能不能刷安卓!
  17. vue使用three.js加载obj和mtl
  18. dos的cd命令输入cd d: 怎么不能切换到D盘了?
  19. 生存之道,每个人都值得尊敬
  20. 全球顶尖大学已将加密货币加入其课程

热门文章

  1. css3 flex的IE8浏览器兼容问题
  2. 电脑计算机无法启动有还原和取消,电脑启动修复无法取消 怎么处理
  3. 用户交互界面---python-PySimpleGUI库
  4. 谁家的宣传口号最赞?
  5. 为什么int8的取值范围是-128 - 127
  6. Flutter实战——Map Json Object对象转换
  7. 对LOAM算法原理和代码的理解
  8. L1-043 阅览室 (20 分)——memset补充
  9. iostat linux,centos安装iostat命令的方法详解
  10. 电视综艺舆情如何监控?