2017-2018-1 20162308 实验二 树

实验二 树

实验内容

实验二 实现二叉树

参考教材p375,完成链树LinkedBinaryTree的实现(getRight,contains,toString,preorder,postorder)。用JUnit或自己编写驱动类对自己实现的LinkedBinaryTree进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息。课下把代码推送到代码托管平台

1.png

import java.util.*;

public class MyLinkedBinaryTree<T> implements BinaryTree<T>
{
    protected BTNode<T> root;

    public MyLinkedBinaryTree()
    {
        root = null;
    }

    public MyLinkedBinaryTree (T element)
    {
        root = new BTNode<T>(element);
    }

    public MyLinkedBinaryTree (BTNode rootNode){
        root = rootNode;
    }

    public MyLinkedBinaryTree (T element, MyLinkedBinaryTree<T> left,
                             MyLinkedBinaryTree<T> right)
    {
        root = new BTNode<T>(element);
        root.setLeft(left.root);
        root.setRight(right.root);
    }

    @Override
    public T getRootElement()
    {
        if (root == null){
            return null;
        }
        return root.getElement();
    }

    @Override
    public MyLinkedBinaryTree<T> getLeft()
    {
        if (root == null){
            return null;
        }

        MyLinkedBinaryTree<T> result = new MyLinkedBinaryTree<T>();
        result.root = root.getLeft();

        return result;
    }

    @Override
    public T find (T target)
    {
        BTNode<T> node = null;

        if (root != null){
            node = root.find(target);
        }
        if (node == null){
            return null;
        }
        return node.getElement();
    }

    @Override
    public int size()
    {
        int result = 0;
        if (root != null){
            result = root.count();
        }
        return result;
    }


    @Override
    public Iterator<T> inorder()
    {
        ArrayIterator<T> iter = new ArrayIterator<T>();

        if (root != null){
            root.inorder (iter);
        }
        return iter;
    }

    @Override
    public Iterator<T> levelorder()
    {
        MyLinkedQueue<BTNode<T>> queue = new MyLinkedQueue<BTNode<T>>();
        ArrayIterator<T> iter = new ArrayIterator<T>();

        if (root != null)
        {
            queue.enqueue(root);
            while (!queue.isEmpty())
            {
                BTNode<T> current = queue.dequeue();

                iter.add (current.getElement());

                if (current.getLeft() != null){
                    queue.enqueue(current.getLeft());
                }
                if (current.getRight() != null){
                    queue.enqueue(current.getRight());
                }
            }
        }

        return iter;
    }

    @Override
    public Iterator<T> iterator()
    {
        return inorder();
    }
    @Override
    public MyLinkedBinaryTree<T> getRight() {
        if (root == null){
            return null;
        }

        MyLinkedBinaryTree<T> result = new MyLinkedBinaryTree<T>();
        result.root = root.getRight();

        return result;
    }
    @Override
    public boolean contains (T target) {
        Iterator<T> iter = this.inorder();
        while (iter.hasNext()){
            if (target.equals(iter.next())){
                return true;
            }
        }
        return false;
    }
    @Override
    public boolean isEmpty() {return root==null; }

    @Override
    public String toString() {
        Iterator iter = levelorder();
        return iter.toString();
    }
    @Override
    public Iterator<T> preorder() {
        ArrayIterator<T> iter = new ArrayIterator<>();
        if (root!=null){
            root.preorder(iter);
        }
        return iter;
    }
    @Override
    public Iterator<T> postorder() {
        ArrayIterator<T> iter = new ArrayIterator<>();
        if (root!=null){
            root.postorder(iter);
        }
        return iter;
    }
}

实现了LinkedBinaryTree的getRight,contains,toString,preorder,postorder等方法

实验二 中序先序序列构造二叉树

基于LinkedBinaryTree,实现基于(中序,先序)序列构造唯一一棵二㕚树的功能,比如教材P372,给出HDIBEMJNAFCKGL和ABDHIEJMNCFGKL,构造出附图中的树。用JUnit或自己编写驱动类对自己实现的功能进行测试,提交测试代码运行截图,要全屏,包含自己的学号信息。课下把代码推送到代码托管平台

2.png

import java.util.HashMap;


public class exp2 {
    final static char[] inorder = "HDIBEMJNAFCKGL".toCharArray();
    final static char[] preorder = "ABDHIEJMNCFGKL".toCharArray();
    public static void main(String[] args) {
        MyLinkedBinaryTree<Character> root= new MyLinkedBinaryTree(genetree(preorder,inorder));
        System.out.println(root);
    }
    public static BTNode genetree(char[] pre, char[] in) {
        if (pre == null) return null;
        HashMap<Character, Integer> map = geneMap(in);
        return preIn(pre, 0, pre.length - 1, in, 0, in.length - 1, map);
    }

    public static HashMap<Character,Integer> geneMap(char[] charArray){
        HashMap<Character,Integer> temp = new HashMap<>();
        int len = charArray.length;
        for (int i = 0; i < len;i++){
            temp.put(charArray[i],i);
        }
        return temp;
    }

    public static BTNode preIn(char[] pre, int preindex, int pj, char[] in, int inindex, int nj, HashMap<Character, Integer> position) {

        if (preindex > pj) return null;
        BTNode head = new BTNode(pre[preindex]);
        int index = position.get(pre[preindex]);
        head.left = preIn(pre, preindex + 1, preindex + index - inindex, in, inindex, index - 1, position);
        head.right = preIn(pre, preindex + index - inindex + 1, pj, in, index + 1, nj, position);
        return head;
    }
}

使用递归的方法,从根结点的两边开始构造子树,并如此循环。

实验二 决策树

完成PP16.6。提交测试代码运行截图,要全屏,包含自己的学号信息。课下把代码推送到代码托管平台

2017-10-27.png

import java.util.Scanner;

public class BackPainExpert
{
    private MyLinkedBinaryTree<String> tree;

    //-----------------------------------------------------------------
    //  Sets up the diagnosis question tree.
    //-----------------------------------------------------------------
    public BackPainExpert()
    {
        String e1 = "一共有七种动物(小猫、小狗、小仓鼠、小鸭子、小鱼、小乌龟、大熊猫),\n你想好的动物能游泳吗?";
        String e2 = "你想好的动物萌吗?";
        String e3 = "你想好的动物能在水里生活吗?";
        String e4 = "你想好的动物会中暑吗?";
        String e5 = "你想好的动物灵活吗?";
        String e6 = "你想好的动物能在陆地上生活吗?";
        String e7 = "那一定是小鸭子吧🦆";
        String e8 = "🐼PANDA";
        String e9 = "🐱 喵喵喵~";
        String e10 = "🐶汪汪汪";
        String e11 = "🐭吱吱吱";
        String e12 = "🐬";
        String e13 = "🐢";

        MyLinkedBinaryTree<String> n2, n3, n4, n5, n6, n7, n8, n9,
                n10, n11, n12, n13;

        n8 = new MyLinkedBinaryTree<String>(e8);
        n9 = new MyLinkedBinaryTree<String>(e9);
        n4 = new MyLinkedBinaryTree<String>(e4, n8, n9);

        n10 = new MyLinkedBinaryTree<String>(e10);
        n11 = new MyLinkedBinaryTree<String>(e11);
        n5 = new MyLinkedBinaryTree<String>(e5, n10, n11);

        n12 = new MyLinkedBinaryTree<String>(e12);
        n13 = new MyLinkedBinaryTree<String>(e13);
        n6 = new MyLinkedBinaryTree<String>(e6, n12, n13);

        n7 = new MyLinkedBinaryTree<String>(e7);

        n2 = new MyLinkedBinaryTree<String>(e2, n4, n5);
        n3 = new MyLinkedBinaryTree<String>(e3, n6, n7);

        tree = new MyLinkedBinaryTree<String>(e1, n2, n3);
    }

    //-----------------------------------------------------------------
    //  Follows the diagnosis tree based on user responses.
    //-----------------------------------------------------------------
    public void diagnose()
    {
        Scanner scan = new Scanner(System.in);
        MyLinkedBinaryTree<String> current = tree;

        System.out.println ("So, you're having back pain.");
        while (current.size() > 1)
        {
            System.out.println (current.getRootElement());
            if (scan.nextLine().equalsIgnoreCase("N"))
                current = current.getLeft();
            else
                current = current.getRight();
        }

        System.out.println (current.getRootElement());
    }
}

设计了一个猜小动物的游戏。

实验二 表达式树

完成PP16.8。提交测试代码运行截图,要全屏,包含自己的学号信息。课下把代码推送到代码托管平台。

4.png

import java.util.ArrayList;
import java.util.Stack;


public class ExpressionTree {
    private String exp = "";
    private BTNode root;
    private Integer result;
    public void geneTree(String s) {
        ArrayList<String> oper = new ArrayList();
        ArrayList<BTNode<String>> num = new ArrayList();
        for (int i = 0; i < s.length(); i++) {
            char c = s.toCharArray()[i];
            if (c >= '0' && c <= '9') {
                exp += c + " ";
            } else {
                num.add(new BTNode<String>(exp));
                exp = "";
                oper.add(c + " ");
            }
        }
        num.add(new BTNode(exp));
        while (oper.size() > 0) {
            BTNode left = num.remove(0);
            BTNode right = num.remove(0);
            String o = oper.remove(0);
            BTNode node = new BTNode(o, left, right);
            num.add(0, node);
        }
        root = num.get(0);
    }

    public String toStr() {
        this.s = "";
        inorder(root);
        return s;
    }

    private ArrayList<String> getStringList(String str) {
        ArrayList<String> result = new ArrayList<String>();
        String num = "";
        for (String item : str.split(" ")) result.add(item);
        return result;
    }

    //求逆波兰表达式
    private ArrayList<String> getRPN(ArrayList<String> inOrderList) {
        ArrayList<String> RPN = new ArrayList<String>();
        Stack<String> stack = new Stack<String>();
        for (String item : inOrderList) {
            if (Character.isDigit(item.charAt(0))) RPN.add(item);
            else {
                while (!stack.isEmpty() && compare(stack.peek(), item)) RPN.add(stack.pop());
                stack.push(item);
            }
        }
        while (!stack.isEmpty()) RPN.add(stack.pop());
        return RPN;
    }

    //计算后缀表达式 
    private Integer calculate(ArrayList<String> RPN) {
        Stack stack = new Stack();
        for (String item : RPN) {
            if (Character.isDigit(item.charAt(0))) stack.push(Integer.parseInt(item));
            else {
                Integer back = (Integer) stack.pop();
                Integer front = (Integer) stack.pop();
                Integer res = 0;
                switch (item.charAt(0)) {
                    case '+': {
                        res = front + back;
                        break;
                    }
                    case '-': {
                        res = front - back;
                        break;
                    }
                    case '*': {
                        res = front * back;
                        break;
                    }
                    case '/': {
                        res = front / back;
                        break;
                    }
                }
                stack.push(res);
            }
        }
        return (Integer) stack.pop();
    }

    //比较运算符等级 
    private static boolean compare(String peek, String cur) {
        if ("*".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("/".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("+".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("-".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
            return true;
        }
        return false;
    }
    private ArrayList<String> getStringLst(String str) {
        ArrayList<String> result = new ArrayList<String>();
        String num = "";
        for (String item : str.split(" ")) result.add(item);
        return result;
    }

    public Integer getResult(){
        ArrayList strList = getStringList(toStr());
        ArrayList rpn = getRPN(strList);
        return calculate(rpn);
    }
    private String s;

    public void inorder(BTNode node) {
        if (node.getLeft() != null) {
            inorder(node.getLeft());
        }
        this.s += node.getElement();
        if (node.getRight() != null) {
            inorder(node.getRight());
        }
    }
}
public class ExpressionTreeTest{
    public static void main(String[] args) {
        ExpressionTree et = new ExpressionTree();
        et.geneTree("1+1-5-6");
        System.out.println(et.toStr());
        System.out.println(et.getResult());
    }

}

实验二 二叉搜索树

完成PP17.1。提交测试代码运行截图,要全屏,包含自己的学号信息。课下把代码推送到代码托管平台。


public class LinkedBinarySearchTree<T extends Comparable<T>>
        extends MyLinkedBinaryTree<T> implements BinarySearchTree<T>
{
    //-----------------------------------------------------------------
    //  Creates an empty binary search tree.
    //-----------------------------------------------------------------
    public LinkedBinarySearchTree()
    {
        super();
    }


    public LinkedBinarySearchTree (BSTNode node){
        root = node;
    }

    //-----------------------------------------------------------------
    //  Creates a binary search tree with the specified element at its
    //  root.
    //-----------------------------------------------------------------
    public LinkedBinarySearchTree (T element)
    {
        root = new BSTNode<T>(element);
    }

    //-----------------------------------------------------------------
    //  Adds the specified element to this binary search tree.
    //-----------------------------------------------------------------
    public void add (T item)
    {
        if (root == null)
            root = new BSTNode<T>(item);
        else
            ((BSTNode)root).add(item);
    }

    //-----------------------------------------------------------------
    //  Removes and returns the element matching the specified target
    //  from this binary search tree. Throws an ElementNotFoundException
    //  if the target is not found.
    //-----------------------------------------------------------------
    public T remove (T target)
    {
        BSTNode<T> node = null;

        if (root != null)
            node = ((BSTNode)root).find(target);

        if (node == null)
            return null;

        root = ((BSTNode)root).remove(target);

        return node.getElement();
    }

    //-----------------------------------------------------------------
    //  The following methods are left as programming projects.
    //-----------------------------------------------------------------
    public T findMin() {
        BTNode<T> temp = root;
        while (temp.getLeft()!=null){
            temp = temp.getLeft();
        }
        return temp.getElement();
    }
    public T findMax() {
        BTNode<T> temp = root;
        while (temp.getRight()!=null){
            temp = temp.getRight();
        }
        return temp.getElement();
    }
}

实现了findMin和findMax方法。

实验二 源码分析

参考http://www.cnblogs.com/rocedu/p/7483915.html对Java中的红黑树(TreeMap,HashMap)进行源码分析,并在实验报告中体现分析结果。

Entry<K, V>                ceilingEntry(K key)
K                          ceilingKey(K key)
void                       clear()
Object                     clone()
Comparator<? super K>      comparator()
boolean                    containsKey(Object key)
NavigableSet<K>            descendingKeySet()
NavigableMap<K, V>         descendingMap()
Set<Entry<K, V>>           entrySet()
Entry<K, V>                firstEntry()
K                          firstKey()
Entry<K, V>                floorEntry(K key)
K                          floorKey(K key)
V                          get(Object key)
NavigableMap<K, V>         headMap(K to, boolean inclusive)
SortedMap<K, V>            headMap(K toExclusive)
Entry<K, V>                higherEntry(K key)
K                          higherKey(K key)
boolean                    isEmpty()
Set<K>                     keySet()
Entry<K, V>                lastEntry()
K                          lastKey()
Entry<K, V>                lowerEntry(K key)
K                          lowerKey(K key)
NavigableSet<K>            navigableKeySet()
Entry<K, V>                pollFirstEntry()
Entry<K, V>                pollLastEntry()
V                          put(K key, V value)
V                          remove(Object key)
int                        size()
SortedMap<K, V>            subMap(K fromInclusive, K toExclusive)
NavigableMap<K, V>         subMap(K from, boolean fromInclusive, K to, boolean toInclusive)
NavigableMap<K, V>         tailMap(K from, boolean inclusive)
SortedMap<K, V>            tailMap(K fromInclusive)

以上是TreeMap对外提供的API接口(来自:https://www.cnblogs.com/skywang12345/p/3310928.html),我们先尝试使用TreeMap,并观察其在内存中的存储方式。

TreeMap<Integer, String> tmap = new TreeMap<Integer, String>();
tmap.put(1, "语文");
tmap.put(3, "英语");
tmap.put(2, "数学");
tmap.put(4, "政治");
tmap.put(5, "历史");
tmap.put(6, "地理");
tmap.put(7, "生物");
tmap.put(8, "化学");
for(Entry<Integer, String> entry : tmap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

使用单步跟踪,查看tmap的存储。

2017-10-27 (1).png

阅读上述代码中所用到的put方法。

    public V put(K key, V value) {
        TreeMapEntry<K,V> t = root;
        if (t == null) {//检查当前树中是否存在一个结点
            if (comparator != null) {//如果用户提供了comparator
                if (key == null) {
                    comparator.compare(key, key);//在key为空值时,根据comparator比较key
                }
            } else {
                if (key == null) {
                    throw new NullPointerException("key == null");//如果用户没有提供comparator,且key值为空,则抛出空指针异常
                } else if (!(key instanceof Comparable)) {
                    throw new ClassCastException(
                            "Cannot cast" + key.getClass().getName() + " to Comparable.");
                }//如果用户没有提供comparator,且key对象没有实现Comparable接口,抛出异常
            }

            root = new TreeMapEntry<>(key, value, null);//完成类型检查后,新建根节点
            size = 1;//此时TreeMap的size显然为1
            modCount++;
            return null;
        }
        int cmp;
        TreeMapEntry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
			//如果用户提供了comparator,并从根节点开始,寻找新插入的节点合适的位置,如果这个位置已经有节点,则更新值,否则新建一个节点。
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
			//如果用户没有提供comparator,若key没有实现comparable接口或key为空,则抛出异常,否则,从根节点开始,寻找新插入的节点合适的位置,如果这个位置已经有节点,则更新值,否则新建一个节点。
        }
        TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
		//调整二叉树的平衡性
        size++;
        modCount++;
        return null;
    }

在上述的代码中,我插入了注释,主要的思路就是如果存在old value就更新值,不存在就新建一个节点,最后调整红黑树的平衡性。下面是get方法的源码分析,get方法主要依赖于getEntry方法,因此我对getEntry方法也进行了分析

    final TreeMapEntry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);//这个方法原理上和下面的遍历一样,就是使用了用户提供的comparator对key进行比较
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        TreeMapEntry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }//根据顺序,对数进行遍历
        return null;
    }
public V get(Object key) {
    Entry<K,V> p = getEntry(key);
    return (p==null ? null : p.value);//如果p为空,则返回null,否则返回entry内的value
}
posted @ 2017-10-27 23:38  20162308马平川  阅读(265)  评论(1编辑  收藏  举报