通過(guò)先序遍歷和中序遍歷后的序列還原二叉樹(shù)(實(shí)現(xiàn)方法)
當(dāng)我們有一個(gè)
先序遍歷序列:1,3,7,9,5,11
中序遍歷序列:9,7,3,1,5,11
我們可以很輕松的用筆寫(xiě)出對(duì)應(yīng)的二叉樹(shù)。但是用代碼又該如何實(shí)現(xiàn)?
下面我們來(lái)簡(jiǎn)單談?wù)劵舅枷搿?/p>
首先,先序遍歷的順序是根據(jù) 根-左孩子-右孩子 的順序遍歷的,那么我們可以率先確認(rèn)的是先序遍歷序列的第一個(gè)數(shù)就是根節(jié)點(diǎn),然后中序遍歷是根據(jù) 左孩子-根-右孩子 的順序遍歷的。我們通過(guò)先序遍歷確認(rèn)了根節(jié)點(diǎn),那么我們只需要在中序遍歷中找到根節(jié)點(diǎn)的位置,然后就可以很好地區(qū)分出,那些屬于左子樹(shù)的節(jié)點(diǎn),那些是屬于右子樹(shù)的節(jié)點(diǎn)了。如下圖:
我們確定數(shù)字1為根節(jié)點(diǎn),然后根據(jù)中序遍歷的遍歷順序確定,中序遍歷序列中數(shù)字1的左邊全部為左子樹(shù)節(jié)點(diǎn),右邊全部為右子樹(shù)。通過(guò)左子樹(shù)節(jié)點(diǎn)的個(gè)數(shù),得出先序遍歷序列中從根節(jié)點(diǎn)往后的連續(xù)3個(gè)數(shù)是屬于左子樹(shù)的,剩下的為右子樹(shù)。這樣再在左右子樹(shù)的序列中重復(fù)以上步驟,最終找到?jīng)]有子節(jié)點(diǎn)為止。
實(shí)現(xiàn)代碼如下:
package com.tree.traverse; import java.util.ArrayList; import java.util.List; /** * @author Caijh * * 2017年6月2日 下午7:21:10 */ public class BuildTreePreOrderInOrder { /** * 1 * / \ * 3 5 * / \ * 7 11 * / * 9 */ public static int treeNode = 0;//記錄先序遍歷節(jié)點(diǎn)的個(gè)數(shù) private List<Node> nodeList = new ArrayList<>();//層次遍歷節(jié)點(diǎn)的隊(duì)列 public static void main(String[] args) { BuildTreePreOrderInOrder build = new BuildTreePreOrderInOrder(); int[] preOrder = { 1, 3, 7, 9, 5, 11}; int[] inOrder = { 9, 7, 3, 1, 5, 11}; treeNode = preOrder.length;//初始化二叉樹(shù)的節(jié)點(diǎn)數(shù) Node root = build.buildTreePreOrderInOrder(preOrder, 0, preOrder.length - 1, inOrder, 0, preOrder.length - 1); System.out.print("先序遍歷:"); build.preOrder(root); System.out.print("\n中序遍歷:"); build.inOrder(root); System.out.print("\n原二叉樹(shù):\n"); build.prototypeTree(root); } /** * 分治法 * 通過(guò)先序遍歷結(jié)果和中序遍歷結(jié)果還原二叉樹(shù) * @param preOrder 先序遍歷結(jié)果序列 * @param preOrderBegin 先序遍歷起始位置下標(biāo) * @param preOrderEnd 先序遍歷末尾位置下標(biāo) * @param inOrder 中序遍歷結(jié)果序列 * @param inOrderBegin 中序遍歷起始位置下標(biāo) * @param inOrderEnd 中序遍歷末尾位置下標(biāo) * @return */ public Node buildTreePreOrderInOrder(int[] preOrder, int preOrderBegin, int preOrderEnd, int[] inOrder, int inOrderBegin, int inOrderEnd) { if (preOrderBegin > preOrderEnd || inOrderBegin > inOrderEnd) { return null; } int rootData = preOrder[preOrderBegin];//先序遍歷的第一個(gè)字符為當(dāng)前序列根節(jié)點(diǎn) Node head = new Node(rootData); int divider = findIndexInArray(inOrder, rootData, inOrderBegin, inOrderEnd);//找打中序遍歷結(jié)果集中根節(jié)點(diǎn)的位置 int offSet = divider - inOrderBegin - 1;//計(jì)算左子樹(shù)共有幾個(gè)節(jié)點(diǎn),節(jié)點(diǎn)數(shù)減一,為數(shù)組偏移量 Node left = buildTreePreOrderInOrder(preOrder, preOrderBegin + 1, preOrderBegin + 1 + offSet, inOrder, inOrderBegin,inOrderBegin + offSet); Node right = buildTreePreOrderInOrder(preOrder, preOrderBegin + offSet + 2, preOrderEnd, inOrder, divider + 1, inOrderEnd); head.left = left; head.right = right; return head; } /** * 通過(guò)先序遍歷找到的rootData根節(jié)點(diǎn),在中序遍歷結(jié)果中區(qū)分出:中左子樹(shù)和右子樹(shù) * @param inOrder 中序遍歷的結(jié)果數(shù)組 * @param rootData 根節(jié)點(diǎn)位置 * @param begin 中序遍歷結(jié)果數(shù)組起始位置下標(biāo) * @param end 中序遍歷結(jié)果數(shù)組末尾位置下標(biāo) * @return return中序遍歷結(jié)果數(shù)組中根節(jié)點(diǎn)的位置 */ public int findIndexInArray(int[] inOrder, int rootData, int begin, int end) { for (int i = begin; i <= end; i++) { if (inOrder[i] == rootData) return i; } return -1; } /** * 二叉樹(shù)先序遍歷結(jié)果 * @param n */ public void preOrder(Node n) { if (n != null) { System.out.print(n.val + ","); preOrder(n.left); preOrder(n.right); } } /** * 二叉樹(shù)中序遍歷結(jié)果 * @param n */ public void inOrder(Node n) { if (n != null) { inOrder(n.left); System.out.print(n.val + ","); inOrder(n.right); } } /** * 還原后的二叉樹(shù) * 二叉數(shù)層次遍歷 * 基本思想: * 1.因?yàn)橥茖?dǎo)出來(lái)的二叉樹(shù)是保存在Node類(lèi)對(duì)象的子對(duì)象里面的,(類(lèi)似于c語(yǔ)言的結(jié)構(gòu)體)如果通過(guò)遞歸實(shí)現(xiàn)層次遍歷的話(huà),不容易實(shí)現(xiàn) * 2.這里采用List隊(duì)列逐層保存Node對(duì)象節(jié)點(diǎn)的方式實(shí)現(xiàn)對(duì)二叉樹(shù)的層次遍歷輸出 * 3.如果父節(jié)點(diǎn)的位置為i,那么子節(jié)點(diǎn)的位置為,2i 和 2i+1;依據(jù)這個(gè)規(guī)律逐層遍歷,通過(guò)保存的父節(jié)點(diǎn),找到子節(jié)點(diǎn)。并保存,不斷向下遍歷保存。 * @param tree */ public void prototypeTree(Node tree){ //用list存儲(chǔ)層次遍歷的節(jié)點(diǎn) if(tree !=null){ if(tree!=null) nodeList.add(tree); nodeList.add(tree.left); nodeList.add(tree.right); int count=3; //從第三層開(kāi)始 for(int i=3;count<treeNode;i++){ //第i層第一個(gè)子節(jié)點(diǎn)的父節(jié)點(diǎn)的位置下標(biāo) int index = (int) Math.pow(2, i-1-1)-1; /** * 二叉樹(shù)的每一層節(jié)點(diǎn)數(shù)遍歷 * 因?yàn)榈趇層的最大節(jié)點(diǎn)數(shù)為2的i-1次方個(gè), */ for(int j=1;j<=Math.pow(2, i-1);){ //計(jì)算有效的節(jié)點(diǎn)的個(gè)數(shù),和遍歷序列的總數(shù)做比較,作為判斷循環(huán)結(jié)束的標(biāo)志 if(nodeList.get(index).left!=null) count++; if(nodeList.get(index).right!=null) count++; nodeList.add(nodeList.get(index).left); nodeList.add(nodeList.get(index).right); index++; if(count>=treeNode)//當(dāng)所有有效節(jié)點(diǎn)都遍歷到了就結(jié)束遍歷 break; j+=2;//每次存儲(chǔ)兩個(gè)子節(jié)點(diǎn),所以每次加2 } } int flag=0,floor=1; for(Node node:nodeList){ if(node!=null) System.out.print(node.val+" "); else System.out.print("# ");//#號(hào)表示空節(jié)點(diǎn) flag++; /** * 逐層遍歷輸出二叉樹(shù) * */ if(flag>=Math.pow(2, floor-1)){ flag=0; floor++; System.out.println(); } } } } /** * 內(nèi)部類(lèi) * 1.每個(gè)Node類(lèi)對(duì)象為一個(gè)節(jié)點(diǎn), * 2.每個(gè)節(jié)點(diǎn)包含根節(jié)點(diǎn),左子節(jié)點(diǎn)和右子節(jié)點(diǎn) */ class Node { Node left; Node right; int val; public Node(int val) { this.val = val; } } }
運(yùn)行結(jié)果:
最后逐層輸出二叉樹(shù)的基本思想:
* 1.因?yàn)橥茖?dǎo)出來(lái)的二叉樹(shù)是保存在Node類(lèi)對(duì)象的子對(duì)象里面的,(類(lèi)似于c語(yǔ)言的結(jié)構(gòu)體)如果通過(guò)遞歸實(shí)現(xiàn)層次遍歷的話(huà),不容易實(shí)現(xiàn)
* 2.這里采用List隊(duì)列逐層保存Node對(duì)象節(jié)點(diǎn)的方式實(shí)現(xiàn)對(duì)二叉樹(shù)的層次遍歷輸出
* 3.如果父節(jié)點(diǎn)的位置為i,那么子節(jié)點(diǎn)的位置為,2i 和 2i+1;依據(jù)這個(gè)規(guī)律逐層遍歷,通過(guò)保存的父節(jié)點(diǎn),找到子節(jié)點(diǎn)。并保存,不斷向下遍歷保存。
以上這篇通過(guò)先序遍歷和中序遍歷后的序列還原二叉樹(shù)(實(shí)現(xiàn)方法)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持我們。
上一篇:C++ 數(shù)據(jù)結(jié)構(gòu)完全二叉樹(shù)的判斷
欄 目:C語(yǔ)言
下一篇:C++ 數(shù)據(jù)結(jié)構(gòu) 堆排序的實(shí)現(xiàn)
本文標(biāo)題:通過(guò)先序遍歷和中序遍歷后的序列還原二叉樹(shù)(實(shí)現(xiàn)方法)
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/1481.html
您可能感興趣的文章
- 01-10深入理解二叉樹(shù)的非遞歸遍歷
- 01-10深入遍歷二叉樹(shù)的各種操作詳解(非遞歸遍歷)
- 01-10判斷整數(shù)序列是否為二元查找樹(shù)的后序遍歷結(jié)果的解決方法
- 01-10探討:C++實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)(用非遞歸方式先序,中序,后序遍歷二叉樹(shù)
- 01-10深入linux下遍歷目錄樹(shù)的方法總結(jié)分析
- 01-10深入探討:linux中遍歷文件夾下的所有文件
- 01-10先序遍歷二叉樹(shù)的遞歸實(shí)現(xiàn)與非遞歸實(shí)現(xiàn)深入解析
- 01-10c++ builder TreeView控件節(jié)點(diǎn)遍歷代碼
- 01-10如何通過(guò)函數(shù)指針調(diào)用函數(shù)(實(shí)現(xiàn)代碼)
- 01-10怎么通過(guò)C語(yǔ)言自動(dòng)生成MAC地址


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改