数据结构:关于重建二叉树的三种思路
前言:
? 前幾天在溫習《編程之美》這本書的時候,看到了二叉樹的重建。正好,也想復習一下數據結構的知識,就來寫了一個小Demo。居然有新發現(本文中的第三種方式)。
? 我們在學習數據結構的時候,肯定可以很輕松地編寫對二叉樹的三種遍歷過程。分別是前序、中序和后序遍歷。
? 這里要說的不是對二叉樹遍歷,而是要通過一些遍歷過程來重建一棵二叉樹。比例,告訴你有一棵二叉樹前序遍歷的結果為:ABC;中序遍歷的結果為:BAC。我們可以很輕松地寫出這棵二叉樹就是以A為根節點、其左孩子是B、右孩子是C。那么從代碼的角度,或者說是從算法的角度又要怎么來編寫程序呢?
?
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
本文作者:Q-WHai
發表日期: 2015年10月24日
本文鏈接:https://qwhai.blog.csdn.net/article/details/49798221
來源:CSDN
更多內容:分類 >> 算法與數學
?
二叉樹的遍歷過程:
圖-1 二叉樹的前序遍歷
圖-2?二叉樹的中序遍歷
圖-3?二叉樹的后序遍歷
?
思路說明:
這里我會采用三種不同的方法來說明其重建過程,代碼部分則是采用其中一種來作詳解。
而具體數據如下:
前序:A B D E H I C F G
中序:D B H E I A F C G
1.遞歸重建
? 在上面的前序序列中,我們可以很容易地獲得A就是根節點。此時,我們可以在后序序列中找到這個A,那么在A的左邊就是A的左孩子及其子節點,在A的右邊就是A的右孩子及其子節點。假設,我們目前在A的左邊。在遍歷前序序列到B的時候,我就知道了B就是A的左孩子,而在B的左邊(中序序列)的都是B的左孩子及其子節點,在B的右邊(同是也在A的左邊)的就是B的右孩子及其子節點...以此類推.這就是利用遞歸來重建二叉樹。
?
2.建立節點集
? 關于這種方法,如果你對B樹有所了解,也就不難理解了。因為后面我會單獨寫一篇關于B樹的文章,這里就暫時一筆代過,說說思路就好了。
? 為子節點建立節點集。在遍歷(前/后序遍歷的序列)的過程中,分裂和修正這個節點集。
?
3.創建索引函數
? 前面的兩種方法,其實可以說是同一種方法,也是比較常見的方法,《編程之美》里使用的正是常見的遞歸調用。下面的這種方法是本文的重點,我在其他地方并沒有見到過類似的方法,于是在此記錄一下思路和過程。我當時也只是靈光一閃,想到還可以用這樣巧妙的方法來實現。真是讓人興奮。下面看看具體實現過程。
? 讓前/后序遍歷的序列擁有中序遍歷序列的索引,在遍歷(前/后序遍歷的序列)的過程中按照二叉排序樹的方法直接插入即可.
?
圖-4 節點索引函數對照表
? 看到這個表,是不是有一種似曾相識的感覺。這個在KMP模式匹配也有一個類似的INDEX函數,在KMP里叫作next.這里我給他取名叫作index吧。因為這個index很直觀,就是取了某一個節點的下標,并保存。
? 其實在已知的遍歷序列中,如果含有中序遍歷結果,那么我們都可以采用上面的這種創建索引函數的方式來簡化重建過程。可能你會問我為什么會這樣?下面請看圖-4.
圖-5?二叉樹的中序遍歷順序示意圖
? 我們可以把圖-2中的中序遍歷二叉樹過程平攤開,就可以獲得圖-5中這樣的一個順序序列。
? 從上面的圖-5中我們可以發現一個現象,那就是某一個節點的左孩子一定是在這個節點的左邊,其右孩子一定是在這個節點的右邊(當然,這個現象也可以從中序遍歷的定義獲得)。也就是節點Node的左孩子Left的值一定是比Node的值小,而Node右孩子Right的值一定是比Node的值大。
? 這樣的一些描述是不是似曾相識呢?沒錯,在二叉排序樹中正是這樣定義的。
? 現在,我們再來看看二叉樹的前序遍歷過程。因為是前序,所以我們在遍歷節點Node的孩子節點之前,必定是已經遍歷過Node的孩子節點。這樣也可以理解成是一種臨近遍歷的過程。
? 這樣看來,前序 + 中序 = 二叉排序樹。于是,我們就有了以下代碼:
?
節點(Node):
?
public class Node {String name;Node leftNode;Node rightNode;int index;public String getName() {return name;}public void setName(String name) {this.name = name;}public Node getLeftNode() {return leftNode;}public void setLeftNode(Node leftNode) {this.leftNode = leftNode;}public Node getRightNode() {return rightNode;}public void setRightNode(Node rightNode) {this.rightNode = rightNode;}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;} }主函數(RestoreBinTree):
public class RestoreBinTree {Node root = null;public static void main(String[] args) {RestoreBinTree m = new RestoreBinTree();String[] F = {"A", "B", "D", "E", "H", "I", "C", "F", "G"};String[] L = {"D", "B", "H", "E", "I", "A", "F", "C", "G"};m.restoreTree(F, L);System.out.println(m.root);}/*** 重建二叉樹* @param labelFirst* @param labelLast*/public void restoreTree(String[] labelFirst, String[] labelLast) {int[] r = recordArray(labelFirst, labelLast);if (root == null) {root = new Node();root.setName(labelFirst[0]);root.setIndex(r[0]);}for (int i = 1; i < labelFirst.length; i++) {Node currentNode = new Node();currentNode.setName(labelFirst[i]);currentNode.setIndex(r[i]);insert(currentNode);}}/*** 向二叉樹中插入一個節點* @param insertNode*/public void insert(Node insertNode) {Node currentNode = root;while (true) {if (insertNode.getIndex() < currentNode.getIndex()) {if (currentNode.getLeftNode() == null) {currentNode.setLeftNode(insertNode);break;} else {currentNode = currentNode.getLeftNode();}} else if (insertNode.getIndex() > currentNode.getIndex()) {if (currentNode.getRightNode() == null) {currentNode.setRightNode(insertNode);break;} else {currentNode = currentNode.getRightNode();}} else {break;}}}/*** 計算索引函數* @param labelFirst* @param labelLast* @return*/public int[] recordArray(String[] labelFirst, String[] labelLast) {if (labelFirst == null || labelFirst.length == 0 || labelLast == null || labelLast.length == 0) {return null;}int[] record = new int[labelFirst.length];for (int i = 0; i < labelFirst.length; i++) {record[i] = index(labelLast, labelFirst[i]);}return record;}/*** 計算索引函數* @param labels* @param label* @return*/private int index(String[] labels, String label) {for (int i = 0; i < labels.length; i++) {if (label.equals(labels[i])) {return i;}}return -1;} }?
REF:
《編程之美》
?
Github
https://github.com/qwhai/simple-tree
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的数据结构:关于重建二叉树的三种思路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java反射机制浅析
- 下一篇: 网络爬虫:基于对象持久化实现爬虫现场快速