二分搜索樹的深度優先遍歷和廣度優先遍歷

来源:https://www.cnblogs.com/Demrystv/archive/2018/05/15/9043356.html
-Advertisement-
Play Games

二分搜索樹的特點 二分搜索樹首先是一個二叉樹,其次其必須滿足的條件是:每個節點的鍵值必須大於其左子節點,每個節點的鍵值必須小於其右子節點,這樣以左右孩子為根的子樹仍為二分搜索樹,需要註意的是,二分搜索樹不一定是一顆完全二叉樹。 深度優先遍歷 深度優先遍歷的基本思想:對每一個可能的分支路徑深入到不能再 ...


二分搜索樹的特點

  二分搜索樹首先是一個二叉樹,其次其必須滿足的條件是:每個節點的鍵值必須大於其左子節點,每個節點的鍵值必須小於其右子節點,這樣以左右孩子為根的子樹仍為二分搜索樹,需要註意的是,二分搜索樹不一定是一顆完全二叉樹。

 

深度優先遍歷

  深度優先遍歷的基本思想:對每一個可能的分支路徑深入到不能再深入為止,而且每個結點只能訪問一次。深度優先遍歷的非遞歸的通用做法是採用棧。要特別註意的是,二分搜索樹的深度優先遍歷比較特殊,可以細分為前序遍歷、中序遍歷、後序遍歷。

  前序遍歷:先訪問當前節點,再依次遞歸訪問左右子樹 ,訪問到前面節點才繼續   中序遍歷:先遞歸訪問左子樹,再訪問自身,再遞歸訪問右子樹,訪問到中間節點才繼續    後序遍歷:先遞歸訪問左右子樹,再訪問自身節點,訪問到後面節點才繼續   例如,對於下麵的這個二分搜索樹,其前序遍歷結果是:28  16  13  22  30  29  42,其中序遍歷結果是:13  16  22  28  29  30  42,其後序遍歷結果是:13  22  16  29  42  30  28。

 二分搜索樹

 

廣度優先遍歷

  深度優先遍歷的基本思想:從上往下對每一層依次訪問,在每一層中,從左往右(也可以從右往左)訪問結點,訪問完一層就進入下一層,直到沒有結點可以訪問為止。廣度優先遍歷的非遞歸的通用做法是採用隊列。

  例如,對於上面的這個二分搜索樹,其層序遍歷(廣度優先遍歷)結果是:28 16 30 13 22 29 42。

 

Java代碼實現深度優先遍歷和廣度優先遍歷

  下麵採用Java語言來構建這個二分搜索樹,並且實現前序遍歷、中序遍歷、後序遍歷三種不同方式的深度優先遍歷和廣度優先遍歷(層序遍歷)。

  1 package com.allSorts;
  2 
  3 
  4 import java.util.LinkedList;
  5 import java.util.Queue;
  6 
  7 /**
  8  * Created by Demrystv.
  9  */
 10 public class BSTTraverseTest {
 11 
 12     public static void main(String[] args) {
 13         BinarySearchTree<Integer> tree = new BinarySearchTree<Integer>();
 14         tree.insertNode(28);
 15         tree.insertNode(16);
 16         tree.insertNode(13);
 17         tree.insertNode(22);
 18         tree.insertNode(30);
 19         tree.insertNode(29);
 20         tree.insertNode(42);
 21         System.out.print("前序遍歷(遞歸):");
 22         tree.preOrderTraverse(tree.getRoot());
 23         System.out.println();
 24         System.out.print("中序遍歷(遞歸):");
 25         tree.inOrderTraverse(tree.getRoot());
 26         System.out.println();
 27         System.out.print("後序遍歷(遞歸):");
 28         tree.postOrderTraverse(tree.getRoot());
 29         System.out.println();
 30         System.out.print("前序遍歷(非遞歸):");
 31         tree.preOrderTraverseNoRecursion(tree.getRoot());
 32         System.out.println();
 33         System.out.print("中序遍歷(非遞歸):");
 34         tree.inOrderTraverseNoRecursion(tree.getRoot());
 35         System.out.println();
 36         System.out.print("後序遍歷(非遞歸):");
 37         tree.postOrderTraverseNoRecursion(tree.getRoot());
 38         System.out.println();
 39         System.out.print("廣度優先遍歷:");
 40         tree.breadthFirstTraverse(tree.getRoot());
 41     }
 42 
 43 
 44     /**
 45      * 結點
 46      */
 47     public static class Node<E extends Comparable<E>> {
 48         E value;
 49         Node<E> left;
 50         Node<E> right;
 51         Node(E value) {
 52             this.value = value;
 53             left = null;
 54             right = null;
 55         }
 56     }
 57 
 58     /**
 59      * 使用一個前序遍歷構建一棵二分搜索樹
 60      */
 61     public static class BinarySearchTree<E extends Comparable<E>> {
 62         private Node<E> root;
 63         BinarySearchTree() {
 64             root = null;
 65         }
 66         public void insertNode(E value) {
 67             if (root == null) {
 68                 root = new Node<E>(value);
 69                 return;
 70             }
 71             Node<E> currentNode = root;
 72             while (true) {
 73                 if (value.compareTo(currentNode.value) > 0) {
 74                     if (currentNode.right == null) {
 75                         currentNode.right = new Node<E>(value);
 76                         break;
 77                     }
 78                     currentNode = currentNode.right;
 79                 } else {
 80                     if (currentNode.left == null) {
 81                         currentNode.left = new Node<E>(value);
 82                         break;
 83                     }
 84                     currentNode = currentNode.left;
 85                 }
 86             }
 87         }
 88         public Node<E> getRoot(){
 89             return root;
 90         }
 91         /**
 92          * 前序遍歷二分搜索樹(遞歸)
 93          * @param node
 94          */
 95         public void preOrderTraverse(Node<E> node) {
 96             System.out.print(node.value + " ");
 97             if (node.left != null)
 98                 preOrderTraverse(node.left);
 99             if (node.right != null)
100                 preOrderTraverse(node.right);
101         }
102         /**
103          * 中序遍歷二分搜索樹(遞歸)
104          * @param node
105          */
106         public void inOrderTraverse(Node<E> node) {
107             if (node.left != null)
108                 inOrderTraverse(node.left);
109             System.out.print(node.value + " ");
110             if (node.right != null)
111                 inOrderTraverse(node.right);
112         }
113         /**
114          * 後序遍歷二分搜索樹(遞歸)
115          * @param node
116          */
117         public void postOrderTraverse(Node<E> node) {
118             if (node.left != null)
119                 postOrderTraverse(node.left);
120             if (node.right != null)
121                 postOrderTraverse(node.right);
122             System.out.print(node.value + " ");
123         }
124         /**
125          * 前序遍歷二分搜索樹(非遞歸),用的是棧
126          * @param root
127          */
128         public void preOrderTraverseNoRecursion(Node<E> root) {
129             LinkedList<Node<E>> stack = new LinkedList<Node<E>>();
130             Node<E> currentNode = null;
131             stack.push(root);
132             while (!stack.isEmpty()) {
133                 currentNode = stack.pop();
134                 System.out.print(currentNode.value + " ");
135                 if (currentNode.right != null)
136                     stack.push(currentNode.right);
137                 if (currentNode.left != null)
138                     stack.push(currentNode.left);
139             }
140         }
141         /**
142          * 中序遍歷二分搜索樹(非遞歸),用的是棧
143          * @param root
144          */
145         public void inOrderTraverseNoRecursion(Node<E> root) {
146             LinkedList<Node<E>> stack = new LinkedList<Node<E>>();
147             Node<E> currentNode = root;
148             while (currentNode != null || !stack.isEmpty()) {
149                 // 一直迴圈到二叉排序樹最左端的葉子結點(currentNode是null)
150                 while (currentNode != null) {
151                     stack.push(currentNode);
152                     currentNode = currentNode.left;
153                 }
154                 currentNode = stack.pop();
155                 System.out.print(currentNode.value + " ");
156                 currentNode = currentNode.right;
157             }
158         }
159         /**
160          * 後序遍歷二分搜索樹(非遞歸),用的是棧
161          * @param root
162          */
163         public void postOrderTraverseNoRecursion(Node<E> root) {
164             LinkedList<Node<E>> stack = new LinkedList<Node<E>>();
165             Node<E> currentNode = root;
166             Node<E> rightNode = null;
167             while (currentNode != null || !stack.isEmpty()) {
168                 // 一直迴圈到二叉排序樹最左端的葉子結點(currentNode是null)
169                 while (currentNode != null) {
170                     stack.push(currentNode);
171                     currentNode = currentNode.left;
172                 }
173                 currentNode = stack.pop();
174                 // 當前結點沒有右結點或上一個結點(已經輸出的結點)是當前結點的右結點,則輸出當前結點
175                 while (currentNode.right == null || currentNode.right == rightNode) {
176                     System.out.print(currentNode.value + " ");
177                     rightNode = currentNode;
178                     if (stack.isEmpty()) {
179                         return; //root以輸出,則遍歷結束
180                     }
181                     currentNode = stack.pop();
182                 }
183                 stack.push(currentNode); //還有右結點沒有遍歷
184                 currentNode = currentNode.right;
185             }
186         }
187         /**
188          * 廣度優先遍歷二分搜索樹,又稱層次遍歷,用的是隊列
189          * @param root
190          */
191         public void breadthFirstTraverse(Node<E> root) {
192             Queue<Node<E>> queue = new LinkedList<Node<E>>();
193             Node<E> currentNode = null;
194             queue.offer(root);
195             while (!queue.isEmpty()) {
196                 currentNode = queue.poll();
197                 System.out.print(currentNode.value + " ");
198                 if (currentNode.left != null)
199                     queue.offer(currentNode.left);
200                 if (currentNode.right != null)
201                     queue.offer(currentNode.right);
202             }
203         }
204     }
205 }

  運行結果如下,與前面理論分析完全對應。

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 好久沒有學python了,反正各種理由吧(懶惰總會有千千萬萬的理由),最近網上學習了一下selenium,實現了一個簡單的自動登錄網頁,具體如下。 1.安裝selenium:如果你已經安裝好anaconda3,直接在windows的dos視窗輸入命令安裝selenium:python -m pip ...
  • 摘要(面試必問題之HashMap) HashMap是Java程式員使用頻率最高的用於映射(鍵值對)處理的數據類型。隨著JDK(Java Developmet Kit)版本的更新,JDK1.8對HashMap底層的實現進行了優化,例如引入紅黑樹的數據結構和擴容的優化等。本文結合JDK1.7和JDK1. ...
  • logging模塊 這個模塊是目前最重要的模塊!!!我一定給講透徹一點 很多程式都有記錄日誌的需求,並且日誌中包含的信息即有正常的程式訪問日誌,還可能有錯誤、警告等信息輸出,python中的logging模塊提供了標準的日誌介面,你可以通過它存儲各種級別的日誌,Logging的日誌可以分為以下5個級 ...
  • (一) 簡介 Appium是一個開源的自動化測試框架,可以用來測試基於iOS、Android和Firefox OS平臺的原生和混合應用。該框架使用Selenium Webdriver,在執行測試時和Selenium server通信的是JSON Wire Protocol。Appium允許我們使用, ...
  • (一){%%}和{{ }} {%%}:裡面的是模板標簽,{{}}裡面的是變數 {%%}標簽: 只有模板變數、字元串、整數和小數可以作為 {% ifequal %} 標簽的參數,像字典、列表、布爾類型的是不能用在 {% ifequal %}中的,例如{% ifequal test [1,2,3] %} ...
  • 最近正在努力學習中。。。我會把我每天學到的知識上傳到我的博客中,希望和大家交流,勿噴》、 首先要明白普通java項目跟伺服器中的路徑是不同的,普通java項目尋找路徑直接寫絕對路徑就可以,但是伺服器上的路徑不能直接寫你的eclips中的路徑。 當你的servlet類編譯以後,它會編譯到你的tomca ...
  • Python 之所以這麼流行得益於它適用於很多不同領域,目前 Python 使用最廣泛的領域包括有 Python Web(後端)開發、數據分析挖掘、網路爬蟲、機器學習人工智慧、運維開發等等。不管你選擇哪個方向,把Python基礎學牢有利於你在該領域更好的施展拳腳。 入門系列 《Python編程:從入 ...
  • 1.修改 list.get(i).name = name_1;一、封裝 1.成員變數增加private,在其他類訪問成員變數,無法訪問 2.無關成員方法,因為方法還用public來修飾 作用: 1、提高了代碼的復用性。 2、隱藏了實現細節,還要對外提供可以訪問的方式。便於調用者的使用。這是核心之一, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...