20172303 2018-2019-1《程序設計與數據結構》第6周學習總結

20172303 2018-2019-1《程序設計與數據結構》第6周學習總結

教材學習內容總結

在瞭解了查找和排序後,咱們又從新將目光放回數據結構上,本章咱們將學習一種非線性數據結構——樹。html

1、樹的概述

1.樹的概念

  • 概念:樹是一種由結點和邊組成的,經過結點來存儲元素,邊來鏈接結點構成層次結構的非線性數據結構。
  • 相關術語:
    • :位於樹的頂層的惟一結點,一棵樹只有一個根結點。
    • 雙親和孩子:在樹的某兩層上下結構中,位於較高層的結點是位於較低層結點的雙親,位於較低層的結點是位於較高層結點的孩子。一個結點只有一個雙親,但一個結點能夠有多個孩子。
    • 兄弟:有同一個雙親的多個結點相互爲對方的兄弟。
    • 葉子:沒有孩子的結點稱之爲葉子。葉子不必定所有位於最底層。
    • 內部結點:一顆樹中既不是根結點也不是葉結點的稱爲內部結點。
    • 祖先和子孫:用一個例子來具體說明,根是全部結點的祖先,全部結點都是根的子孫。
    • 高度/深度:一顆樹的層數。
    • 度/階:一棵樹中任一結點所具備的最大孩子數目。

2.樹的分類

  • 按度來劃分
    • n元樹:樹的每一個結點的孩子數不超過n個孩子。
    • 二叉樹:每一個結點最多有兩個結點的數。
  • 按樹是否平衡來劃分
    • 平衡:樹的全部葉子之間相差層數不超過一層的樹稱爲穩定的樹。含有m個元素的平衡n元樹具備的高度爲lognm。
    • 徹底樹:底層葉子都位於樹的左邊的平衡樹稱爲徹底樹。
    • 滿樹:在一顆n元樹中,全部葉子都位於一層,且除葉子外的每一個結點都有n個孩子,則該樹被稱做滿樹。

2、樹的遍歷

  • 樹的遍歷均是從根結點開始的,而後遍歷樹內全部結點,共有四種方法。
    • 前序遍歷:從根結點開始,而後從左孩子開始訪問每一個結點的全部孩子。
    public void preorder(ArrayIterator<T> iter){
        iter.add(element);
    
        if(left != null)
            left.preorder(iter);
    
        if(right != null)
            right.preorder(iter);
    }
    • 中序遍歷:先訪問根結點的左孩子,而後是根結點,最後是根結點的右孩子。
    public void inorder(ArrayIterator<T> iter){
        if(left != null)
            left.inorder(iter);
    
        iter.add(element);
    
        if(right != null)
            right.inorder(iter);
    }
    • 後序遍歷:從左到右遍歷全部孩子,最後訪問根結點。
    public void postorder(ArrayIterator<T> iter){
        if(left != null)
            left.postorder(iter);
    
        if(right != null)
            right.postorder(iter);
    
        iter.add(element);
    }
    • 層序遍歷:從根結點開始,從左至右訪問每一層的全部結點。
    public void levelorder(TreeNode root)
    {
        ArrayDeque<TreeNode> deque=new ArrayDeque<TreeNode>();
        deque.add(root);//根節點入隊
        while(!deque.isEmpty()){
            TreeNode temp=deque.remove();
            System.out.print(temp.val+"--");
            if(temp.left!=null){
                deque.add(temp.left);
            }
            if(temp.right!=null){
                deque.add(temp.right);
            }
        }
    }
  • 經過下圖來看四種遍歷方法的不一樣:
    • 前序遍歷:A、B、D、E、C
    • 中序遍歷:D、B、E、A、C
    • 後序遍歷:D、E、B、C、A
    • 層序遍歷:A、B、C、D、E

3、二叉樹

1.二叉樹相關

  • 二叉樹的基本形態
    • (a)爲空樹
    • (b)爲僅有一個結點的二叉樹
    • (c)爲僅有左子樹而右子樹爲空的二叉樹
    • (d)爲僅有右子樹而左子樹爲空的二叉樹
    • (e)爲既有左子樹又有右子樹的二叉樹。
    • 這裏應特別注意的是,二叉樹的左子樹和右子樹是嚴格區分而且不能隨意顛倒的,(c)與(d)就是兩棵不一樣的二叉樹。
  • 二叉樹的性質(假設二叉樹的根結點位於第1層)
    • (1)二叉樹的第i層最多有2^(i-1)個結點。
    • (2)深度爲k的二叉樹最多有2^k-1個結點。
    • (3)對任何一顆二叉樹,若是其葉子個數爲n0,度爲2的結點數爲n2,則有n0=n2+1。
    • (4)具備n個結點的徹底二叉樹的高度爲[log2n]+1

2.實現樹的策略

  • 數組實現
    • 計算策略:存儲在數組中位置爲n的元素,元素的左子結點存儲在(2n+1)的位置,右子結點存儲在(2*(n+1))的位置。
    • 模擬連接策略:每個元素都是一個結點類,每個結點存儲其孩子的數組索引,而不是孩子指針的對象引用變量。
  • 鏈表實現
    • 設置一個新的TreeNode類,每一結點都將包含一個指針,它指向將要存儲在該結點的元素,以及該結點全部可能孩子的指針。

3.二叉樹的操做

  • 二叉樹ADT
  • 在二叉樹的操做中,並無添加和刪除元素的操做。由於依據二叉樹的用途和結構的不一樣,添加元素和刪除元素的位置也會有所不一樣。除此以外,尤爲是刪除操做,會對二叉樹結構產生很大的影響,刪除的結點爲根、內部結點或葉子時其他剩餘的元素該如何處理是個很大的問題。

4.二叉樹的應用

  • 表達式樹
    • 原理:表達式樹是使用棧來實現的,它實現了將輸入的後綴表達式輸出成樹的形式。每次將操做數壓入棧並建立單結點樹中,遇到操做符時彈出兩個單結點樹(元素爲操做數)構成一顆二叉樹,以後不斷反覆兩種操做(遇到操做數和遇到操做符的兩種操做)直至最後棧中只存儲了一顆完整的表達式樹。
    • 此篇博客中有一個圖文並茂的很是直觀的例子,要比書上的例子好懂得多。
  • 決策樹
    • 原理:決策樹的結點用於表示決策點,其子結點表示在該決策點的可選項,葉結點表示決策的結果。使用決策樹進行決策的過程就是從根結點開始,測試待分類項中相應的特徵屬性,並按照其值選擇輸出分支,直到到達葉子。二叉樹能夠用於實現簡單決策樹(回答只有是和否)

教材學習中的問題和解決過程

  • 問題1:在上一篇博客的問題三中我曾經提問說爲何有些方法要先定義一個私有方法,而後再定義一個公用方法來調用私有方法?
  • 問題1解決方案:當時個人回答是以爲爲了格式一致才設置兩個方法,可是在第十章中我找到了正確答案:當某些方法是以遞歸式編寫的時候,它們一般須要使用一個私有支持方法,由於第一個調用和隨後每一個調用的簽名或行爲多是不一樣的。
  • 問題2:決策樹中提到的is-a關係是什麼關係?
  • 問題2解決方法:is-a(英語:subsumption,包含架構)指的是類的父子繼承關係,例如類D是另外一個類B的子類(類B是類D的父類)。換句話說,一般"D is-a B"(B把D包含在內,或是D被包含在B內)指的是,概念體D物是概念體B物的特殊化,而概念體B物是概念體D物的通常化。舉例來講,水果是蘋果、橘子、芒果與其餘水果的通常化。

代碼調試中的問題和解決過程

  • 問題1:在測試背部疼痛診斷器時,老是拋出錯誤
  • 問題1解決方法:依據拋出的錯誤來看應該是由於數據類型不一樣,可是不論我怎麼修改toString都沒法消除錯誤。後來發現是因爲LinkedBinaryTree中的getLeft()getRight()方法出現了問題,由於按照書上代碼所寫的它本來一直返回的是本來設置的rightleft而不是實際應該返回的根結點的左孩子或右孩子。
public BinaryTreeNode<T> getLeft() 
 {
    return left;
 }

public BinaryTreeNode<T> getRight() 
 {
    return right;
 }
  • getLeft()getRight()做出修改便可實現。

  • 問題2:在完成PP10.3時,不論選擇哪的結點進行判斷輸出的都是true
  • 問題2解決方法:我本來想的是在isLeaf的方法中輸入所要判斷的結點做爲參數,可是後來發現這樣引用的時候會特別醜。
System.out.println(node1.isLeaf(node1));
  • 第一次修改的時候我只是把參數刪掉了,此時的代碼以下:
public boolean isLeaf(){
        if (left == null && right == null){
            return true;
        }
        else {
            return false;
        }
    }
  • 結果輸出結果依然都爲true,緣由是leftright都是開始時設定的結點其內容都爲空,想要引用實際想要判斷的結點的話要加上this
public boolean isLeaf(){
        if (this.left == null && this.right == null){
            return true;
        }
        else {
            return false;
        }
    }
  • 以後就能夠了:

代碼託管

上週考試錯題總結(正確爲綠色,錯誤爲紅色)

  • 本週沒有測試。

結對及互評

點評模板:

  • 博客中值得學習的或問題:
    • 本週的博客相比上週又增長了不少加粗和變紅的標註,能夠看出對所學內容有了比之前更加深入的思考,因此會在博客中突出標記本身在學習過程當中發現的重點。
  • 代碼中值得學習的或問題:
    • 本週代碼中規中矩,沒有什麼突出的優勢或問題。

點評過的同窗博客和代碼

  • 本週結對學習狀況
    • 20172322
    • 結對學習內容
      • 共同討論了課後的PP項目。

其餘(感悟、思考等,可選)

  • 相比於以前本章學習的最大感觸就是代碼不是那麼看得很懂了,以前的幾章代碼都看得很細很透徹,每一步是幹什麼的基本上都清楚,可是本章不知道是因爲代碼數量過多仍是什麼其餘的緣由,時常看着看着就不知道在幹什麼了。可能這就是線性數據結構和非線性數據結構的差別吧。

學習進度條

代碼行數(新增/累積) 博客量(新增/累積) 學習時間(新增/累積) 重要成長
目標 5000行 30篇 400小時
第一週 10/10 1/1 10/10
第二週 246/366 2/3 20/30
第三週 567/903 1/4 10/40
第四周 2346/3294 2/6 20/60
第五週 2346/3294 2/8 30/90
第六週 1343/4637 2/10 20/110
  • 計劃學習時間:30小時
  • 實際學習時間:20小時
  • 改進狀況:因爲各類緣由致使本週的學習時間沒有達到預期標準,因此感受本章學的不是很好,以後要儘快補起來。

參考資料

相關文章
相關標籤/搜索