决策模式在二叉树打印中的一种应用

前面在回顾设计模式和数据结构时,遇到二叉树不同打印方式需求,于是想着能不能把二叉树的不同遍历方法独立出来,作为多个单独的打印方法来方便使用,然后想到了策略模式,于是有了下面的内容,以作记录和分享。若有不足,还请多多指正。

定义接口

第一个接口:定义策略接口。用于二叉树不同遍历方法的实现,作为不同的策略,例如:前序、中序、后序、层序遍历。

public interface Shower {
    //解决:如果Node节点是在数据结构内部,不对外暴露怎么办?
    void show(NodeInter node);
}

第二个接口:用于解决二叉树中Node是在二叉树中内部定义,不对外暴露的情况。只是这里有个要求就是内部的Node去实现下这个接口。

public interface NodeInter<T, V> {
    NodeInter<T, V> getRight();
    NodeInter<T, V> getLeft();
}

第三个接口:定义一个二叉树打印的接口

public interface STInterf {
    void show(Shower shower);
}

定义使用到的普通的二叉树,如下:

 
public class ST<Key extends Comparable, Value> implements STInterf {
    private Node root;

    private class Node implements NodeInter<Key, Value> {
        private Key key;
        private Value value;
        private Node left, right;

        public Node(Key key, Value value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "key=" + key +
                    ", value=" + value +
                    '}';
        }

        @Override
        public NodeInter<Key, Value> getRight() {
            return right;
        }

        @Override
        public NodeInter<Key, Value> getLeft() {
            return left;
        }
    }

    @Override
    public void show(Shower shower) {
        shower.show(root);
    }

    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    private Node put(Node node, Key key, Value value) {
        if (node == null) return new Node(key, value);

        int cmp = key.compareTo(node.key);
        if (cmp < 0) node.left = put(node.left, key, value);
        else if (cmp > 0) node.right = put(node.right, key, value);
          //存在键,则更新值
        else node.value = value;

        return node;
    }



}

二叉树的遍历

下面是策略接口的具体实现。

前序

public class PreShowerImpl implements Shower {
    @Override
    public void show(NodeInter node) {
        if (null ==node) return;
        System.out.println(node);
        show(node.getLeft());
        show(node.getRight());
    }
}

中序

public class MidShowerImpl implements Shower {
    @Override
    public void show(NodeInter node) {
        if (null ==node) return;
        show(node.getLeft());
        System.out.println(node);
        show(node.getRight());
    }
}

后续

public class AfterShowerImpl implements Shower {
    @Override
    public void show(NodeInter node) {
        if (null ==node) return;
        show(node.getLeft());
        show(node.getRight());
        System.out.println(node);
    }
}

层序

public class LevelShowerImpl implements Shower {
    /**
     * 使用了两个队列
     */
    @Override
    public void show(NodeInter root) {

        if (root == null) return;
        //使用队列
        Queue<NodeInter> queue = new LinkedQueue<>();
        //层队列
        Queue<NodeInter> levelQueue = new LinkedQueue<>();
        //判断是否是同一个节点下的右节点,否则是左节点
        boolean isRight = false;
        //判断是否是在同一个节点先的左右节点中间
        boolean inner = false;
        //根节点入队列
        queue.enqueue(root);
        while (!queue.isEmpty() || !levelQueue.isEmpty()) {
            //打印一层节点,并加他们的下一层节点入队到层队列
            while (!queue.isEmpty()) {
                //节点出队列
                NodeInter tmp = queue.dequeue();

                //辨别节点间的分隔符
                if (tmp == null) {
                    System.out.printf("%s ", isRight ? "], " : "[");
                    isRight = isRight ? false : true;
                    if (isRight) {
                        inner = true;
                    }
                    continue;
                }
                System.out.printf("%s ", tmp);
                //根据是否是同一个节点的左右子树,来将左右子树分开
                if (inner) {
                    //并不能很好区分左右
                    System.out.print("\t");
                    inner = false;
                }

                if (tmp.getLeft() != null || tmp.getRight() != null) {
                    levelQueue.enqueue(null);
                }
                //将左右子节点入队
                if (tmp.getLeft() != null) levelQueue.enqueue(tmp.getLeft());
                if (tmp.getRight() != null) levelQueue.enqueue(tmp.getRight());
                //对于叶节点,不再对其左右子树进行划分
                //在兄弟节点的子节点间,添加分割符,以用于打印分割
                if (tmp.getLeft() != null || tmp.getRight() != null) {
                    levelQueue.enqueue(null);
                }
            }
            System.out.println("\n----------分层------------");
            //将同一层节点放到总队列中,以便出队打印
            while (!levelQueue.isEmpty()) {
                //出栈
                NodeInter pop = levelQueue.dequeue();
                //入队
                queue.enqueue(pop);
            }
        }

    }

}

测试


public class Client {
    ST<Integer, Integer> st = new ST();


    @Before
    public void init() {
        int num = 10;
        Random random = new Random();
        for (int i = 0; i < num; i++) {
            st.put(random.nextInt(20), random.nextInt(100));
        }

    }

    @Test
    public void test() {
        //st.show();
        Shower shower = new PreShowerImpl();
        Shower shower1 = new MidShowerImpl();
        Shower shower2 = new AfterShowerImpl();

        st.show(shower);
        System.out.println("----------分割线------------");
        st.show(shower1);
        System.out.println("----------分割线------------");
        st.show(shower2);

        System.out.println("----------分割线------------");
        st.show(new LevelShowerImpl());

    }
}

结果:

Node{key=18, value=63}
Node{key=7, value=41}
Node{key=2, value=17}
Node{key=0, value=68}
Node{key=6, value=57}
Node{key=3, value=89}
Node{key=8, value=95}
Node{key=12, value=52}
----------分割线------------
Node{key=0, value=68}
Node{key=2, value=17}
Node{key=3, value=89}
Node{key=6, value=57}
Node{key=7, value=41}
Node{key=8, value=95}
Node{key=12, value=52}
Node{key=18, value=63}
----------分割线------------
Node{key=0, value=68}
Node{key=3, value=89}
Node{key=6, value=57}
Node{key=2, value=17}
Node{key=12, value=52}
Node{key=8, value=95}
Node{key=7, value=41}
Node{key=18, value=63}
----------分割线------------
Node{key=18, value=63}
----------分层------------
[ Node{key=7, value=41} ],
----------分层------------
[ Node{key=2, value=17} Node{key=8, value=95} ],
----------分层------------
[ Node{key=0, value=68} Node{key=6, value=57} ], [ Node{key=12, value=52} ],
----------分层------------
[ Node{key=3, value=89} ],
----------分层------------

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值