[BOJ-9934] Complete Binary Tree (Golang)

[BOJ-9934] Complete Binary Tree (Golang)

May 21, 2025

Overview

While preparing for a job change, I had the opportunity to study tree algorithms again after a long time, which led me to write this post.

The Complete Binary Tree Problem is a question where you need to determine and output the structure of a complete binary tree using an array obtained from an in-order traversal. To understand this problem, it is first necessary to grasp the concept of in-order traversal.

In-Order Traversal

The criteria for pre-order, in-order, and post-order traversals are determined by the position of the node.

If we traverse in the order of node -> left subtree -> right subtree, the node comes first, indicating pre-order traversal. Conversely, if we follow left subtree -> node -> right subtree, then the node is in the middle, representing in-order traversal.

Finally, if we traverse in the order of left subtree -> right subtree -> node, the node is last, thus indicating post-order traversal.

The traversal method we will examine is in-order traversal, with examples illustrated in the following image.

image

Complete Binary Tree

A complete binary tree is defined as a binary tree for which the total number of nodes satisfies 2^h - 1 for a given height h of the tree.

A binary tree is one where all nodes have at most 2 children.

In simpler terms, it refers to a tree where all nodes are fully filled up to a specified height.

For example, if the height is 1, the tree simply has one node as shown below:

Number of nodes = 2^1 - 1 = 1

image

If the height is 2, the tree contains 3 nodes as follows:

image

Problem Solving

First, let’s examine the results of the in-order traversal.

The provided tree in the problem looks like this:

image

The example input for the result of the in-order traversal of this tree is [1, 6, 4, 3, 5, 2, 7].

From the array, we can see that it somewhat resembles a tree. By varying the height slightly,

image

patterns begin to emerge.

image

We can confirm that it encapsulates the shape of the tree we intend to build.

Now, let’s convert this into code.

Since the purpose of this problem is to output the nodes according to their heights, we first need to identify the root node.

1. Finding the Root Node

The root node of a complete binary tree can be located very simply. As mentioned earlier, it always has a length of 2^h - 1, and since in-order traversal flattens the tree’s shape, the root node is always positioned at the center.

In the array [1, 6, 4, 3, 5, 2, 7], the element in the center is 3, confirming it is the root node, as observed in the earlier figure.

In code, this can be expressed as follows:

root := arr[len(arr)/2]

2. Finding Child Nodes

Child nodes can be identified by splitting according to the index of the root node, separating them into left and right children.

Let’s again look at the in-order traversal array.

In [1, 6, 4, 3, 5, 2, 7], the children of the root node are 6 and 2.

It is clear that each of those nodes has a difference of 2 indexes from the root node 3.

image

Now, examining the children of those children, 6 and 2 have children 1, 4 and 5, 7, respectively.

Each of them has a difference of 1 index from 6 and 2.

image

Thus, it is evident that as we move further away from the parent, the index differences decrease. However, the rule governing this distance is still unclear, so let’s add some more nodes to investigate.

To make it easier to understand, let’s assume the in-order traversal result consists of consecutive numbers.

image

The root node is in the middle at 8, while its children are 4 and 12.

The index differences here are clearly 4.

image

Now let’s look at the children of 4 and 12: children of 4 are 2, 6, while children of 12 are 10, 14.

Each of these has an index difference of 2.

image

The remaining nodes show that the children of 2 and 6 are 1, 3 and 5, 7, while 10 and 14 are 9, 11 and 13, 15 respectively. Each of these has an index difference of 1.

Thus, it can be concluded that the index differences are determined by the height: with a root at height 1 having a difference of 4, at height 2 the difference is 2, and at height 3 the difference is 1.

To express this in the form of a formula, the index difference for any height h within the total tree height K can be denoted as:

interval = 2^(K - h)

Design

Let’s consolidate points (1) and (2).

First, (a) find the root node, (b) find the children positioned at an interval distance from the root, and (c) using that child node to find the grandchildren at the same interval distance.

Solution

Due to the interconnected nature of the explanations within the code, I’ll replace them with comments within the code itself.

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	writer := bufio.NewWriter(os.Stdout)
	reader := bufio.NewReader(os.Stdin)
	defer writer.Flush()

	// Get the height of the tree
	var K int
	if _, err := fmt.Fscanln(reader, &K); err != nil {
		log.Fatal(err)
	}

	// Calculate tree length based on height, then accept in-order array as input
	length := 1<<K - 1
	inOrder := make([]int, length)
	for i := 0; i < length; i++ {
		if _, err := fmt.Fscan(reader, &inOrder[i]); err != nil {
			log.Fatal(err)
		}
	}

	// Initial index for the root node: total length / 2 is the root
	idxs := []int{length / 2}

	// Process to find child nodes based on height h (the last height has no children, so stored only in idxs)
	for h := 1; h < K; h++ {
		children := make([]int, 0, 1<<(h))
		interval := 1 << (K - h - 1)
		for _, idx := range idxs {
			_, _ = fmt.Fprint(writer, inOrder[idx], " ") // Output child nodes for height h
			children = append(children, idx-interval, idx+interval) // Save child node indices
		}
		idxs = children
		_, _ = fmt.Fprintln(writer)
	}

	// Output child nodes for the last height
	for _, idx := range idxs {
		_, _ = fmt.Fprint(writer, inOrder[idx], " ")
	}
}

Result

image

Conclusion

Thus, we managed to solve the complete binary tree problem. I referenced this method from another person’s solution, where my initial approach was to create a dummy index tree, perform an in-order traversal, and then deduce the original tree using those indices.

However, this method seems more concise and cleaner, so I adopted it.

You can view the Go implementation of the algorithm problem I wrote on YangTaeyoung/algorithm.

Reference