Week 6 of Arts | iterate through binary tree | reread inflection point of effective go | brush problem



Arts is an activity launched by Chen Hao in the geek time column. The purpose is to keep learning through sharing.

Each person writes an arts every week: algorithm is an algorithm problem, review is to read an English article, technology / tips is to share a small technology, share is to share a viewpoint.

Content of this week

This week’s arts you’ll see:

  1. Iterative way to achieve the binary tree after the order traversal
  2. Reread go official effective go
  3. The first inflection point of the ability to solve algorithm problems


This week’s problem is to iterate through the binary tree.

Traversing the binary tree is probably one of the simplest and most basic algorithm problems you can think of. Traversing by recursion may be less than 10 lines of code. But the problem is hard. Why?

The reason is very simple, in the topic this must add the request, lets the difficulty soar.

Follow up: Recursive solution is trivial, could you do it iteratively?

In this paper, we use iterative method to realize the post order traversal. In fact, for preorder and mesorder traversal, the iterative method is not difficult to achieve. As long as the idea of stack is used, the recursive node traversal order can be simulated by iteratively maintaining the stack. Even if you can’t think of it for a while, you can easily understand and remember it by looking at a regular implementation, but the iterative way of post order traversal is not so easy. It is difficult to simulate the stack and ensure that the current node outputs after its left and right child nodes. If you do not pass some skills, it is easy to cause the code to be very succinct, and to use multiple loops to deal with it, resulting in poor readability of the code and writing mistakes.

After trying all kinds of collapsing iterative post order traversal methods, I find the simplest way to achieve it here, and the code of pre -, middle -, and post order traversal can keep the same style. Here is my translation of this solution into golang’s version.

//Through the iterative simulation of recursion after the first out to achieve after order traversal
//For the preorder traversal, we only need to change the stack order of the current node and its left and right sub nodes
//Very good unification of the three traversal
func postorderTraversal(root *TreeNode) []int {
    var ans []int
    var stack []*TreeNode
    //Put the root node on the stack first
    stack = append(stack, root)
    for len(stack) > 0 {
        top := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        if top != nil {
            //The current node is put into the stack first, so that when it is put out of the stack, it can ensure that it is later than the child node
            //And for the node that has processed the child node, it will press in a nil as a mark when it enters the stack again
            //Next time you traverse to nil, you will directly put the nodes under nil out of the stack
            stack = append(stack, top, nil)
            //The stacking sequence of child nodes is from right to left, which ensures that the stack is from left to right
            if top.Right != nil {
                stack = append(stack, top.Right)
            if top.Left != nil {
                stack = append(stack, top.Left)
        } else if len(stack) > 0 {
            //The nodes that have processed the child nodes are directly out of the stack and added to the output
            top = stack[len(stack)-1]
            ans = append(ans, top.Val)
            stack = stack[:len(stack)-1]
    return ans

Review article recommendation

This week, I reread go’s official effective go. This is an official golang e-book or Changwen. This paper mainly introduces some common usages of go or “best practices” to readers who have known the basic grammar of go. Because the last time I read it, because the article was too long, I just skimmed over it. This time I read it patiently and found some points that I didn’t pay much attention to before. Many places are more or less aware of some, but if there are official articles to prove it, it will be more confident to meet again in the development, saving the time of search confirmation, thus saving the development time.

In terms of content, I don’t think there are many places to talk about effective in this e-book or this long article, but there are many places to talk about the idiom of golang, which is what the article saysidiomThis is more like an official golang practice guide. In this paper, almost every important syntax of golang is explained in depth, and code examples that are very easy to understand are given, and these examples are very good. Here are some things that I think are important.

  • Notes on the use of colon and equal sign combination
  • Recommended usage of init function

    Besides initializations that cannot be expressed as declarations, a common use of init functions is to verify or repair correctness of the program state before real execution begins.

  • Method set
    About pointer receiver and value receiver and pointer method and value method

    We pass the address of a ByteSlice because only *ByteSlice satisfies io.Writer. The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers.
    This rule arises because pointer methods can modify the receiver; invoking them on a value would cause the method to receive a copy of the value, so any modifications would be discarded. The language therefore disallows this mistake. There is a handy exception, though. When the value is addressable, the language takes care of the common case of invoking a pointer method on a value by inserting the address operator automatically. In our example, the variable b is addressable, so we can call its Write method with just b.Write. The compiler will rewrite that to (&b).Write for us.

  • Register a handler process for HTTP server
  • Correct use of underline placeholders
    Take advantage of the side effects of the underline placeholder. For example, when you need to use the init function of the package, you can name the package of import as the underline.
  • Combining embedding
    Some recommended usage
  • Concurrent programming
    The common usage of channel, especially the improper use of go func() closure, which is often made by novices, is explained. At the same time, two common ways to control the number of concurrent co programs are given.

    the loop variable is reused for each iteration, so the req variable is shared across all goroutines. That’s not what we want. We need to make sure that req is unique for each goroutine.
    A lock free RPC prototype based on channel
    Channel based simple leaky bucket memory pool?.
    The idiom of panic.

Tip programming skills

No programming skills to talk about this week, crying

Share flash

Recently, I have been insisting on one leetcode every day for more than a month. Up to now, I have brushed more than 150 questions. Although many questions definitely need to see other people’s solutions to know how to do it, the process of brushing questions is much easier than at the beginning. Looking back on my recent experience of writing questions, I found that there was an obvious inflection point between the initial and even easy questions that I couldn’t do, and now I can do a lot of medium and a little hard. About 100 questions have been written. The performance of this turning point is that we can write the correct solution to the conventional problem-solving methods, such as recursion and double pointer. Moreover, for the problem that you can’t think of a solution, you can quickly understand it after reading other people’s solutions and quickly implement it in your own language.

I call this the “entry” state of brushing questions. After the initial painful period, although the number of questions still needs to be increased, the fear of brushing questions has almost disappeared.