2017-2018-1 學習總結目錄: 1 2 3 5 6 7 9 10 11 12
html
- 0. 教材學習內容總結
- 0.1 樹
- 0.2 樹的遍歷
- 0.3 樹的實現策略
- 0.4 二叉樹的實現
- 0.5 決策樹
- 1. 教材學習中的問題和解決過程
- 1.1 樹的高度是否徹底等同於深度
- 1.2 課堂測試葉結點題目
- 2. 代碼調試中的問題和解決過程
- 2.1 沒法調用ArrayIterator類
棧、隊列、鏈表都是線性數據結構,樹是非線性結構(層次結構)。java
非線性結構:(一對多)
除根結點以外的每一個結點有且僅有一個直接前驅。
每一個結點能夠有多個直接後繼。
除根結點以外,其餘結點都存在惟一一條從根結點到該結點的路徑。node
樹:結點 + 邊(有限集合)
【注】結點數爲0,稱爲空樹。git
結點類型:根結點(惟一)、子結點、父結點、兄弟結點(同父)、葉節點(無子結點)、內部結點(非根葉結點)。算法
結點的度:結點的子樹數。
樹的度:結點的最大度數。(如:二叉樹的度爲2)
葉子(葉結點):度爲0。
分支點:非終端結點。
數組
例如:上圖中結點 K
L
F
G
M
I
J
的度爲0,A
D
結點的度爲3,B
E
結點的度爲2,C
H
結點的度爲1,結點 A
B
C
D
E
H
屬於分支點。數據結構
結點的層次:根爲第一層,以此類推。(從根到該結點的路徑上的邊數)
樹的深度:結點的最大層次。
樹的高度:從根到葉結點的最長路徑的長度。
【注】深度不一樣於高度,仍是以上圖爲例,該樹的深度爲4,高度爲3。post
樹的分類:n叉樹(最大子結點數)、通常樹(子結點無限制)、平衡樹(子結點彼此不超出一層)、滿樹、徹底樹。
學習
滿樹:全部葉結點在同一層,每一個非葉結點都正好有n個子結點。
徹底樹:底層全部葉結點位於樹的左側,其他層結點全滿。測試
例如:上圖中a和b是 非滿徹底樹,只有c是 滿徹底樹。
m個元素的平衡的n叉樹的高度爲log\(_n\)m,例如:有n個結點的平衡二叉樹的高度爲log\(_2\)n。(計算時取整加一)
先序遍歷:訪問根後,從左到右遍歷子樹。
中序遍歷:遍歷左子樹,而後訪問根,以後從左到右遍歷餘下子樹。(把樹壓扁)
後序遍歷:從左到右遍歷各子樹,最後訪問根。
層序遍歷:從上到下,從左到右遍歷結點。
public void preorder(ArrayIterator<T> iter){ iter.add(element); if(left != null) left.preorder(iter); if(right != null) right.preorder(iter); }
**中序遍歷:**若二叉樹爲空,則空操做;不然
(1)中序遍歷左子樹;
(2)訪問根結點;
(3)中序遍歷右子樹;
public void inorder(ArrayIterator<T> iter){ if(left != null) left.inorder(iter); iter.add(element); if(right != null) right.inorder(iter); }
**後序遍歷:**若二叉樹爲空,則空操做;不然
(1)後序遍歷左子樹;
(2)後序遍歷右子樹;
(3)訪問根結點;
public void postorder(ArrayIterator<T> iter){ if(left != null) left.postorder(iter); if(right != null) right.postorder(iter); iter.add(element); }
如上圖所示,該樹的不一樣遍歷方式依次遍歷結點的順序以下:
先序遍歷:A
B
D
E
H
I
K
C
F
G
J
中序遍歷:D
B
H
E
K
I
A
F
C
G
J
後序遍歷:D
H
K
I
E
B
F
J
G
C
A
//樹的根結點入隊 //當隊列不空時 { //結點出隊列 //訪問結點 //結點的左子結點入隊 //結點的右子結點入隊 }
public Iterator<T> levelorder() { LinkedQueue<BTNode<T>> queue = new LinkedQueue<>(); ArrayIterator<T> iter = new ArrayIterator<>(); 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; }
這三種遍歷算法的訪問路徑是相同的,只是訪問結點的時機不一樣。
重要結論:中序 + 先序,或 中序 + 後序 均能惟一肯定一棵二叉樹,但 先序 + 後序 卻不必定能惟一肯定一棵二叉樹。已知某棵二叉樹,容易求得它的某種遍歷序列。可是,反過來,若已知某種遍歷序列,是否能夠惟一肯定一棵二叉樹呢?
使用數組表示樹:存儲在數組中位置爲 n 的元素,元素的左子結點存儲在(2n + 1)的位置,右子結點存儲在(2 x(n+1))的位置。
鏈式結點:使用一個單獨的類來定義樹結點。
二叉樹:樹和子樹的結點數最多有兩個。
有序樹:子樹有左右之分。(左右不一樣會形成二叉樹不一樣)
二叉樹的 5 種不一樣形態以下圖:
二叉樹的重要性質:
若二叉樹的根結點位於第1層,則:
性質1:在二叉樹的第 i 層最多有 \(2^{i-1}\) 個結點。(i ≥ 1)
性質2:深度爲 k 的二叉樹最多有 \(2^k\)-1 個結點。(k ≥ 1)
性質3:對任何一棵二叉樹, 若是其葉結點個數爲n\(_0\), 度爲2的結點數爲 n\(_2\), 則有:n\(_0\)=n\(_2\)+1。
特殊的二叉樹:
滿二叉樹:每層 充滿 結點,上文有解釋。
深度爲 k,層數爲 i,根結點在第1層
結點總數\(2^k\)-1
每層結點數\(2^{i-1}\)
徹底二叉樹:滿二叉樹去掉右下方的結點,上文有解釋。
樹中所含的 n 個結點和滿二叉樹中編號爲 1 至 n 的結點一一對應。
徹底二叉樹的性質:
性質1:具備n個結點的徹底二叉樹的高度爲[log\(_2\)n]+1
性質2:若是將一棵有 n 個結點的徹底二叉樹自頂向下,同一層自左向右連續給結點編號1, 2, …, n,則對於任意結點 i (1 ≤ i ≤ n),有:
若i = 1, 則該 i 結點是樹根,它無雙親;
若2i >n , 則編號爲 i 的結點無左孩子, 不然它的左孩子是編號爲 2*i 的結點 ;
若2i +1>n, 則編號爲 i的結點無右孩子,不然其右孩子結點編號爲 2*i+1;
public interface BinaryTree<T> extends Iterable<T> { // Returns the element stored in the root of the tree. public T getRootElement(); // Returns the left subtree of the root. public BinaryTree<T> getLeft(); // Returns the right subtree of the root. public BinaryTree<T> getRight(); // Returns true if the binary tree contains an element that matches the specified element. public boolean contains(T target); // Returns a reference to the element in the tree matching the specified target. public T find(T target); // Returns true if the binary tree contains no elements,and false otherwise. public boolean isEmpty(); // Returns the number of elements in this binary tree. public int size(); // Returns the string representation of the binary tree. public String toString(); // Returns a preorder traversal on the binary tree. public Iterator<T> preorder(); // Returns an inorder traversal on the binary tree. public Iterator<T> inorder(); // Returns a postorder traversal on the binary tree. public Iterator<T> postorder(); // Performs a level-order traversal on the binary tree. public Iterator<T> levelorder(); }
【問題1】:我看了書中第370頁的定義:樹的高度(height;或深度,depth)定義爲樹中從根到葉結點的最長路徑的長度。圖16.2中樹的高度是3,由於從根到葉結點F(或G)的路徑長度爲3。我又看了老師的PPT,PPT中將A定義爲第一層,這樣就形成了該樹的高度不等於深度,而書中的定義方式又說樹的高度或深度,按照書中的意思理解,若是將A定義爲第一層,則樹的高度不等於深度,高度定義與路徑長度有關,而路徑長度爲從根到該結點的路徑上的邊數。深度是指某結點的最大層次數。樹的高度是否徹底等同於深度?
解決方案 :(思考並查找資料)
對於這種問題,我有個人見解:對於沒有將根結點定義爲第0層的樹來講,其高度不等於深度。查找到資料後驗證個人猜測正確,一種解釋爲:
高度的定義爲:從結點 x 向下到某個葉結點最長簡單路徑中邊的條數。
【注意】對因而否是邊的條數這個不清楚,待我後來查證,這個主要是因爲其初值是1仍是0來肯定的,通常都是以1開始。
除此以外,我還得出了其餘結論:
對於樹中相同深度的每一個結點來講,它們的高度不必定相同,這取決於每一個結點下面的葉結點的深度。
另外一種解釋爲:
引自考研大綱解析38頁:樹的深度是從根節點開始(其深度爲1)自頂向下逐層累加的,而高度是從葉節點開始(其高度爲1)自底向上逐層累加的。雖然樹的深度和高度同樣,可是具體到樹的某個結點,其深度和高度是不同的。個人理解是:非根非葉結點的深度是從根節點數到它的,高度是從葉節點數到它的。
這兩種解釋異曲同工,樹的高度只有在根結點被定義爲第0層時其高度纔等同於深度。
【問題2】:課堂測試中的第一題:
有100個結點的徹底二叉樹,其高度是多少?葉結點數是多少?
第二問爲何答案是50個葉結點?
解決方案 :(閱讀課本)
我將課本和課件過了一遍,對於這樣一個徹底二叉樹,首先其高度爲[log$_2$100] + 1 = 7,將根結點定義爲第一層,則在第六層一共有32個結點,前六層一共有63個結點,因此第七層有100 - 63 - 1 = 37個葉結點,因此上一層左側必定會有19個內部結點,因此第六層就會有 32 - 19 = 13 個葉結點,因此一共有 37 + 13 = 50個葉結點。以前答錯是由於沒有動手大體畫一遍,只是空想公式,理論又不紮實,錯誤率就會很高。
【問題】:教材中的BTNode
類和LinkedBinaryTree
中的一些代碼涉及到ArrayIterator
類,沒法調用該類,在API,源碼中查找也沒有該類。
解決方案 :(思考)
對於這個問題,我認爲在查找不到的狀況下有兩種方案解決此問題:
1、本身寫這個類,實現其調用的方法;
2、修改或者替換這個類。
我採用了第二種方法,經過查找一些資料,我瞭解到ArrayIterator
類各不相同,確實是須要本身定義的,可是又以爲有些麻煩(懈怠了),因此打算替換此類,看到以後調用的add()
方法,又看到原類的迭代對象是數組,因此我馬上想到了ArrayList
類,正好該類又實現了Iterable
接口。個人嘗試暫時沒有問題,只是還缺乏一些測試來驗證。
後來婁老師在上課時給出了自定義的ArrayIterator類,這個類繼承了ArrayList類並實現了Iterator接口,加入後即可正常編譯。
【錯題1】When one type of object contains a link to another object of the same type, the object is sometimes called __________ .
A .circular
B .recursive
C .self-referential
D .a stack
E .a queue
錯誤緣由:書看得不細緻,只憑本身的理解選了A。
加深理解:自指示關係的對象指的是同一類型的另外一個對象。自指示關係組成了鏈表的基礎,所謂鏈表就是一個鏈式結構,一個對象指向下一個對象,創建了表中對象之間的線性關係。
【錯題2】It is possible to implement a stack and a queue in such a way that all operations take a constant amount of time.
A .true
B .false
錯誤緣由:考慮到每一個操做的時間複雜度都是O(1),所以須要很短的時間,錯選B。
加深理解:一個理想的堆棧或者一個理想的隊列實現的全部操做都須要大量持續時間。
本週莫禮鍾狀態有些下滑,不過仍是抽出必定時間實現了使用鏈表實現隊列的代碼,掌握狀況良好,除此以外還將課本上的十六章基礎內容過了一遍,可是代碼學習內容較少。本週也因爲個人我的緣由致使與莫禮鐘的學習交流較少。在團隊任務方面,莫禮鍾在例會上主動承擔採訪有經驗的學長或者老師這一項任務,雖然完成質量有待提升,可是對於團隊的積極性值得表揚。
本週個人狀態良好,比上週的效率高一些,本週咱們學習了樹結構,可是樹的遍歷方法仍然須要思考,包括上課時給出的一些重要結論和公式,這些都須要本身下去驗證和熟悉。樹結構在生活中的例子仍是不少的,並且還有些激發我對咱們團隊遊戲選取的興趣。
本週的團隊例會依然繼續進行着,組建團隊以後,我發現本身須要改進的地方還有不少,不只僅是技術方面,在管理方面、計劃方面都須要仔細考慮,通知類的消息仍是落實到面對面交談效果比較好,固然整體來講咱們團隊從一開始就很是出色,我以爲咱們組只是按要求完成了老師的基礎任務,並無每項都作到完美,可是有時也可以獲得老師的表揚,這多是咱們學院學風的根源問題吧。下週,我依然會和組長一塊兒帶領團隊繼續前進。
【附1】教材及考試題中涉及到的英語:
Chinese | English | Chinese | English |
---|---|---|---|
邊 | edge | 自指示 | self-referential |
兄弟結點 | sibling | 祖先 | ancestor |
內部結點 | internal node | 先序遍歷 | preorder traversal |
子樹 | subtree | 中序遍歷 | inorder traversal |
後繼 | descendant | 後序遍歷 | postorder traversal |
度 | order | 層序遍歷 | level-order traversal |
遍歷 | traversal | 模擬 | simulation |
【附2】本週小組博客
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 234/234 | 1/28 | 14/14 | 瞭解算法效率、大O符號等理論內容 |
第二週 | 255/489 | 1/29 | 12/26 | 瞭解敏捷的團隊、泛型的使用 |
第三週 | 436/925 | 2/31 | 10/36 | 瞭解一些查找和排序的算法 |
第四周 | 977/1902 | 3/34 | 10/46 | 掌握實現線性結構 |
第五週 | 800/2702 | 2/36 | 12/58 | 掌握實現棧集合 |
第六週 | 260/2962 | 1/37 | 8/64 | 掌握實現隊列集合 |
第七週 | 843/3805 | 4/41 | 12/76 | 掌握實現樹的基本結構 |
計劃學習時間:14小時
實際學習時間:12小時
有效學習時間:5小時
改進狀況:本週效率通常,主要感受在團隊平常管理上花費的時間較多,不過本週代碼進度較好,會繼續保持。