20172310《程序設計與數據結構》(下)實驗二:二叉樹實驗報告


20172310《程序設計與數據結構》(下)實驗二:二叉樹實驗報告

報告封面

  • 課程:《軟件結構與數據結構》
  • 班級: 1723
  • 姓名: 仇夏
  • 學號:20172310
  • 實驗教師:王志強老師
  • 實驗日期:2018年11月7日-2018年11月日
  • 必修選修: 必修

實驗二-1-實現二叉樹

實驗要求內容

參考教材p212,完成鏈樹LinkedBinaryTree的實現(getRight,contains,toString,preorder,postorder)
用JUnit或自己編寫驅動類對自己實現的LinkedBinaryTree進行測試,提交測試代碼運行截圖,要全屏,包含自己的學號信息
課下把代碼推送到代碼托管平台

實驗過程及結果

鏈樹LinkedBinaryTree其實課本上已經有基本的框架代碼了,要自己編寫的就是getRight,contains,toString,preorder,postorder這些代碼。

getRight和getLeft編寫的時候其實時遇到了一些問題,最后換了上述的寫法。

實驗二樹-2-中序先序序列構造二叉樹

實驗要求內容

基於LinkedBinaryTree,實現基於(中序,先序)序列構造唯一一棵二㕚樹的功能,比如給出中序HDIBEMJNAFCKGL和后序ABDHIEJMNCFGKL,構造出附圖中的樹
用JUnit或自己編寫驅動類對自己實現的功能進行測試,提交測試代碼運行截圖,要全屏,包含自己的學號信息
課下把代碼推送到代碼托管平台

實驗過程及結果

(我現在覺得自己的腦子快要氣死了,現在是11月19號,我在寫實驗三的博客時,以實驗二的博客作為模板,結果直接在上面對實驗1和2進行了更改,還沒有發現什么不對,直接保存了,而且還沒有備份。我的人生,一片灰暗,啊啊啊啊啊ε=ε=ε=(#>д<)ノ,只好重寫了一遍,但是當時的有些圖片已經找不到了了,所以接下來的圖是藍墨雲中找回來的)。

  • 先來看中序和后序遍歷構造出一棵樹的思路。

  • 結果:


實驗二 樹-3-決策樹

實驗要求內容

自己設計並實現一顆決策樹
提交測試代碼運行截圖,要全屏,包含自己的學號信息
課下把代碼推送到代碼托管平台

實驗過程及結果

  • 實驗三是仿照背部疼痛診斷器來寫的,只要看懂了背部疼痛診斷器就很好寫

實驗二 樹-4-表達式樹

實驗要求內容

輸入中綴表達式,使用樹將中綴表達式轉換為后綴表達式,並輸出后綴表達式和計算結果(如果沒有用樹,則為0分)
提交測試代碼運行截圖,要全屏,包含自己的學號信息
課下把代碼推送到代碼托管平台

實驗過程及結果

在課本第十章編寫了一個表達式樹的類,其中的思路就是操作數一個棧,操作符一個棧來構造一棵二叉樹。這個實驗的思路就是一樣利用表達式樹的原理,
將輸入的中綴表達式讀取構建一棵二叉樹,想要變成后綴表達式,其實就是將這顆二叉樹后序遍歷輸出

關鍵代碼為:

   ExpressionTree operand1,operand2;
        char operator;
        String tempToken;

        Scanner parser = new Scanner(expression);

        while(parser.hasNext()){
            tempToken = parser.next();
            operator=tempToken.charAt(0);

            if ((operator == '+') || (operator == '-') || (operator=='*') ||
                    (operator == '/')){
                if (ope.empty())
                    ope.push(tempToken);//當儲存符號的棧為空時,直接進棧
                else{
                    String a =ope.peek()+"";
                    if (((a.equals("+"))||(a.equals("-")))&&((operator=='*')||(operator=='/')))
                        ope.push(tempToken);//當得到的符號的優先級大於棧頂元素時,直接進棧
                    else {
                        String s = String.valueOf(ope.pop());
                        char temp = s.charAt(0);
                        operand1 = getOperand(treeExpression);
                        operand2 = getOperand(treeExpression);
                        treeExpression.push(new ExpressionTree
                                (new ExpressionTreeOp(1, temp, 0), operand2, operand1));
                        ope.push(operator);
                    }//當得到的符號的優先級小於棧頂元素或者優先級相同時時,數字棧出來兩個運算數,形成新的樹進棧
                }
            }
            else
                treeExpression.push(new ExpressionTree(new ExpressionTreeOp
                        (2,' ',Integer.parseInt(tempToken)), null, null));
        }
        while(!ope.empty()){
            String a = String.valueOf(ope.pop());
            operator = a.charAt(0);
            operand1 = getOperand(treeExpression);
            operand2 = getOperand(treeExpression);
            treeExpression.push(new ExpressionTree
                    (new ExpressionTreeOp(1, operator, 0), operand2, operand1));
        }
        return treeExpression.peek();
    }

    public String getTree()
    {
        return (treeExpression.peek()).printTree();
    }

    public int getResult(){
        return treeExpression.peek().evaluateTree();
    }
    public String PostOrder(){
        Iterator iterator =  treeExpression.peek().iteratorPostOrder();
        String result="";
        for (;iterator.hasNext();)
            result +=iterator.next()+" ";
        return result;
    }

實驗二 樹-5-二叉查找樹

實驗要求內容

完成PP11.3,對於二叉查找樹的鏈表實現,請實現removeMax、findMin和findMax等操作。
提交測試代碼運行截圖,要全屏,包含自己的學號信息
課下把代碼推送到代碼托管平台

實驗過程及結果

public T removeMin() throws EmptyCollectionException 
    {
        T result = null;

        if (isEmpty())
            throw new EmptyCollectionException("LinkedBinarySearchTree");
        else 
        {
            //如果根元素沒有左孩子,根就是最小的元素,根元素變為原根元素的右孩子
            if (root.left == null) 
            {
                result = root.element;
                root = root.right;
            }
            //如果根有左孩子
            else 
            {
                BinaryTreeNode<T> parent = root;
                BinaryTreeNode<T> current = root.left;
                while (current.left != null) 
                {
                    parent = current;
                    current = current.left;
                }
                result =  current.element;
                parent.left = current.right;
            }

            modCount--;
        }
 
        return result;
    }


    public T removeMax() throws EmptyCollectionException 
    {
        T result = null;

        if (isEmpty())
            throw new EmptyCollectionException("LinkedBinarySearchTree");
        else
        {
            //如果沒有右孩子
            if (root.right == null)
            {
                result = root.element;
                root = root.left;
            }
            //如果有右孩子
            else
            {
                BinaryTreeNode<T> parent = root;
                BinaryTreeNode<T> current = root.right;
                while (current.right != null)
                {
                    parent = current;
                    current = current.right;
                }
                result =  current.element;
                parent.right = current.left;
            }

            modCount--;
        }

        return result;
    }


    public T findMin() throws EmptyCollectionException 
    {
        T result = null;

        if (isEmpty())
            throw new EmptyCollectionException("LinkedBinarySearchTree");
        else
        {
            if (root.left == null)
            {
                result = root.element;
            }
            else
            {
                BinaryTreeNode<T> parent = root;
                BinaryTreeNode<T> current = root.left;
                while (current.left != null)
                {
                    parent = current;
                    current = current.left;
                }
                result =  current.element;
            }

        }

        return result;
    }


    public T findMax() throws EmptyCollectionException 
    {
        T result = null;

        if (isEmpty())
            throw new EmptyCollectionException("LinkedBinarySearchTree");
        else {
            if (root.right == null)
            {
                result = root.element;
            }
            else
            {
                BinaryTreeNode<T> parent = root;
                BinaryTreeNode<T> current = root.right;

                while (current.right != null)
                {
                    parent = current;
                    current = current.right;
                }
                result = current.element;
            }
        }
        return result;
    }

實驗二 樹-6-紅黑樹分析

實驗要求內容

參考http://www.cnblogs.com/rocedu/p/7483915.html對Java中的紅黑樹(TreeMap,HashMap)進行源碼分析,並在實驗報告中體現分析結果。
(C:\Program Files\Java\jdk-11.0.1\lib\src\java.base\java\util)

實驗過程及結果

TreeMap 是一個有序的key-value集合,它是通過紅黑樹實現的。
TreeMap 繼承於AbstractMap,所以它是一個Map,即一個key-value集合。

TreeMap 實現了NavigableMap接口,意味着它支持一系列的導航方法。比如返回有序的key集合。
TreeMap 實現了Cloneable接口,意味着它能被克隆。
TreeMap 實現了java.io.Serializable接口,意味着它支持序列化。
TreeMap基於紅黑樹(Red-Black tree)實現。該映射根據其鍵的自然順序進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。
TreeMap的基本操作 containsKey、get、put 和 remove 的時間復雜度是 log(n) 。
另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。

這是大多數參考資料上給出的關於TreeMap的簡介,但是里面還涉及到了很多的其他的有關概念,所以不太好理解,我也翻看了一些資料,在上面點擊就可以查看。關於代碼的理解可以看一下Java 集合系列12之 TreeMap詳細介紹(源碼解析)和使用示例

HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。
HashMap 繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable接口。

HashMap 的實現不是同步的,這意味着它不是線程安全的。它的key、value都可以為null。此外,HashMap中的映射不是有序的。
HashMap 的實例有兩個參數影響其性能:“初始容量” 和 “加載因子”。容量 是哈希表中桶的數量,初始容量 只是哈希表在創建時的容量。加載因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。
通常,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設置初始容量時應該考慮到映射中所需的條目數及其加載因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以加載因子,則不會發生 rehash 操作。

  • HashMap和TreeMap最本質的區別:

HashMap通過hashcode方法對其內容進行快速查找,而 TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該使用TreeMap,因為HashMap中元素的排列順序是不固定的。

實驗過程中遇到的問題和解決過程

  • 問題一:在實驗二—2中,想要用迭代的方式繼續處理左右子樹,但是估計是參數寫錯了,於是出現了這樣的錯誤。

  • 問題一的解決方案:形參的編寫一定要仔細,不然就很可能得不到正確的結果。肉眼難以找出自己的思路錯誤,於是進行了代碼調試。

  • 問題二:在實驗二 樹-4-表達式樹中寫的方法最開始是對於“/”操作符的放入是有問題的,就像:

所以判斷是下面這段代碼放入操作符的時候出現了問題。

if (((ope.peek().equals("+"))||(ope.peek().equals("-")))&&((operator=='*')||(operator=='/')))
                        ope.push(tempToken);

於是進行調試

  • 問題二的解決方法:其實這個問題我之前一直都沒有想明白,多虧了我機智聰明的隊友,他又對代碼進行了思考和調試,在他的指導下,我才發現錯誤的地方是

其他(感悟、思考等)

這次的實驗有簡單的也有困難的,發現自己有時候的思路真的挺奇葩的。對於第六個那種純看文字學習的實驗我有些轉不動腦子,平常自學其實都用的是紙質課本,可以在上面勾勾畫畫,但看電腦我的思維就很容易跑偏,所以看了好幾遍第六個實驗,看來以后還是要多克服克服這種思維不集中的問題,提高一下學習的效率。還有要感謝一下隊友的幫助,不然問題都還解決不了。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM