二叉查詢樹(查詢、插入、遍歷、刪除)--Java實現
阿新 • • 發佈:2019-01-27
搜尋樹資料結構支援許多動態集合操作,包括search、insert、delete、maximum、minimum等。因此,我們使用一棵搜尋樹既可以作為一個字典又可以作為一個優先佇列。
二叉搜尋樹上的基本操作所花費的時間與這棵樹的高度成正比。對於有n個結點的一棵完全二叉樹來說,這些操作的最壞執行時間為O(logn)。然而,如果這棵樹是一條n個結點組成的線性鏈,那麼同樣的操作就要花費O(n)的最壞的執行時間。
一、什麼是二叉搜尋樹
一棵二叉搜尋樹是以一棵二叉樹來組織的,這樣的一棵樹可以使用一個連結串列資料結構來表示,其中每個結點就是一個物件。最重要的特性就是:對任何結點x,其左子樹的關鍵字最大不超過x.value,其右子樹中的關鍵字最小不低於x.value。不同二叉搜尋樹可以代表同一組值的集合,大部分搜尋樹的最壞執行時間與樹的高度成正比。下圖為一棵包含11個結點、高度為4的二叉搜尋樹。
二、二叉查詢樹的操作(查詢、插入、遍歷、刪除)
定義結點
public class TreeNode{
public int keyValue; //關鍵字值
public TreeNode leftNode;//左節點
public TreeNode rightNode;//右節點
public TreeNode(){}
public TreeNode(int Key){
this.keyValue = Key;
}
}
(1)查詢二叉搜尋樹的結點
//查詢結點
public TreeNode BSTsearch(TreeNode root, int Key){
TreeNode node=root;
//當節點值不等於要查詢的結點值就迴圈,如果沒有找到則返回null
while(node.keyValue!=Key){
if(Key<node.keyValue){
node=node.leftNode;
}else{
node=node.rightNode;
}
if (node==null){
return null;
}
}
return node;
}
(2)插入二叉搜尋樹的結點
//插入結點,插入結點的過程就是先查詢再插入
public void BSTinsert(TreeNode root, int Key){
TreeNode node=new TreeNode(Key);
//插入結點之前先找到要插入的位置,這樣就要記住插入結點的父節點
//讓父節點的左右指標指向要新增的結點
if(root== null){
root=node;
}else{
TreeNode currentNode = root;//定義當前節點為根節點
TreeNode parentNode;
while(true){
parentNode=currentNode;
if(Key<currentNode.keyValue){
currentNode=currentNode.leftNode;
if(currentNode==null){
parentNode.leftNode=node;
return;
}
}else{
currentNode=currentNode.rightNode;
if(currentNode==null){
parentNode.rightNode=node;
return;
}
}
}
}
}
(3)遍歷二叉樹的結點
//遍歷樹,主要分為中序遍歷、前序遍歷和後序遍歷
//下面以中序遍歷做例子
public void BSTdisplay(TreeNode node){
if(node!=null){
BSTdisplay(node.leftNode);
System.out.println(node.keyValue+",");
BSTdisplay(node.rightNode);
}
}
(4)查詢二叉查詢樹中的最大結點
//最大值
public int BSTmax(TreeNode root){
TreeNode node=root;
TreeNode parent=null;
while(node!=null){
parent=node;
node=node.rightNode;
}
return parent.keyValue;
}
(5)查詢二叉查詢樹中的最小結點
//最小值
public int BSTmin(TreeNode root){
TreeNode node=root;
TreeNode parent=null;
while(node!=null){
parent=node;
node=node.leftNode;
}
return parent.keyValue;
}
(6)刪除二叉搜尋樹的結點
二叉樹的結點刪除要分成三類:
刪除沒有子結點的結點;
刪除只有一個子結點的結點;
刪除有兩個子結點的結點。
// 刪除節點分三種方式刪除節點
// 1、刪除沒有子節點的節點,直接讓該節點的父節點的左節點或右節點指向空
// 2、刪除有一個子節點的節點,直接讓該節點的父節點指向被刪除節點的剩餘節點
// 3、刪除有三個節點的子節點,找到要刪除節點的後繼節點, 用該節點替代刪除的節點
public boolean BSTdelete(TreeNode root,int Key) {
// 首先查詢節點,並記錄該節點的父節點引用
TreeNode current = root;
TreeNode parent = root;
boolean isLeftNode = true;
while (current.keyValue != Key) {
parent = current;
if (Key < current.keyValue) {
isLeftNode = true;
current = current.leftNode;
} else {
isLeftNode = false;
current = current.rightNode;
}
}
if (current == null) {
System.out.println("沒有找到要刪除的節點!");
return false;
}
// 下面分三種情況刪除節點
if (current.leftNode == null && current.rightNode == null) { //要刪除的節點沒有子節點
if (current == root) { // 根節點就刪除整棵樹
root = null;
} else if (isLeftNode) { // 如果是左節點,做節點指向空
parent.leftNode = null;
} else { // 如果是右節點,右節點指向空
parent.rightNode = null;
}
} else if (current.leftNode == null) { //要刪除的節點只有右節點
if (current == root) {
root = current.rightNode;
} else if (isLeftNode) {
parent.leftNode = current.rightNode;
} else {
parent.rightNode = current.rightNode;
}
} else if (current.rightNode == null) { //要刪除的節點只有左節點
if (current == root) {
root = current.leftNode;
} else if (isLeftNode) {
parent.leftNode = current.leftNode;
} else {
parent.rightNode = current.leftNode;
}
} else { //要刪除的節點有兩個節點
TreeNode successor = findSuccessor(current);
if(current == root){
root = successor;
}else if(isLeftNode){
parent.leftNode = successor;
}else{
parent.rightNode = successor;
}
successor.leftNode = current.leftNode;
}
return true;
}
private TreeNode findSuccessor(TreeNode delNode){
TreeNode parent = delNode;
TreeNode successor = delNode;
TreeNode current = delNode.rightNode;
while(current != null){
parent = successor;
successor = current;
current = current.leftNode;
}
if(successor != delNode.rightNode){
parent.leftNode = successor.rightNode;
successor.rightNode = delNode.rightNode;
}
return successor;
}