日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二叉树的遍历实现-2(三级)

發布時間:2024/4/13 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉树的遍历实现-2(三级) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

package com.learn.btree;/*** 二叉鏈表的節點* @author Leon.Sun**/ public class Node {/*** 節點的值*/// private Object value;Object value;/*** 左孩子* 左子樹的引用* 同樣為了處理方便,我們把private去掉*/// private Node leftChild; Node leftChild;/*** 右子樹的引用*/// private Node rightChild;Node rightChild;public Node() {super();}public Node(Object value) {super();this.value = value;}public Node(Object value, Node leftChild, Node rightChild) {super();this.value = value;this.leftChild = leftChild;this.rightChild = rightChild;}/*** 這個toString該怎么寫呢* 輸出三個屬性的值就可以了*/@Overridepublic String toString() {return "Node [value=" + value + ", leftChild=" + leftChild + ", rightChild=" + rightChild + "]";}} package com.learn.btree;/*** 二叉樹接口* 可以有不同的實現類,每個類可以使用不同的存儲結構,比如順序結構、鏈式結構* 鏈式結構可以是二叉的,也可以是三叉的* @author Leon.Sun**/ public interface BinaryTree {/*** 是否空樹* 你的樹是空的嗎,空是什么意思* 有沒有根節點,有根就不是空的了* @return*/public boolean isEmpty();/*** 樹結點數量* 樹里面有幾個節點* @return*/public int size();/*** 獲取二叉樹的高度* 得到樹的高度* @return*/public int getHeight();/*** 查詢指定值的結點* 在樹里面去找一個值* 我去找20,要告訴我這里沒有20才可以* @param value* @return*/public Node findKey(int value); // 查找/*** 前序遞歸遍歷* 這三個遍歷要采用遞歸來實現*/public void preOrderTraverse(); /*** 中序遍歷遞歸操作*/public void inOrderTraverse(); /*** 后序遍歷遞歸操作*/public void postOrderTraverse();/*** 后序遍歷遞歸操作* 這個是重載,一個有參,一個無參* @param node 樹根結點*/public void postOrderTraverse(Node node); /*** 中序遍歷非遞歸操作* 1)對于任意節點current,若該節點不為空則將該節點壓棧,并將左子樹節點置為current,重復此操作,直到current為空。 * 2)若左子樹為空,棧頂節點出棧,訪問節點后將該節點的右子樹置為current* 3) 重復1、2步操作,直到current為空且棧內節點為空。 */public void inOrderByStack();/*** 前序遍歷非遞歸操作* 1)對于任意節點current,若該節點不為空則訪問該節點后再將節點壓棧,并將左子樹節點置為current,重復此操作,直到current為空。 * 2)若左子樹為空,棧頂節點出棧,將該節點的右子樹置為current * 3) 重復1、2步操作,直到current為空且棧內節點為空。*/public void preOrderByStack(); /*** 后序遍歷非遞歸操作* 1)對于任意節點current,若該節點不為空則訪問該節點后再將節點壓棧,并將左子樹節點置為current,重復此操作,直到current為空。 * 2)若左子樹為空,取棧頂節點的右子樹,如果右子樹為空或右子樹剛訪問過,則訪問該節點,并將preNode置為該節點 * 3) 重復1、2步操作,直到current為空且棧內節點為空。 */public void postOrderByStack(); /*** 按照層次遍歷二叉樹* 這個需要借助隊列來實現,這里還是包含很多技能點的*/public void levelOrderByStack(); } package com.learn.btree;import java.util.Deque; import java.util.LinkedList; import java.util.Queue;/*** 如果以后別人問你二叉樹,二叉樹進行層次遍歷,應該怎么來實現* 能用遞歸嗎,不能用遞歸,怎么辦,不能說借助while循環和for循環* 就是借助隊列,什么個原理啊,先把根放到隊列里面去,* 根出隊,根出隊之前,它會把根的兩個孩子都放到隊列里面去,* 自左向右放,把第一層處理完之后,第二層的節點已經在隊列里面了* 然后再處理第二層的節點,在處理第二層的節點之后已經把第三層的節點從左至右依次加到隊列里面去了* 然后再處理第三層節點了,第三層節點處理之后就把第四層節點放到隊列里面去* 隊列是先進先出,我們是先放左邊的再放右邊的,所以先遍歷左邊的,再遍歷右邊的* 這里面什么時候結束了,隊列是空,隊列是空所有的節點都遍歷完了* 它是按照這個思路來的,這是我們按層次遍歷的* 代碼好好的理解一下,大循環里面就是再來一個小循環,二叉樹的層次遍歷* 下面我們再來看一個中序遍歷* @author Leon.Sun**/ public class LinkedBinaryTree implements BinaryTree {private Node root;// private int size;public LinkedBinaryTree(Node root) {super();this.root = root;}public LinkedBinaryTree() {super();}@Overridepublic boolean isEmpty() {return root==null;}@Overridepublic int size() {System.out.println("二叉樹節點的個數: ");return this.size(root);}private int size(Node root) {if(root==null) { return 0;}else {int nl = this.size(root.leftChild);int nr = this.size(root.rightChild);return nl+nr+1; }}@Overridepublic int getHeight() {System.out.println("二叉樹的高度是: ");return this.getHeight(root);}private int getHeight(Node root) {if(root==null) { return 0;}else {int nl = this.getHeight(root.leftChild);int nr = this.getHeight(root.rightChild);return nl>nr ? nl+1 : nr+1; }}/*** 這里只傳了值,沒有說在哪里找*/@Overridepublic Node findKey(int value) {/*** 那我們在用戶調用的時候顯示的在root里面找* * 最后返回的是Node,如果沒有找到就返回Null* 找到就返回這個節點就可以了,*/return this.findKey(value, root);}/*** 這里要寫成Object* * 我們來讀一下這個代碼什么含義* @param value* @param root* @return*/public Node findKey(Object value,Node root) {/*** 如果root等于空,直接返回null* 如果你這顆樹是空的,那你就返回空了* 這個root是誰,剛開始的時候root是1,* 但是后來最終是作為遞歸調用的一個結束條件的,* 你看下面會一直遞歸調用的* * 這個root剛開始指的是1,整個樹的根* 最終到了左孩子和右孩子的根了* * 這是遞歸結束條件1* */if(root == null){/*** root為null,節點為空* 可能是整棵樹的根節點,* 也可能是遞歸調用中的葉子節點的左孩子和右孩子*/return null;/*** 這是遞歸結束條件2* 有可能是值,也可能是null* 都有可能*/}else if(root != null && root.value == value){/*** 這個根不等于空,根的值等于value,這什么意思啊,* 就是找到了,你不是找7嗎,找到7了,* 你找2,2這個節點不等于空,但是值是不是等于我們要找的2* 找到了怎么辦,找到了就直接返回了* 這個大家記住了,如果不是這兩種情況的話* 那就該遞歸了* * 這是找到了*/return root;}else {/*** 對左子樹進行查找* 所以root一直往下調用,最后root會變成所有葉子節點的* 左孩子和右孩子都是空的,到葉子節點的時候就結束了* * 先在左子樹里面找,再在右子樹里面找* 找到左子樹里面的一個值,再找到右子樹里面的一個值* * 這是遞歸調用*/Node node1 = this.findKey(value, root.leftChild);/*** 對右子樹進行查找*/Node node2 = this.findKey(value, root.rightChild);/*** 如果左子樹不等于空,值等于那返回就可以了* 如果左子樹里面找到了,就返回左子樹里面的*/if(node1 != null && node1.value == value){return node1;}else if(node2 != null && node2.value == value){/*** 如果右子樹里面找到了,那就返回右子樹里面的*/return node2;}else{/*** 如果左子樹和右子樹都沒有找到,那還是返回空吧*/return null;}}} @Overridepublic void preOrderTraverse() {if(root!=null) { System.out.print(root.value + " ");if(root.leftChild!=null) {BinaryTree leftTree = new LinkedBinaryTree(root.leftChild);leftTree.preOrderTraverse();}if(root.rightChild!=null) {BinaryTree rightTree = new LinkedBinaryTree(root.rightChild);rightTree.preOrderTraverse();}}}@Overridepublic void inOrderTraverse() {System.out.println("中序遍歷");this.inOrderTraverse(root);System.out.println();}private void inOrderTraverse(Node root) {if(root!=null) { if(root.leftChild!=null) { this.inOrderTraverse(root.leftChild);}System.out.print(root.value + " ");if(root.rightChild!=null) {this.inOrderTraverse(root.rightChild);}}}@Overridepublic void postOrderTraverse() {System.out.println("后序遍歷");this.postOrderTraverse(root);System.out.println();}@Overridepublic void postOrderTraverse(Node node) {if(node!=null) {if(node.leftChild!=null) {this.postOrderTraverse(node.leftChild);}if(node.rightChild!=null) {this.postOrderTraverse(node.rightChild);}System.out.print(node.value + " "); }}/*** 不采用遞歸可以采用棧,棧是后進的先出* 對于棧我們之前使用過一個例子* 什么例子啊,十進制轉換為二進制數,* 是不是符合后進先出* 現在這個列子與他類似* * 功能已經實現了,但是代碼是什么含義啊* 第一步理解他,第二步實現它就可以了* * */@Overridepublic void inOrderByStack() {System.out.println("中序非遞歸遍歷:");// 創建棧/*** Deque什么意思,Deque這個單詞在JAVA里面是作為棧來使用的* 實際上還是LinkedList,但是它是作為棧來使用的,* 回顧我們的棧和隊列,Deque是雙端隊列,棧操作建議使用他* 一般我們當做棧來用的,但是他的實現類有兩個,一個是找LinkedList* 還有一個采用ArrayDeque,這都是可以的,再復習一下前面的內容* * 我么先看第一條語句是什么,是一個棧,是一個鏈棧,* 為了簡單起見,我們畫一個數組類型的吧,* 棧里面是可以放元素,就這么來放,首先我們把中序的順序寫出來* 中序的順序是什么,我們看順序是怎么一步一步出來的* 我們下邊來寫是不是一致,* 第一步是先創建一個棧,一個鏈棧* 為了簡單起見我們寫成一個數組的樣式* */Deque<Node> stack = new LinkedList<Node>();/*** 我們這里又定義了一個變量* 簡單的就畫到這兒,這個變量就叫current* 因為我們沒有畫棧內存和堆內存* 所以我們就簡單的畫,在這個方法的棧內存里面實現的* root賦給current什么意思,current是不是指向root了* */Node current = root;/*** 如果current不等于空,他指向1* 或者棧不等于空,現在棧是空的* 你看這里是或者,兩個條件只要滿足一個就可以了* 現在滿足吧,現在不等于空啊* 他的循環有兩部分,前面有一個循環,后面是一個判斷* * 又到這里了,current現在是空嗎,不是空* 棧現在是空嗎,也不是空,還有一個1呢* * current已經不指向5了,他指向5的右孩子了* 但是棧里面還不是空的,這里面還有一個1呢,* */while (current != null || !stack.isEmpty()) {/*** 前面的循環條件是誰啊,就是current != null這個條件* * 當current不等于空* * 如果current不等于空,current現在等于空,* current現在是空的,就不循環了* * 循環又回來了,current不等于空,等于2* 如果current不等于空,2不等于空* 是不是我們現在要做這么一個操作,把我們的2放進去* */while (current != null) {/*** 我們是中序遍歷* 什么叫中序,一上來不會遍歷這個根,* 先把根存起來* 棧里面有個1,先存起來* * 把4入棧* * 5已經進來了* * 把我們的2放進去* * 然后把3給放進去,3不等于空再放進去* 這里是3嗎,*/stack.push(current);/*** 然后干什么呢,然后把它的左孩子賦給current* 這什么意思,current就指向4了,* 指向4就回來,回來什么意思,* 4等于空嗎,不等于空* * 再取4的左孩子,4沒有左孩子了,* 如果4這邊還有左孩子,它是想干什么* 把它所有的左孩子一直放進去,一直往里頭放* 目前我們比較簡單,只有這兩級,* 按照我們的中序遍歷,整個的左邊遍歷完之后才能輪到root* 所以我們進棧的順序正好相反,1先進,4后進* 退的時候4要先出來,后進先出的用棧* 先進先出的用隊列,那現在找4的孩子對不起他已經是空了 * 這個循環就結束了,從左邊開始,一直找* 所有的左孩子都進去了* * 5現在有左孩子嗎,現在是空,* 所以這個循環到這里就結束了,只把5放進去* * 然后再找他的左孩子,2的左孩子循環的過程中是不是又指向3了* * 3還有沒有左孩子,3沒有左孩子了,這個循環是不是結束了* 再往下就不講了,大家想一下,2進了棧,3進了棧,* 和1進了棧,4進了棧,是不是一樣的,他都一樣的,* 只不過當時是把1看成根的,現在是把2看成根的* 重復剛才的過程就可以,總體下來是什么樣的* 不管是大樹還是小的二叉樹來說,都是先把左邊的遍歷完,* 再遍歷根,然后再遍歷右邊的,你看我們把451都出來了* 右邊變成一個整體開始處理了,這就是我們講的非遞歸的遍歷* 代碼我們做相關的比較的話,這個代碼有幾行,* 在看看那個代碼有幾行,遞歸的代碼少,然后遞歸的代碼更容易理解* 非遞歸的代碼雙重循環,還有這么多的條件,* 這個要好好理解一下,采用遞歸可以簡化思路,簡化代碼* 但是遞歸調用每次調用都要開辟一份空間,他里面是比較占用空間的* 關于中序非遞歸遍歷就寫到這,那非遞歸的前序和后序遍歷怎么寫呢,* 大家可以自己來想,或者從網上找一些資料* 可以把這一塊給解決一下,提高不只是寫代碼的能力,* 還有讀代碼的能力,還有思想,遇到問題該怎么來解決* 到這兒的話我們再來看,那關于樹和二叉樹的所有內容,就都給大家講了* 二叉樹是我們數據結構的一個重點* */current = current.leftChild;}/*** 后面的條件是誰啊,!stack.isEmpty()這個條件* * 如果這個棧不等于空,棧現在是空的嗎,現在不是空* 怎么辦* * 我們這里可不是循環,是if,就執行一遍* * 如果棧不等于空,怎么辦,誰出棧啊,5出棧* * 如果stack不等于空,現在還有1呢,*/if (!stack.isEmpty()) {/*** 出棧,4出棧了,還是賦給current,* 是不是沒有變,* * 把這個1出棧,1出棧了,* 出棧以后賦給current* current現在又指向這個1了*/current = stack.pop();/*** 輸出一下current的值,值4* * 輸出5,5就這么出來了* * 輸出current的值,他的值是1* 這個時候發現對于我們這個圖來說,左子樹已經遍歷完了* 根也已經遍歷完了,剩下來該右子樹了*/System.out.print(current.value + " ");/*** 然后就是做一件事,因為按照我們的遍歷來說* 左邊的一大串遍歷完和1沒有關系* 這做了一個操作,4已經出去了* 然后輸出一下4的值,current現在指向4的右孩子* 這是誰,是指向5了* * 把current的右孩子賦給他,相當于5是根* 根已經遍歷,是不是要遍歷他的右了* 5已經出來了,但是這里的5沒有右孩子* 沒有的話if就到這兒了,5已經出去了* * 輸出1之后current的rightChild是誰,* 我們再在這里畫一個棧* 這個棧1和5都已經出去了* 現在current指向1,他的右孩子,是2* current指向2,右孩子是2了* */current = current.rightChild;}}System.out.println();}@Overridepublic void preOrderByStack() {}@Overridepublic void postOrderByStack() {}/*** 我們先來看按照層次遍歷* 先明確一下,他沒有遞歸,* Queue是什么來的,Queue是隊列* * 體會一下隊列的作用,我們把這棵樹移過來* 我們畫一下這整個的執行過程,是怎么來執行的* 開始執行了*/@Overridepublic void levelOrderByStack() {/*** 你如果想省事的話在這里加一條語句* 加一條什么語句啊,按照層次遍歷二叉樹*/System.out.println("按照層次遍歷二叉樹");/*** 如果root等于null return什么意思,* 沒有遞歸,如果你的樹是空樹,就結束了,* 如果要是不是空的呢,創建了一個隊列*/if(root == null) return;/*** LinkedList是一個什么隊列,是一個鏈表隊列* 我們在這里畫一個數組,實際上是一個鏈表,你看這時候會發生什么,*/Queue<Node> queue = new LinkedList<Node>() ;/*** 告訴我這條語句是什么,是往隊列里面加了一個節點* root是誰啊,root就是1,先把這個1加進來了* */queue.add(root);/*** 當這個隊列的數量不等于0,現在隊列的長度是1* 不等于空,獲得了這個隊列的長度,長度不就是1嗎* * 再回到這邊來,queue.size等于0嗎* 不等于0,等于幾,等于3,等于3的話怎么辦* queue.size等于0嗎,不等于0等于幾* 等于1的,數量是1* * 現在queue的數量等于0,循環結束* */while(queue.size() != 0){/*** 然后我們回頭看queue.size等于0嗎* 不等于0等于幾,等于2,有兩個* 得到他的數量是幾啊,是2* * 獲得這個值3,* * 數量是1,*/int len = queue.size();/*** 循環了幾次,長度是幾就循環了幾次* 你現在長度是1就循環了一次* 這個for循環就循環一次,因為一開始是1* 除了輸出這個1之外,還把他的孩子放在里面了* 然后這個循環就結束了* * 循環兩次,怎么循環兩次,* 第一次處理4,第二次處理2* i=0的時候我們先處理4,* 第二次循環2* 把第二個遍歷完之后,之后他同時做了一件事* 一件事做完了,把第三層所有的節點都放在里面去了,* 并且是按照從左到右的順序放的* 放到隊列里面去了,那就是先進先出了* * 循環三次* 第一次處理5,第二次處理3,第三次處理6* 怎么處理* * 然后再循環第二次,要處理3了,* * 再循環最后一次,第三次該處理這個6* 這三次已經執行完了* 他把第三層的執行完之后,同時第四層的所有節點已經在隊列里面了* * 循環一次,*/for(int i=0;i <len; i++){/*** queue.poll,poll什么意思,poll出隊* add是入隊,poll是出隊,出隊賦給了一個臨時變量temp* 這邊有一個變量,取個名字叫temp,現在出隊賦給他,本來是1嗎* 相當于什么意思,相當于指向的是1,輸出一下temp的值,* temp的值是1,結束了嗎,沒有,* 現在1已經出去了,在他的長度變成0之前* * poll什么意思,4又出去了* 4出去了賦給temp,相當于我們的temp指向4* 然后輸出temp的值,4,輸出這個4* * 第一步把2poll出去,出棧了* 出棧了賦給一個臨時變量* 那個臨時變量指向了2* 這是一個內容* 輸出他的值,他的值就是2* * 先讓這個5出隊,賦給temp,這個時候temp指向5了* 輸出他的值* * 處理3,3出去了,賦給temp,temp指向3* 輸出一下他的值,他的值是誰啊,3* * 第一條語句出隊,6出隊以后賦給temp了* 指向這個6了,輸出這個值,別忘了輸出這個值6* * 讓這個7出來,然后再來輸出他的值,因為這個時候temp已經指向他了,*/Node temp = queue.poll();System.out.print(temp.value+" ");/*** 如果他的左子樹不為空,1的左子樹為空嗎,不為空,就把他的左孩子放到這兒* * 然后4有左孩子嗎,4有沒有左孩子,沒有,那就別加了* * 然后2有左孩子嗎,有,是3,加進去,左孩子是3加進去* * 5左孩子有嗎,沒有,右孩子有嗎,沒有,那就不加了* * 3的左孩子沒有* * 6左孩子有嗎,沒有* * 然后把他的左孩子入隊,右孩子入隊,是不是都沒有啊* 一次小循環之后就會到大循環*/if(temp.leftChild != null) queue.add(temp.leftChild);/*** 如果他的右孩子不為空,那是2,那就把2放到這兒* 第一層的出去了,把第二層的放到隊列里面去了* 并且是先進先出,這個for循環就循環一次* * 4他有沒有右孩子,有,是5* 在這加個5,這是一個結束了* 接下來我們要for循環,這個循環還沒有結束呢* * 2有沒有右孩子啊,有,6加進去* 這個循環循環兩次,第二次兩個都出了* * 3的右孩子也沒有* * 6右孩子有嗎,有,7*/if(temp.rightChild != null) queue.add(temp.rightChild);}}/*** 缺少一個換行的*/System.out.println();}} package com.learn.btree;/*** 在這個測試類里面我們要干什么,* 這是一個測試類,我們按照這些功能依次來實現* @author Leon.Sun**/ public class Test {public static void main(String[] args) {Node node5 = new Node(5,null,null);Node node4 = new Node(4,null,node5);Node node3 = new Node(3,null,null);Node node7 = new Node(7,null,null);Node node6 = new Node(6,null,node7);// Node node6 = new Node(6,null,null);Node node2 = new Node(2,node3,node6);Node node1 = new Node(1,node4,node2);BinaryTree btree = new LinkedBinaryTree(node1);// BinaryTree btree = new LinkedBinaryTree();System.out.println(btree.isEmpty());/*** 前面我們實現了二叉樹的三種遍歷* 都是采用遞歸來實現的,*/System.out.println("先序遍歷:");btree.preOrderTraverse();System.out.println();// System.out.println("中序遍歷:");btree.inOrderTraverse();btree.postOrderTraverse();/*** 中序遍歷非遞歸* 中序遍歷如果采用非遞歸的遍歷* 需要借助棧* * 我們再實現一個功能,這個非遞歸的我們先等一等吧* 我們先看一下別的* * 還有一個中序遍歷,非遞歸的方式來實現,這個需要借助棧* 這三個我們就不寫代碼了,直接把代碼拿過來運行出結果* 然后我們一起來讀這段代碼* * 中序非遞歸遍歷,里面有輸出語句*/btree.inOrderByStack();/*** 按照層次遍歷,借助隊列* 先把這些層次記住* * 另外還有一個層次遍歷,不能用遞歸借助隊列來實現* * 按照層次遍歷,顯示第一層,然后再是第二層,* 1425367,是不是他,按照層次是這么來的* 先第一層,第二層,第三層,第四層,* 每層從左向右,看結果對不對* 1425367,實現了* */btree.levelOrderByStack();/*** 在二叉樹中查找某個值* * 第一個在二叉樹中查找某個值* 怎么樣查到這個值,我們可以在遍歷的基礎上來實現查找* * 現在在二叉樹中查找某個值,輸出一下唄* 我們要找個值是7,請問咱們的二叉樹有沒有7,* 是有的,二叉樹里面是有7的,是別的也可以,* 我們看能不能夠找到* * 返回的值是7,左孩子是空,右孩子也是空,是葉子節點* 我們來找一下1,1是誰啊,1是根,node1的值是1* 左孩子是4,左孩子還有孩子,右孩子是2,這功能已經實現了* 我們可以debug,看到btree有左孩子,右孩子* 然后值是1,那我們再來看他的左孩子,左孩子沒有左孩子,只有右孩子* 它的值是4,是不是可以看得到,再找他的右孩子呢,* 沒有左孩子也沒有右孩子,他的值是5,我們都是可以這么來看到的,* 要通過eclipse的調試工具來查看相關的一個內容* */System.out.println(btree.findKey(1));/*** 對于二叉樹的高度以及二叉樹的節點數量呢,我們有通過遞歸去實現了* 大家發現遞歸非常的簡單,另外遞歸使用的場合還是比較多的* 這是我們講的一個內容,再往下我們還有三個操作*/System.out.println(btree.getHeight());System.out.println(btree.size());} }

?

總結

以上是生活随笔為你收集整理的二叉树的遍历实现-2(三级)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。