跳转至

7 Chapter 7 Solutions

Solution to Challenge 1

A straightforward way to print the nodes in level-order is to leverage the level-order traversal using a Queue data structure. The tricky bit is determining when a newline should occur. For that it would be useful to know the number of elements in the queue. The queues you made in the last chapter don’t have a length property, but you can add one now.

Open your QueueStack implementation and add the following line:

int get length => _leftStack.length + _rightStack.length;

You implemented the double-stack queue using two lists, so finding the length is still an O(1) operation. This would not be true if you used the linked-list implementation.

Now you’re ready to deal with the challenge:

void printEachLevel<T>(TreeNode<T> tree) {
  final result = StringBuffer();
  // 1
  var queue = QueueStack<TreeNode<T>>();
  var nodesLeftInCurrentLevel = 0;
  queue.enqueue(tree);
  // 2
  while (!queue.isEmpty) {
    // 3
    nodesLeftInCurrentLevel = queue.length;
    // 4
    while (nodesLeftInCurrentLevel > 0) {
      final node = queue.dequeue();
      if (node == null) break;
      result.write('${node.value} ');
      for (var element in node.children) {
        queue.enqueue(element);
      }
      nodesLeftInCurrentLevel -= 1;
    }
    // 5
    result.write('\n');
  }
  print(result);
}
  1. You begin by initializing a Queue data structure to facilitate the level-order traversal. You also create nodesLeftInCurrentLevel to keep track of the number of nodes you’ll need to work on before you print a new line.
  2. Your level-order traversal continues until your queue is empty.
  3. Inside the first while loop, you begin by setting nodesLeftInCurrentLevel to the number of current elements in the queue.
  4. Using another while loop, you dequeue the first nodesLeftInCurrentLevel number of elements from the queue. Every element you dequeue is added to result without establishing a new line. You also enqueue all the children of the node.
  5. At this point, you append a newline to result. In the next iteration, nodesLeftInCurrentLevel will be updated with the count of the queue, representing the number of children from the previous iteration.

This algorithm has a time complexity of O(n). Since you initialize the Queue data structure as an intermediary container, this algorithm also uses O(n) space.

Solution to Challenge 2

When building a UI widget tree it’s easier if you can pass the children in as parameters in the constructor. Here is one version of what the nodes could look like:

class Widget {}

class Column extends Widget {
  Column({this.children});
  List<Widget>? children;
}

class Padding extends Widget {
  Padding({this.value = 0.0, this.child});
  double value;
  Widget? child;
}

class Text extends Widget {
  Text([this.value = '']);
  String value;
}

Now you can easily build a Flutter-like widget tree:

final tree = Column(
  children: [
    Padding(
      value: 8.0,
      child: Text('This'),
    ),
    Padding(
      value: 8.0,
      child: Text('is'),
    ),
    Column(
      children: [
        Text('my'),
        Text('widget'),
        Text('tree!'),
      ],
    ),
  ],
);