二叉樹系列5:建立二叉搜尋樹
二叉查詢樹(Binary Search Tree),(又:二叉搜尋樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉排序樹。
二叉排序樹的查詢過程和次優二叉樹類似,通常採取二叉連結串列作為二叉排序樹的儲存結構。中序遍歷二叉排序樹可得到一個關鍵字的有序序列,一個無序序列可以通過構造一棵二叉排序樹變成一個有序序列,構造樹的過程即為對無序序列進行排序的過程。每次插入的新的結點都是二叉排序樹上新的葉子結點,在進行插入操作時,不必移動其它結點,只需改動某個結點的指標,由空變為非空即可。搜尋,插入,刪除的複雜度等於樹高,O(log(n))。
1 插入
/**
* 二叉樹的插入操作
*/
public boolean add(TreeNode t, int val) {
if (t == null) {
t = new TreeNode(val);
return true;
}
// 如果父節點等於要插入的值,則說明該值已存在,所以不新建任何節點,返回false
if (t.val == val) {
return false;
}
// 如果val 小於 父節點的值,則新節點應該為其左子樹中
else if (val < t.val) {
// 如果左子樹為空,則新建節點, 並將這個節點設為左孩子
if (t.left == null) {
t.left = new TreeNode(val);
return true;
} else {
return add(t.left, val);
}
} else {
if (t.right == null ) {
t.right = new TreeNode(val);
return true;
} else {
return add(t.right, val);
}
}
}
/** 非遞迴中序遍歷二叉樹 */
public ArrayList<TreeNode> inorderTraversal(TreeNode t) {
if (t == null) {
return null;
}
Stack<TreeNode> stack = new Stack<>();
ArrayList<TreeNode> aList = new ArrayList<>();
TreeNode p = t;
while (p != null || !stack.isEmpty()) {
// 如果目前訪問的節點不為空,則嘗試先訪問它的左子樹
if (p != null) {
stack.push(p);
// 開始訪問左子樹
p = p.left;
}
// 如果 p為null說明訪問的左節點為空,將先前壓入棧的父節點pop,列印,並且開始訪問右子樹
else {
p = stack.pop();
// 列印父節點
aList.add(p);
// 開始訪問右子樹
p = p.right;
}
}
return aList;
}
2 刪除
- 首先,找到這個要刪除的節點
- 如果它是葉子節點就可以直接刪除
- 如果它只有一個子節點,則讓它的子節點代替它的位置就好了
- 如果它有兩個子節點,則找到右子樹的最小值,這個值一定是一個葉子,所以先將這個最小值復值給要刪除的節點的值域,然後刪除這個最小值節點,由於是葉子節點,所以很容易刪除
private TreeNode remove(TreeNode t, int val) {
if (t == null) {
return null;
}
// 第一步是,找到要刪除的節點
// 小於0,說明該節點在左子樹中
if (val - t.val < 0) {
t.left = remove(t.left, val);
}
// 大於0,說明該節點在右子樹中
else if (val - t.val > 0) {
t.right = remove(t.right, val);
}
// 等於0,說明找到了
else {
// 如果這是一個葉子,則直接刪除這個節點
if (t.left == null && t.right == null) {
t = null;
}
// 如果該節點有一個兒子
else if (t.left == null ^ t.right == null) {
return t = (t.left != null ? t.left : t.right);
}
// 如果有兩個兒子
else if (t.left != null && t.right != null) {
TreeNode minNode = findMin(t.right);
t.val = minNode.val;
t.right = remove(t.right, minNode.val);
}
}
return t;
}
private TreeNode findMin(TreeNode t) {
if (t == null) {
return null;
} else if (t.left == null) {
return t;
} else {
return findMin(t.left);
}
}
3 測試
public class Main {
public static void main(String[] args) {
TreeNode binarySearchTree = new TreeNode(8);
BinaryTreeTest testTree = new BinaryTreeTest();
testTree.add(binarySearchTree, 22);
testTree.add(binarySearchTree, 3);
testTree.add(binarySearchTree, 13);
testTree.add(binarySearchTree, 5);
testTree.add(binarySearchTree, 7);
testTree.add(binarySearchTree, 27);
System.out.println("\n通過插入新建了一個二叉搜尋樹,然後輸出其中序遍歷的結果");
ArrayList<TreeNode> aList = testTree.inorderTraversal(binarySearchTree);
for (TreeNode treeNode : aList) {
System.out.printf("%-5d", treeNode.val);
}
testTree.remove(binarySearchTree, 7);
System.out.println("\n刪除已經存在的 7");
aList = testTree.inorderTraversal(binarySearchTree);
for (TreeNode treeNode : aList) {
System.out.printf("%-5d", treeNode.val);
}
}
}
輸出:
通過插入新建了一個二叉搜尋樹,然後輸出其中序遍歷的結果
3 5 7 8 13 22 27
刪除已經存在的 7
3 5 8 13 22 27
相關推薦
二叉樹系列5:建立二叉搜尋樹
二叉查詢樹(Binary Search Tree),(又:二叉搜尋樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的
劍指offer第55.5:平衡二叉樹
題目描述 輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 class Solution: def IsBalanced_Solution(self, pRoot): # write code here if not pRoot:
二叉樹系列3: 二叉樹的路徑問題
1 輸出根節點到葉子節點的路徑 TreeNode.java package BinaryTree; public class TreeNode { int val; TreeNode left; TreeNode right
java由先根中根遍歷序列建立二叉樹,由標明空子樹建立二叉樹,有完全二叉樹順序儲存結構建立二叉鏈式儲存結構
//由先根和中根遍歷建立二叉樹 public class bitree{ public bitree(String preorder,String inorder,int preindex,int in
【LeetCode & 劍指offer刷題】樹題9:34 二叉樹中和為某一值的路徑(112. Path Sum)
【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 112. Path Sum Given a binary tree and a sum, determine if the tree has a root-to-leaf path suc
【LeetCode & 劍指offer刷題】樹題7:27 二叉樹的映象
【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 27 二叉樹的映象 題目描述 操作給定的二叉樹,將其變換為源二叉樹的映象。 輸入描述: 二叉樹的映象
遍歷二叉樹的應用:輸出二叉樹所有葉結點和求高度
利用二叉樹的遍歷方法,我們可以求得一棵二叉樹的很多東西,例如我們可以遍歷求得一棵二叉樹的所有葉結點,到我們找到一個結點的左右子樹都為空了,它就是其中一個葉結點,我們把它儲存起來,在遍歷完一棵二叉樹後,我們就可以找到所有的葉結點。同理,我們也可以通過遍歷一棵二叉樹的所有節點後,
CentOS 基本指令(二)——Linux 使用者管理:建立使用者與變更使用者組
首先我們使用 useradd 使用者名稱 命令建立一個新使用者: 然後需要繼續為新使用者建立密碼和主目錄: useradd -d "/home/username" -m passwd username 使用如下命令可以將使用者新增到不同的使用者組: usermod -
C++遊戲系列5:不止有一件武器
location ref 初始 .text isalive urn lan dead then 很多其它見:C++遊戲系列文件夾 知識點:對象數組作為數據成員 改進:每一個角色所持有的武器不僅僅一件,故持有的武器,用了對象數組來表示,當然,也能
Azure手把手系列5:Azure帳戶和訂閱
雲計算 雲服務 對於Azure來說,帳戶和訂閱是非常重要的。很多朋友都不明白Azure的帳戶和訂閱的關系,今天我們就通過簡單通俗易懂的方式來介紹一下Azure的帳戶和訂閱。 ? ?要使用Azure服務,必須擁有一個Azure 的帳戶,還必須擁有Azure訂閱。這裏我們以身份證和手機SIM卡來介紹Az
go基礎系列(5):陣列
瞭解Python、Perl、JavaScript的人想必都知道它們的陣列是動態的,可以隨需求自動增大陣列長度。但Go中的陣列是固定長度的,陣列一經宣告,就無法擴大、縮減陣列的長度。但Go中也有類似的動態"陣列",稱為slice資料結構,在下一篇文章會詳細解釋它。 Go中的陣列是slice和map兩種資料型別的
強化學習系列5:有模型的策略迭代方法
1. 策略迭代演算法 這裡策略迭代使用的是表格法,基本步驟是: 用字典儲存每個s的v值 根據v值來選骰子 策略迭代的步驟為: 初始化 V
【LeetCode & 劍指offer刷題】樹題5:110 Balanced Binary Tree
【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 110. Balanced Binary Tree Given a binary tree, determine if it is height-balanced.
windows bat系列5:檢視監聽埠&終止程序
1. netstat說明:顯示協議統計和當前 TCP/IP 網路連線。其相關命令列引數如下: -a 顯示所有連線和偵聽埠。 -b 顯示在建立每個連線或偵聽埠時涉及的可執行程式。 在某些情況下,已
爬蟲系列5:scrapy動態頁面爬取的另一種思路
前面有篇文章給出了爬取動態頁面的一種思路,即應用Selenium+Firefox(參考《scrapy動態頁面爬取》)。但是selenium需要執行本地瀏覽器,比較耗時,不太適合大規模網頁抓取。 事實上,還有一種執行效率更高的方法。就是事先分析js發出的GET或者POST請求
VSTO之旅系列(四):建立Word解決方案
本專題概要 引言 Word物件模型 建立Word外接程式 小結 一、引言 在上一個專題中主要為大家介紹如何自定義我們的Excel 介面的,然而在這個專題中,我將為大家介紹如何用VSTO來建立Word專案,對於Word的VSTO開發和Excel的開發很類似,你同樣也可以為Word自定義
SSO單點登入系列5:cas單點登入增加驗證碼功能完整步驟
本篇教程cas-server端下載地址:解壓後,直接放到tomcat的webapp目錄下就能用了,不過你需要登入的話,要修改資料來源,C:\tomcat7\webapps\casServer\WEB-INF\deployerConfigContext.xml,嗯。地址
SQL Server溫故系列(5):SQL 查詢之分組查詢 GROUP BY
1、GROUP BY 與聚合函式 2、GROUP BY 與 HAVING 3、GROUP BY 擴充套件分組 3.1、GROUP BY ROLLUP 3.2、GROUP BY CUBE 3.3、GROUP BY GROUPING SETS 4、GROUP BY 擴充套件函式 4.1、GROUPING
HelloDjango 系列教程:建立 Django 部落格的資料庫模型
文中涉及的示例程式碼,已同步更新到 HelloGitHub-Team 倉庫 設計部落格的資料庫表結構 部落格最主要的功能就是展示我們寫的文章,它需要從某個地方獲取部落格文章資料才能把文章展示出來,通常來說這個地方就是資料庫。我們把寫好的文章永久地儲存在資料庫裡,當用戶訪問我們的部落格時,django
夯實Java基礎系列5:Java檔案和Java包結構
目錄 Java中的包概念 包的作用 package 的目錄結構 設定 CLASSPATH 系統變數 常用jar包 java軟體包的型別 dt.jar rt.jar *.java檔案的奧祕 *.Java檔案簡介 為什麼一個java原始檔中只能有一個public類? Main方法 外部類的訪問許可權