二叉排序樹(二叉查詢樹)BST構造,節點插入,節點查詢,節點刪除(java)
阿新 • • 發佈:2019-01-22
- 二叉排序樹(BST)的構造,節點插入,節點查詢,節點刪除(java)
高度最小BST(同樣資料,順序可能不一樣)
package ccnu.offer.tree;
import java.util.ArrayList;
import java.util.Arrays;
// 二叉排序樹(二叉查詢樹)BST
// 對於給定陣列(資料完全一樣,並且資料順序一定)構造二叉排序樹一定,但是資料一樣,順序不一樣,那麼排序樹就不一樣
// 構造高度最小的二叉排序樹,那麼就需要有如下要求:儘可能將陣列中還未插入的資料的中位數作為根節點
public class Demo04 {
public static void main(String[] args) {
int[] datas = new int[]{53, 17, 78, 9, 45, 65, 94, 23, 81, 88}; // page149:4-22
Node root = null;
root = removeBSTNode(createBST(root, datas), 78);
inOrder(root);
}
// 二叉排序樹的構造:就是不斷的插入新節點
public static Node createBST(Node root, int [] datas){
root = null;
int index = 0;
while(index < datas.length){
root = insertBST(root, datas[index]);
index++; // 插入下一個節點
}
return root;
}
// 二叉排序樹的插入
public static Node insertBST(Node root, int data){ // 插入的新節點一定為葉子
if (root == null){ // 以root為根節點的樹為空樹
root = new Node(data); // 左右子樹均為空
}
/*else if(data == root.data){ // 已存在此值的節點
return root;
}*/
else if(data <= root.data){ // 插入到root的左子樹上
root.lchild = insertBST(root.lchild, data);
}else{ // 插入到root的右子樹上
root.rchild = insertBST(root.rchild, data);
}
return root;
}
// 二叉查詢樹中查詢指定關鍵字值節點
public static Node searchBST(Node root, int data){
Node p = null; // 此處可得到所要找到節點的父節點
while(root != null && root.data != data){ // 當前樹非空並且所找節點不是當前樹的根節點
p = root;
if(data < root.data){
root = root.lchild;
}else{
root = root.rchild;
}
}
/*if(root == null){
p = null;
}*/
// return root;
return p; // 返回找到節點的父節點,當p為null,則說明找到的節點為整棵樹的根節點
}
// 得到指定樹root中父節點p的關鍵字值為data的孩子節點
public static Node getChild(Node root, Node p, int data){
if(p == null){ // 父節點為空,則找到的關鍵字值為data的節點為整棵樹的根節點root
return root;
}
if(p.lchild == null && p.rchild == null){ // 如果父節點為葉子節點,那麼不存在指定data節點
return null;
}
if(p.lchild != null && p.lchild.data == data){
return p.lchild;
}else{
return p.rchild;
}
}
public static Node searchBST1(Node root, int data){
if(root == null){
return null;
}else if(root.data == data){
return root;
}else if(data < root.data){
root = searchBST1(root.lchild, data);
}else{
root = searchBST1(root.rchild, data);
}
return root;
}
// 刪除以root作為根節點的樹中的關鍵字值為data的節點(第一次出現)
public static Node removeBSTNode(Node root, int data) {
if (root == null) {
return null;
}
Node p = searchBST(root, data); // 找到節點的父節點
Node node = null; // 找到的節點
node = getChild(root, p, data);
if (node == null) { // 不存在指定刪除的節點
return root; // 返回原樹根節點
}
if (node.lchild == null && node.rchild == null) { // 要刪除的節點為葉子結點,就直接從其父節點上刪除
if (node == root) { // 找到的節點為根節點 等價於p為null
root = null;
return root;
}
// 父節點不為空
if (p.lchild != null && p.lchild.data == node.data) { // 如果有左子樹並且左子樹根節點為找到的節點
p.lchild = null; // 直接將這個葉子節點從樹中刪除
} else {
p.rchild = null;
}
node = null; // 刪除節點
} else if (node.lchild != null && node.rchild == null) { // 只有左子樹
if (node == root) { // 找到節點為根節點
root = null;
return node.lchild;
}
if (p.lchild != null && p.lchild.data == node.data) { // 找到節點為父節點的左孩子節點
p.lchild = node.lchild;
} else {
p.rchild = node.lchild;
}
} else if (node.lchild == null && node.rchild != null) { // 只有右子樹
if (node == root) { // 找到節點為根節點
root = null;
return node.rchild;
}
if (p.lchild != null && p.lchild.data == node.data) {
p.lchild = node.rchild;
} else {
p.rchild = node.rchild;
}
} else { // 待刪除節點左右子樹均有,則應該將待刪除節點的直接前驅(中序遍歷,比刪除節點關鍵字值不大於節點的最大節點)結點替代,或者
// 將待刪除節點的直接後繼(中序遍歷,比刪除節點關鍵字值不小於節點的最小節點)結點替代,進而將問題轉換為刪除剛才的替代節點
// 此處實現的是用刪除節點的直接後繼結點替代
Node nextNode = node.rchild; // 刪除節點的直接後繼,實際上這個直接後繼節點或者是葉子結點或者是隻有右子樹的節點
while (nextNode.lchild != null) {
nextNode = nextNode.lchild;
}
removeBSTNode(node, nextNode.data); // 在待刪除的節點為根節點的樹中刪除其直接後繼節點nextNode
nextNode.lchild = node.lchild; // 將刪除節點的左子樹作為後繼節點的左子樹
nextNode.rchild = node.rchild; // 將刪除節點的右子樹作為後繼節點的右子樹
if (node == root) { // 刪除節點為根節點
return nextNode;
}else{
if (p.lchild != null && p.lchild.data == node.data) { // 刪除節點在其父節點的左子樹上
p.lchild = nextNode;
} else {
p.rchild = nextNode;
}
}
}
return root;
}
public static void inOrder(Node root){ // 中序遍歷BST為單調遞增序列
if(root != null){
inOrder(root.lchild);
System.out.print(root.data + " ");
inOrder(root.rchild);
}
}
private static class Node extends Object{
private Node lchild = null;
private Node rchild = null;
private int data;
public Node(int data){
this.data = data;
}
}
// 得到一組資料的中位數,以這樣的資料構造BST將會是平衡二叉樹,同時也是所有這些同樣資料(順序不一樣)構造的排序二叉樹中高度最小的哦
public static ArrayList<Integer> getMedians(int[] datas, int begin, int end) {
Arrays.sort(datas);
ArrayList<Integer> arr = new ArrayList<Integer>();
if (begin > end) {
return arr; // 空arr
} else if (begin == end) {
arr.add(datas[begin]);
} else {
int medium = (begin + end) / 2;
arr.add(datas[medium]);
arr.addAll(getMedians(datas, begin, medium - 1));
arr.addAll(getMedians(datas, medium + 1, end));
}
return arr;
}
public static int getDepth(Node root){
int ldepth = 0; // 左子樹高度
int rdepth = 0; // 右子樹高度
if(root == null){ // 空樹深度為0
return 0;
}
ldepth = getDepth(root.lchild);
rdepth = getDepth(root.rchild);
return (ldepth > rdepth ? ldepth : rdepth) + 1;
}
}