本週學習了第10章樹php
一些術語html
根結點是位於樹頂層的惟一結點
位於樹中較低層的結點是上一層結點的孩子,一個結點只有一個雙親
同一雙親的兩個結點稱爲兄弟
根結點是樹中惟一沒有雙親的結點,沒有任何孩子的結點稱爲葉子,其他爲內部結點
結點的層是從根結點到該結點的路徑長度
樹的高度是指從根到葉子之間最遠路徑的長度java
若是一顆n元樹的全部葉子都位於同一層且每一結點要麼是一片葉子要麼正好有n個孩子,則稱此樹是滿的node
操做 | 說明 |
---|---|
getRoot | 返回指向二叉樹根的引用 |
isEmpty | 斷定該樹是否爲空 |
size | 斷定樹中的元素數目 |
contains | 斷定指定目標是否在該樹中 |
find | 若是找到指定元素,返回指向其的引用 |
toString | 返回樹的字符串表示 |
iteratorInOrder | 爲樹的中序遍歷返回一個迭代器 |
iteratorPreOrder | 爲樹的前序遍歷返回一個迭代器 |
iteratorPostOrder | 爲樹的後序遍歷返回一個迭代器 |
iteratorLevelOrder | 爲樹的層序遍歷返回一個迭代器 |
在全部列舉的操做中 ,不存在往樹中添加元素的操做。在一些樹中也沒有刪除樹元素的操做git
public boolean isOperator(){ return (termType == 1); }
爲何須要判斷termType爲一時就是運算符web
private int termType; private char operator; private int value;
結點存儲只須要一個int變量存儲操做數,一個char變量存儲運算符。多出來的int變量termType說明就不是用於存儲操做數。在這個類中,我發現termType的用處都是用來判斷是否爲操做數的,因此設置這個變量的意義就應該在於事先在設置結點時,就標明這個結點存儲的是什麼東西,若是是運算符就把termType改成1,不是就設爲其餘數,這樣就避免了在判斷時要寫一長串的判斷條件if (operator == "+" || operator == "-" || operator == "*" || operator == "/")
的狀況express
public String printTree() { UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>();//建立了一個存儲BinaryTreeNode類的無序列表 UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>();//建立一個存儲int變量的無序列表 BinaryTreeNode<ExpressionTreeOp> current;//設置指向無序列表的一個臨時變量current String result = ""; int printDepth = this.getHeight();//定義printDepth表示樹的高度 int possibleNodes = (int) Math.pow(2, printDepth + 1);//定義possibleNodes表示可能的樹的結點數量多少,possibleNodes = 2 ^ (printDepth + 1) int countNodes = 0; nodes.addToRear(root);//把根結點添加到無序列表末尾 Integer currentLevel = 0; Integer previousLevel = -1;//設置兩個int變量,爲接下來的換行操做進行判斷 levelList.addToRear(currentLevel);//currentLevel添加到levelList末尾 while (countNodes < possibleNodes) { countNodes = countNodes + 1; current = nodes.removeFirst();//current爲nodes移除的首位 currentLevel = levelList.removeFirst(); if (currentLevel > previousLevel) { result = result + "\n\n";//若是curreLevel大於previousLevel,就進行換行操做 previousLevel = currentLevel; for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) result = result + " ";//換行以後添加空格 } else { for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)); i++) { result = result + " ";//不進行換行操做,代表是某一層中的中間的某一結點,在兩個結點之間添加空格 } } if (current != null) { result = result + (current.getElement()).toString();//將當前樹的根結點加到result串中 nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1);//將前一個根結點的左右孩子都存入nodes的尾部,curreLevel+1存入levelList表示左右孩子是在根結點的下一行 } else { nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; }
我以爲這部分代碼難理解的地方在於爲了輸出時的圖像接近於咱們通常的樹的結構圖而進行的換行操做和添加空格的操做。
判斷某個結點在第幾層時運用了一個levelList的一個列表,以及兩個int變量currentLevel和previousLevel分別賦值爲0和-1,經過currentLevel和previousLevel的關係判斷是否須要換行,例如循環到第二層時,nodes裏有了左右孩子兩個結點,levelList裏首位和第二位此時存儲的都是1,而previousLevel此時爲0,首先循環時currentLevel = levelList.removeFirst
,currentLevel=1>previousLevel=0,因此須要另起一行result = result + "\n\n"
,以後將previousLevel賦爲當前的currentLevel的值previousLevel = currentLevel;
,current此時爲nodes首位即左孩子,加入result字符串,再將左孩子的左右孩子分別加入列表尾,它們對應的levelList裏的值爲currentLevel+1=2,以後將列表頭右孩子賦給current,此時的currLevel=previousLevel=1,因此走else這條路,不須要換行而後進行接下來的操做,若是右孩子爲葉結點,雖然沒有子結點,可是依然會留有存儲空間nodes.addToRear(current.getLeft());
,只不過裏面存放的是null,因此輸出時計算機走到此處會繼續執行,並不斷建立新的存儲空間。因此在外面須要套一層while循環,由於二叉樹前n層有不高於2^(n+1)個元素,因此定義possibleNodes的值爲int possibleNodes = (int) Math.pow(2, printDepth + 1);
另外關於加空格的方法不是太懂,譬如爲什麼要這麼定義j < ((Math.pow(2, (printDepth - currentLevel))) - 1)
在兩個結點之間添加空格。
關於二者的取值好像也不是那麼嚴格,也就是不必定非要取0和-1,換成1和0,-1和-2之類也是能夠的,只不過取值的不一樣會影響樹結構的寬窄,或者二者的差值也不必定須要爲1,差2差3好像都沒有問題,只不事後面levelList.addToRear(currentLevel + 1);
的方法,對應就該加2或者加3了。數組
問題1:運行expressionTree類的printTree方法時,樹的結構沒有所有打印出來,如圖
數據結構
BinaryTreeNode cur = root; int height = 0; if (root != null){ height++; } cur = cur.left; while (cur.judge() != true){ height++; cur = cur.left; } height++; return height;
代碼修改後的運行截圖爲
學習
問題2:使用LinkedBinaryTree的toString方法時最終輸出一串亂碼
問題2解決方案:在網上尋找解決方案,而後瞭解到數組是沒有toString方法的。
Object中的toString()方法,是將傳入的參數的類型名和摘要(字符串的hashcode的十六進制編碼)返回,直接對數組使用了toString()方法,就會獲得 一個Ljava.lang.String;@175d6ab
其中,Ljava.lang.String 是指數據是String類型的
雖然這裏給出的亂碼信息是3ecf72fd,可是他給出的解決方案是使用循環的方法來輸出數組中的每個值,姑且一試
這裏輸出樹的結構須要用到遞歸,而後輸出時有點奇怪的就是我把右孩子放在其雙親的上面,左孩子放在雙親的下面,因此會有些不像樹的形狀
public void oString() { string(root); } private void string(BinaryTreeNode temp){ if(temp != null){ string(temp.getRight()); System.out.println(temp.getElement() + " "); string(temp.getLeft()); } }
輸出結果如圖
湊合也能看
上週沒有錯題哦
基於評分標準,我給譚鑫的博客打分:8分。得分狀況以下:
正確使用Markdown語法(加1分):
模板中的要素齊全(加1分)
教材學習中的問題和解決過程, 三個問題加3分
代碼調試中的問題和解決過程, 三個問題加3分
基於評分標準,我給方藝雯的博客打分:8分。得分狀況以下:、
正確使用Markdown語法(加1分):
模板中的要素齊全(加1分)
教材學習中的問題和解決過程, 兩個問題加2分
代碼調試中的問題和解決過程, 四個問題加4分
本週的學習狀況還算不錯,最困難的地方不在於幾個PP項目,反而在於問題中提到的那個printTree的代碼的理解。不過在考試中發揮得有點糟糕,不知道怎麼的錯了兩道不應錯的題
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 8/8 | |
第二週 | 470/470 | 1/2 | 12/20 | |
第三週 | 685/1155 | 2/4 | 10/30 | |
第四周 | 2499/3654 | 2/6 | 12/42 | |
第六週 | 1218/4872 | 2/8 | 10/52 | |
第七週 | 590/5462 | 1/9 | 12/64 |