位於樹中較低層的結點是上一層的孩子html
同一雙親的兩個節點稱爲兄弟node
沒有任何孩子的結點稱爲葉子git
一個至少含有一個孩子的非根結點稱爲一個內部結點數組
根是樹中全部結點的祖先,沿着某一特定結點的路徑可到達的結點是該結點的子孫。函數
結點的層就是從根節點到該結點的路徑長度。從根到該結點 的邊數目就是其路徑長度。
學習
樹的高度是指從根到葉子之間最遠路徑的長度。測試
樹中任一結點能夠具備的最大孩子數目爲該樹的度。this
對結點所含有的孩子數目無限制的樹稱爲廣義樹。lua
每一個節點限制爲不超過n個孩子的樹稱爲一棵n元樹。.net
節點最多含有兩個孩子的樹稱爲二叉樹。
樹的全部葉子都位於同一層或相差不超過兩層,就稱該樹是平衡的。
若是樹是平衡的且底層全部葉子都位於樹的左邊,則認爲該樹是徹底的。(即滿二叉樹去掉最下層右邊的若干個結點)。
若是一個n元樹的全部葉子都位於同一層且每一結點要麼是一片葉子要麼正好具備n個孩子,則稱該樹是滿的。(滿二叉樹是特殊的徹底二叉樹)。
具備n個結點的徹底二叉樹的高度爲(log2n)+1。
表達式樹的根及其內部結點包含着操做,且全部葉子也包含着操做數。對錶達式樹的求值是從下往上的。
Postfix類和PostfixEvaluator類的理解圖示更清楚,對於操做數,創建一個新的ExpressionTreeObj,構造一個ExoressionTree壓入棧中,遇到操做符,彈出棧頂的兩個ExpressionTrees,使用該操做符創建一個新的ExpressionTree壓入棧中。而且須要注意的是,該表達式樹棧的棧頂位於右邊。
Postfix類的UML描述
問題一解決:因爲findAgain方法使用了遞歸,他就須要使用一個私有支持方法,由於第一個調用和隨後每一個調用的簽名和行爲多是不相同的。那就是說,若是沒有findAgain方法中的遞歸部分,那麼find方法就只能用來查找根結點,若是要查找內部結點的話,就須要使用遞歸部分,單純用find方法須要很複雜的程序實現。
問題二解答:首先上網查找了一下部分代碼但願能找到解釋,而後就找到了侯澤洋同窗的博客...裏面有一樣的問題。而後他給我講解了一下具體思路。我把個人理解在代碼中進行了註釋。
public String printTree() { UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>(); UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>(); BinaryTreeNode<ExpressionTreeOp> current; String result = ""; int printDepth = this.getHeight();//樹的高度 int possibleNodes = (int) Math.pow(2, printDepth + 1);//因爲根節點位置是0,最下層是第printDepth+1層,這個二叉樹可能的總結點數就是2的printDepth+1次方 int countNodes = 0;//結點數目 nodes.addToRear(root);//在無序列表中添加根部結點 Integer currentLevel = 0;//當前層 Integer previousLevel = -1;//前一層 levelList.addToRear(currentLevel);//把當前層添加到層數鏈表中 while (countNodes < possibleNodes) {//此樹不滿時 countNodes = countNodes + 1;//從0開始加 current = nodes.removeFirst();//把第一個數取出來 currentLevel = levelList.removeFirst();//設置成當前層數 if (currentLevel > previousLevel) {//若是不在同一層就換行 result = result + "\n\n";//進行換行 previousLevel = currentLevel;//層數下移 for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) result = result + " ";//每一層加空格,第n層有2^(n-1)個數 } else {//若是在同一行,每兩個數之間加空格 for (int i = 0; i < (Math.pow(2, (printDepth - currentLevel + 1)) - 1); i++) { result = result + " "; } } if (current != null) {//若是當前結點不爲空,記錄他的左右孩子,並增長層數 result = result + (current.getElement()).toString(); nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1); } else {//若是當前結點爲空,給他分配空間,存一個null進去 nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; }
問題一:實例化LinkedBinaryTree時,若是使用構造函數
public LinkedBinaryTree(T element, LinkedBinaryTree<T> left, LinkedBinaryTree<T> right) { root = new BinaryTreeNode<T>(element); root.setLeft(left.root); root.setRight(right.root); }
當某個參數爲空時,如圖,就不能運行,產生空指針的錯誤提示。
問題一解決:我開始的時候認爲參數有null能夠是一個空位,但運行出現空指針錯誤,而後把參數改成肯定的數後就不出錯了...實際上是一個很低級的錯誤,參數爲空的話就沒有指針了,固然不能運行(▼ヘ▼#)
問題二:當樹中沒有要查找的結點時,因爲個人contain方法中使用到了find方法,當找不到時,就拋出異常,程序終止了。
public boolean contains(T targetment) { if(find(targetment) != null) return true; return false; }
如圖
問題二解決:首先想到把find方法中的
if (current == null) throw new ElementNotFoundException("LinkedBinaryTree");
改成
if (current == null) return null;
這樣正好符合contains方法的需求,可是有一點小問題就是更改了find方法後,若是單純的使用find方法去查找一個不存在的數,那麼獲得的是一個null,程序並不會終止,但我感受問題不大,嘿嘿。
問題三解決:首先想到在表達樹的代碼中有printTree方法,原理應該是如出一轍的,可是不能直接拿來用,由於它在打印表達樹時,UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>();
BinaryTreeNode<ExpressionTreeOp> current;
參數均爲ExpressionTreeOp,而其中既有操做數又有操做符,而在二叉樹的打印中只有數字結點,且有如圖衝突
因此只須要把他改成泛型便可打印任意樹。
UnorderedListADT<BinaryTreeNode<T>> nodes = new ArrayUnorderedList<BinaryTreeNode<T>>();
BinaryTreeNode<T> current;
問題四:在作哈希表的實驗時,鏈表出現錯誤
問題四解決:首先在每次插入鏈表後進行輸出,找到了錯誤的地方
如圖可見,當出現衝突的時候,會丟失本來在那個位置的數,因此就是insert方法中處理衝突的代碼有錯,檢查代碼後發現
public void insert(LinkHash link) { int data = link.getData(); LinkHash previous = null; LinkHash current = first; while(current!=null&&data>current.getData()) previous = current; current = current.next; count++; alltime++; } if (previous == null) { first = link; alltime++; } else { previous.next = link; link.next = current; //count++; alltime++; } }
while循環的條件while(current!=null&&data>current.getData())
是錯誤的,有衝突的那個位置造成的鏈表是按前後順序排的,並不須要從小到大,因此說當1進去時,他比11小,因此直接執行else操做,就丟失原來的11了。應把條件改成while (current != null)
便可。
沒有錯題
這周對於樹的學習屬於撥雲見日吧。想起來剛開始學Java的時候,我就在博客中寫過,單純的看書看完後容易一臉懵逼,這時候就選擇直接分析代碼,如今我又回到了當時的狀態,剛看完書的時候怎麼也理解不了一些方法,後來直接作pp,嘗試摸索一下就理解不少知識點。哎,Java這東西不能太較真,隨他去吧。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | |
---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 |
第一週 | 0/0 | 1/1 | 8/8 |
第二週 | 1163/1163 | 1/2 | 15/23 |
第三週 | 774/1937 | 1/3 | 12/50 |
第四周 | 3596/5569 | 2/5 | 12/62 |
第五週 | 3329/8898 | 2/7 | 12/74 |
第六週 | 4541/13439 | 3/10 | 12/86 |