二叉搜索樹
二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹。
二叉搜索樹操作
- 因爲二叉樹搜索樹的特點,我們插入一個元素必然需要從根節點開始查找整個樹,直到找到準確的位置
- 二叉搜索樹查詢很快logn
- 二叉搜索樹的刪除
- 如果要刪除的節點是葉子節點 直接刪除,父節點對應子樹設爲null
- 如果要刪除的節點只有一個子樹,父節點指向當前節點的子樹。
- 如果要刪除的節點有2個子樹,則先找到當前節點的後繼節點,把後繼節點的值賦值給當前節點。刪除後繼節點,因爲後繼節點肯定不會有2個子樹。
代碼再現
public class MyBinarySeachTree {
private TreeNode root;
static class TreeNode {
private TreeNode left;//左節點
private TreeNode right;//右節點
private TreeNode parent;//父節點
private int data;//數據值
private boolean position = false;//表示左邊
public TreeNode(int data) {
this.data = data;
}
}
public MyBinarySeachTree(int data) {
root = new TreeNode(data);
}
/**
* 正常插入法
* @param data
*/
public void insert(int data) {
TreeNode node = new TreeNode(data);
TreeNode pa = root.right;
if( node.data >= root.data) {
pa = root.right;
}else{
pa = root.left;
}
while( true ) {
if( pa == null && node.data >= root.data ) {
root.right = node;
node.parent = root;
node.position = true;
break;
}else if(pa == null && node.data < root.data) {
root.left = node;
node.parent = root;
break;
}
if( node.data >= pa.data){
if( pa.right != null) {
pa = pa.right;
continue;
}
pa.right = node;
node.parent = pa;
node.position = true;
break;
}else if(node.data < pa.data ){
if( pa.left != null) {
pa = pa.left;
continue;
}
pa.left = node;
node.parent = pa;
break;
}
}
}
/**
* 遞歸插入法
* @param root
* @param data
*/
public void insert(TreeNode root , int data) {
if( data > root.data) {
if(root.right ==null) {
TreeNode node = new TreeNode(data);
root.right = node;
node.parent = root;
node.position = true;
return;
}
insert(root.right, data);
}else {
if(root.left ==null) {
TreeNode node = new TreeNode(data);
root.left = node;
node.parent = root;
return;
}
insert(root.left, data);
}
}
public TreeNode search(TreeNode root , int data) {
if(root == null) {
System.out.println("沒有找到");
return null;
}
if( data > root.data) {
return search(root.right, data);
}else if(data < root.data ) {
return search(root.left, data);
}else{
System.out.println("找到節點了");
return root;
}
}
private TreeNode findNextNode(TreeNode node) {
TreeNode parent = node;
while(parent.left != null) {
parent = parent.left;
}
return parent;
}
/**
* 9
* 7 11
* 5 8 10 16(X)
*2 6 12 24
* 19 26
* 20 28
*
* 1.要刪除的結點是葉子結點 O(1)
* 2.要刪除的結點只有一個子樹(左或者右)O(1)
* 3.要刪除的結點有兩顆子樹:找後繼結點,而且後繼結點的左子樹一定爲空。
*
*
* @param data
*/
public void remove(int data) {
TreeNode node = search(root, data);
remove(node);
}
private void remove(TreeNode node) {
if( node !=null ) {
//先判斷是否存在左右子樹
if(node.left ==null || node.right == null) {
if(node.left != null && node.position==false) node.parent.left = node.left;//要刪除節點的左子樹不爲空,並且當前節點是父節點的左子樹
else if(node.left != null && node.position==true) node.parent.right = node.left;//要刪除節點的左子樹不爲空,並且當前節點是父節點的右子樹
else if(node.right != null && node.position==false) node.parent.left = node.right;//要刪除節點的右子樹不爲空,並且當前節點是父節點的左子樹
else if(node.right != null && node.position==true) node.parent.right = node.right;//要刪除節點的右子樹不爲空,並且當前節點是父節點的右子樹
else if(node.position==false) node.parent.left = null; //當前節點是父節點的左子樹
else node.parent.right = null; //當前節點是父節點的右子樹
//移除當前節點
node = null;
}else{//查找當前節點的後繼節點
TreeNode treeNode = findNextNode(node.right);
node.data = treeNode.data;
remove(treeNode);
}
}
}
public void print() {
show(root);
System.out.println("");
}
private void show(TreeNode node) {
if(node == null) {
return;
}
show(node.left);
System.out.print(node.data+ " ");
show(node.right);
}
public static void main(String[] args) {
int data[] = {9,7,11,5,8,10,16,2,6,12,24,19,26,20,28};
MyBinarySeachTree root = new MyBinarySeachTree(data[0]); //第一個點作爲跟結點
for(int i = 1 ; i < data.length ; i ++) {
//root.insert(root, data[i]);
root.insert(data[i]);
}
root.print();
root.remove(16);
System.out.println("刪除節點:"+16);
root.print();
}
}