二叉树实战(五) - 折纸问题

【需求】

请把纸条竖着放在桌⼦上,然后从纸条的下边向上⽅对折,压出折痕后再展 开。此时有1条折痕,突起的⽅向指向纸条的背⾯,这条折痕叫做“下”折痕 ;突起的⽅向指向纸条正⾯的折痕叫做“上”折痕。如果每次都从下边向上⽅ 对折,对折N次。

请从上到下计算出所有折痕的⽅向。

给定折的次数n,请返回从上到下的折痕的数组,若为下折痕则对应元素为"down",若为上折痕则为"up".

例如: 
N = 1时,打印:[Down] 
N = 2时,打印:[Down、Down、Up]

【分析】

我们把对折后的纸张翻过来,让粉色朝下,这时第一次对折产生的折痕我们可以看做是根节点,那第二次对折产生的下折痕是该结点的左子节点,第二次对折产生的上折痕是该结点的右子节点,这样我们就可以通过树的数据结构来描述对折后产生的折痕。

这棵树有这样的特点:

  • 根结点为下折痕
  • 每个结点的左子节点为下折痕
  • 每个结点的右子结点为上折痕

【思路】

我们可以使用 层序遍历的思想来生成折痕树使用中序遍历来输出折痕的数组。

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * ‘折纸问题’实现
 */
public class PageFoldingTest {

    public static void main(String[] args) {
        Node<String> tree = create(2);
        printTree(tree);
    }

    // 通过模拟对折N次折纸,产生树
    public static Node<String> create(int N) {

        Node<String> root = null;

        for (int i = 0; i < N; i++) {
            // 1.当前是第一次对折
            if (i == 0) {
                root = new Node<>("down", null, null);
                continue;
            }
            // 2.当前不是第一次对折
            // 定义一个辅助队列,通过层序遍历的思想,找到叶子结点,叶子结点添加子结点。
            Queue<Node> queue = new ConcurrentLinkedQueue<>();
            queue.add(root);

            while (!queue.isEmpty()) {
                // 从队列中弹出一个结点。
                Node tmp = queue.poll();
                // 如果有左子节点,把左子节点放入队列中
                if (tmp.left != null) {
                    queue.add(tmp.left);
                }
                // 如果有右子节点,把右子节点放入队列中
                if (tmp.right != null) {
                    queue.add(tmp.right);
                }
                // 如果同时没有左&右子节点,则证明该结点是叶子结点,只需要对此结点添加左&右子结点即可
                if (tmp.left == null && tmp.right == null) {
                    tmp.left = new Node<String>("down", null, null);
                    tmp.right = new Node<String>("up", null, null);
                }
            }
        }
        return root;
    }

    // 打印树中每个结点到控制台
    public static void printTree(Node<String> root) {
        midErgodic(root);
    }

    private static void midErgodic(Node x) {
        if (x == null) {
            return;
        }
        // 递归遍历x结点的左子树
        if (x.left != null) {
            midErgodic(x.left);
        }
        // 把x结点的key放入到keys中
        System.out.print(x.item + " ");
        // 递归遍历x结点的右子树
        if (x.right != null) {
            midErgodic(x.right);
        }
    }


    // 结点类
    private static class Node<T> {

        public T item;  //存储元素
        public Node left;
        public Node right;

        public Node(T item, Node left, Node right) {
            this.item = item;
            this.left = left;
            this.right = right;
        }
    }
}

 

posted @ 2020-05-03 20:47  灰色飘零  阅读(273)  评论(0)    收藏  举报