普通的二叉搜索树总结+java实现

目录

二叉搜索树的概念

结构

节点类

二叉搜索树类

实现-增删查

插入节点

创建二叉搜索树

搜索节点

删除节点

删除节点2

应用

搜索

排序

完整代码


二叉搜索树的概念

二叉搜索树(Binary Search Tree)节点放置:任何节点的键值一定大于其左子树的每一个节点的键值,并小于其右子树的每一个节点的键值。

因此,找出BST树的最大元素和最小元素,就是从根节点一直往左走,直至无左路可走,即得最小元素;从根节点一直往右走,直至无右路可走,即得最大元素。


结构

节点类

有左右节点和值,还有一个打印节点的方法,方便使用

package datastructure.tree.binarysearchtree;

import java.util.LinkedList;
import java.util.Queue;

public class TreeNode {

	int val;
	public TreeNode left;
	public TreeNode right;
	public TreeNode(int x) {
		val = x; 
		left=null;
		right=null;
	}
	
	//通过队列 当前下层节点个数 打印每层的节点和null,为了方便打印
		public static void printTree(TreeNode root){
	        if(root == null)
	            return;
	        Queue<TreeNode> queue = new LinkedList<TreeNode>();
	        
	        int current;//当前层 还未打印的结点个数
	        int next;//下一层结点个数
	        
	        queue.offer(root);
	        current = 1;
	        next = 0;
	        while(!queue.isEmpty()){
	            TreeNode currentNode = queue.poll();
	            if (currentNode!=null) {
	            	System.out.print(currentNode.val+" ");
	                current--;
	               
				}
	            else{
	            	System.out.print("null ");
	            	 current--;
	            	 queue.offer(null);
	                 next++;
	                 queue.offer(null);
	                 next++;                
	                 if(current ==0){
	                     System.out.println();
	                     current = next;
	                     next = 0;
	                     int temp=0;
	                     for (TreeNode treeNode : queue) {
							if(treeNode==null){
								temp++;
							}
						}
	                     if(temp==current){
	                    	 System.out.println("end");
	                         break;
	                     }
	                     
	                 }
	                continue;
	            }
	            
	            if(currentNode.left != null){
	                queue.offer(currentNode.left);
	                next++;
	            }
	            else{
	            	queue.offer(null);
	                next++;
	            }
	            if(currentNode.right != null){
	                queue.offer(currentNode.right);
	                next++;
	            }
	            else{
	            	queue.offer(null);
	                next++;
	            }
	            if(current ==0){
	                System.out.println();
	                current = next;
	                next = 0;
	                int temp=0;
	                for (TreeNode treeNode : queue) {
						if(treeNode==null){
							temp++;
						}
					}
	                if(temp==current){
	               	 System.out.println("end");
	                    break;
	                }
	                
	            }
	            
	        }
	    }
}

二叉搜索树类

一个tree中有一个节点root,其他全是方法

public class BinarySearchTree {

	public TreeNode root;
	

实现-增删查

插入节点

BST树插入新元素时,从根节点开始,遇到键值较大的值就向左,遇到较小的就向右,一直到尾端,就是插入点。

插入节点,如果已存在相同的树,则不插入,返回已有的节点,否则返回插入的节点
将now=root 将now的值与x比较,相同返回now,x大,则如果now无右节点,创建右节点x并返回,否则now=now.right
x小则反之亦然

//插入节点,如果已存在相同的树,则不插入,返回已有的节点,否则返回插入的节点
	//将now=root 将now的值与x比较,相同返回now,x大,则如果now无右节点,创建右节点x并返回,否则now=now.right
	//x小则反之亦然
	public TreeNode insertNode(int x){		
		if(root==null){
			root=new TreeNode(x);
			return root;
		}
		TreeNode now=root;
		while(true){
			if(now.val==x){
				return now;
			}
			if(now.val>x){
				if(now.left==null){
					now.left=new TreeNode(x);
					return now.left;
				}
				else{
					now=now.left;
					continue;
				}
			}
			else{
				if(now.right==null){
					now.right=new TreeNode(x);
					return now.right;
				}
				else{
					now=now.right;
					continue;
				}
			}
		}
		
	}

创建二叉搜索树

只有一个int,则root为x的节点

x为数组,如果长度为0,初始化root为0的节点
否则逐个插入x的元素

//只有一个int,则root为x的节点
	public BinarySearchTree(int x){
		root=new TreeNode(x);
	}	
	
	//x为数组,如果长度为0,初始化root为0的节点
	//否则逐个插入x的元素
	public BinarySearchTree(int[] x){		
		int length=x.length;
		if(length==0){
			root=new TreeNode(0);
			return;
		}
		for(int i=0;i<length;i++){
			insertNode(x[i]);
		}		
	}

搜索节点

根据now与x的大小,进入now的左右子节点,直到找到now.val==x或者now==null

	
	//根据int x查找二叉搜索树的节点,如果没找到 返回null,找到了,返回该节点
	//now=root 进入true的循环 如果now=null,说明没有返回null,now的值=x,说明找到,返回now
	//否则根据now与x的大小,now=now的左右子节点
	public TreeNode findNode(int x){
		if(root==null){
			return null;
		}
		TreeNode now=root;
		while(true){
			if(now==null){
				return null;
			}
			if(now.val==x){
				return now;
			}
			if(now.val<x){
				now=now.right;
			}
			else {
				now=now.left;
			}
		}				
	}

删除节点

删除节点首先要找到节点,还要找到他的父亲节点,并记录下是父亲节点的左还是右节点

		TreeNode now=root;
		TreeNode parent=root;
		boolean isLeft=true;
		while(true){
			if(now==null){
				return;
			}
			if(now.val==x){
				break;
			}
			if(now.val<x){
				parent=now;
				now=now.right;
				isLeft=false;
			}
			else {
				parent=now;
				now=now.left;
				isLeft=true;
			}
		}	

 

删除节点分两种大情况,每种各有三种情况

如果删除的是普通节点

如果该节点没有左右节点

直接parent的左右节点为null即可

		if(now.left==null&&now.right==null){
			if(isLeft){
				parent.left=null;
				return;
			}
			else{
				parent.right=null;
				return;
			}
		}

如果只有左或者右节点

如果A只有一个子节点,就直接将A的子节点连至A的父节点,并将A删除;

		//如果now没有左右子节点,则parent的子节点为null,根据isLeft判断now是parent的左右节点
		if(now.left==null&&now.right==null){
			if(isLeft){
				parent.left=null;
				return;
			}
			else{
				parent.right=null;
				return;
			}
		}
		//如果now只有左节点,则根据isleft parent的左右节点为now.left
		if(now.left!=null&&now.right==null){
			if(isLeft){
				parent.left=now.left;
				return;
			}
			else{
				parent.right=now.left;
				return;
			}
		}

节点左右节点都有

就以右子树的最小节点(右子树的最左节点,我选的是这个)或左子树的最大节点取代A即可。

有两种方法,一种是修改值,一种是节点left,right改变(我选的是这个),前一个应该简单一点

		//如果now左右节点都有,则根据isleft parent的左右节点为now的右节点的最左边的那个mostLeft
		//相当于把mostLeft替换掉now
		if(now.left!=null&&now.right!=null){
			TreeNode mostLeft=now.right;
			TreeNode mostLeftParent=now;
			while(mostLeft.left!=null){
				mostLeftParent=mostLeft;
				mostLeft=mostLeft.left;		
			}
			if(mostLeft==now.right){
				if(isLeft){
					parent.left=now.right;
				}
				else{
					parent.right=now.right;
				}
				now.right.left=now.left;				
			}
			else{
				mostLeftParent.left=mostLeft.right;
				if(isLeft){
					parent.left=mostLeft;
				}
				else{
					parent.right=mostLeft;
				}
				mostLeft.right=now.right;
				mostLeft.left=now.left;
			}
			
		}				
	}

如果是root,说明它没有parent,需要特殊处理,但是逻辑与上面的相同,只是没有parent的操作

		//如果now是root,说明它没有parent,需要特殊处理,但是逻辑与下面的相同,只是没有parent的操作
		if(now==root){
			if(now.left==null&&now.right==null){
				root=null;
				return;
			}
			if(now.left!=null&&now.right==null){
				root=now.left;
				return;
			}
			if(now.left==null&&now.right!=null){
				root=now.right;
				return;
			}
			if(now.left!=null&&now.right!=null){
				TreeNode mostLeft=now.right;
				TreeNode mostLeftParent=now;
				while(mostLeft.left!=null){
					mostLeftParent=mostLeft;
					mostLeft=mostLeft.left;		
				}
				if(mostLeft==now.right){					
					now.right.left=root.left;	
					root=now.right;	
					return;
				}
				else{					
					mostLeftParent.left=mostLeft.right;
					root=mostLeft;
					mostLeft.right=now.right;
					mostLeft.left=now.left;
					return;
				}
				
			}
			
		}	

删除节点2

节点左右节点都有

就以右子树的最小节点(右子树的最左节点,我选的是这个)或左子树的最大节点取代A即可。

有两种方法,一种是修改值,一种是节点left,right改变(我选的是这个),现在选择第一种,

 

删除30,在30节点处将值换为32,然后删除原来的32节点,将情况从原来的有左右孩子变成有一个孩子或者没有孩子

//获取当前节点的后继结点
Node<T> successor = successor(node);
//转移值
node.key = successor.key;
//后续变成删除 successor,就变成了前两种情况
//在图示例子中,就是第一种没有子节点的情况
node = successor;

3种情况的结合

private BSTNode<T> delete(BSTNode<T> node) {
    //第 3 种情况,如果同时存在左右子节点
    if (node.left != null && node.right != null){
        //获取后继结点
        BSTNode<T> successor = successor(node);
        //转移后继结点值到当前节点
        node.key = successor.key;
        //把要删除的当前节点设置为后继结点
        node = successor;
    }
    //经过前一步处理,下面只有前两种情况,只能是一个节点或者没有节点
    //不管是否有子节点,都获取子节点
    BSTNode<T> child;
    if (node.left != null)
        child = node.left;
    else
        child = node.right;
    //如果 child != null,就说明是有一个节点的情况    
    if (child != null)
        //将子节点和父节点关联上
        child.parent = node.parent;
    //如果当前节点没有父节点(后继情况到这儿时一定有父节点)
    //说明要删除的就是根节点
    if (node.parent == null)
        //根节点设置为子节点
        //按照前面逻辑,根只有一个或者没有节点,所以直接赋值 child 即可
        mRoot = child;
    else if (node == node.parent.left)//存在父节点,并且当前节点是左节点时
        //将父节点的左节点设置为 child
        node.parent.left = child;
    else//右节点时
        //将父节点的右节点设置为 child
        node.parent.right = child;
    //返回被删除的节点
    return node;
}
//删除指定的值
public void delete(T key) {
    //获取要删除的节点
    BSTNode<T> node = search(mRoot, key);
    //如果存在就删除
    if (node != null)
       delete(node);
}

 

应用

搜索

只要o(logn)时间即可

排序

中序遍历即可,o(n)时间

 

完整代码

package datastructure.tree.binarysearchtree;

public class Main {

	public static void main(String[] args) {

		int[] x=new int[]{1,3,2,-4,0,4};	
		BinarySearchTree tree=new BinarySearchTree(x);
		//tree.insertNode(3);
		BinarySearchTree.printTree(tree.root);
		//BinarySearchTree.inOrder(tree.root);
		//BinarySearchTree.breadthFirstSearch(tree.root);
		//BinarySearchTree.depthFirstSearch(tree.root);
		//TreeNode now=tree.findNode(2);
		//now.printTree(now);
		tree.deleteNode(1);
		BinarySearchTree.printTree(tree.root);
	}

}
package datastructure.tree.binarysearchtree;

import java.util.LinkedList;
import java.util.Queue;

public class TreeNode {

	int val;
	public TreeNode left;
	public TreeNode right;
	public TreeNode(int x) {
		val = x; 
		left=null;
		right=null;
	}
	
	//通过队列 当前下层节点个数 打印每层的节点和null,为了方便打印
		public static void printTree(TreeNode root){
	        if(root == null)
	            return;
	        Queue<TreeNode> queue = new LinkedList<TreeNode>();
	        
	        int current;//当前层 还未打印的结点个数
	        int next;//下一层结点个数
	        
	        queue.offer(root);
	        current = 1;
	        next = 0;
	        while(!queue.isEmpty()){
	            TreeNode currentNode = queue.poll();
	            if (currentNode!=null) {
	            	System.out.print(currentNode.val+" ");
	                current--;
	               
				}
	            else{
	            	System.out.print("null ");
	            	 current--;
	            	 queue.offer(null);
	                 next++;
	                 queue.offer(null);
	                 next++;                
	                 if(current ==0){
	                     System.out.println();
	                     current = next;
	                     next = 0;
	                     int temp=0;
	                     for (TreeNode treeNode : queue) {
							if(treeNode==null){
								temp++;
							}
						}
	                     if(temp==current){
	                    	 System.out.println("end");
	                         break;
	                     }
	                     
	                 }
	                continue;
	            }
	            
	            if(currentNode.left != null){
	                queue.offer(currentNode.left);
	                next++;
	            }
	            else{
	            	queue.offer(null);
	                next++;
	            }
	            if(currentNode.right != null){
	                queue.offer(currentNode.right);
	                next++;
	            }
	            else{
	            	queue.offer(null);
	                next++;
	            }
	            if(current ==0){
	                System.out.println();
	                current = next;
	                next = 0;
	                int temp=0;
	                for (TreeNode treeNode : queue) {
						if(treeNode==null){
							temp++;
						}
					}
	                if(temp==current){
	               	 System.out.println("end");
	                    break;
	                }
	                
	            }
	            
	        }
	    }
}
package datastructure.tree.binarysearchtree;

import java.nio.channels.NetworkChannel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;


public class BinarySearchTree {

	public TreeNode root;
	
	//只有一个int,则root为x的节点
	public BinarySearchTree(int x){
		root=new TreeNode(x);
	}	
	
	//x为数组,如果长度为0,初始化root为0的节点
	//否则逐个插入x的元素
	public BinarySearchTree(int[] x){		
		int length=x.length;
		if(length==0){
			root=new TreeNode(0);
			return;
		}
		for(int i=0;i<length;i++){
			insertNode(x[i]);
		}		
	}
	
	//插入节点,如果已存在相同的树,则不插入,返回已有的节点,否则返回插入的节点
	//将now=root 将now的值与x比较,相同返回now,x大,则如果now无右节点,创建右节点x并返回,否则now=now.right
	//x小则反之亦然
	public TreeNode insertNode(int x){		
		if(root==null){
			root=new TreeNode(x);
			return root;
		}
		TreeNode now=root;
		while(true){
			if(now.val==x){
				return now;
			}
			if(now.val>x){
				if(now.left==null){
					now.left=new TreeNode(x);
					return now.left;
				}
				else{
					now=now.left;
					continue;
				}
			}
			else{
				if(now.right==null){
					now.right=new TreeNode(x);
					return now.right;
				}
				else{
					now=now.right;
					continue;
				}
			}
		}
		
	}
	
	//根据int x查找二叉搜索树的节点,如果没找到 返回null,找到了,返回该节点
	//now=root 进入true的循环 如果now=null,说明没有返回null,now的值=x,说明找到,返回now
	//否则根据now与x的大小,now=now的左右子节点
	public TreeNode findNode(int x){
		if(root==null){
			return null;
		}
		TreeNode now=root;
		while(true){
			if(now==null){
				return null;
			}
			if(now.val==x){
				return now;
			}
			if(now.val<x){
				now=now.right;
			}
			else {
				now=now.left;
			}
		}				
	}
	
	
	//如果树中没有值为x,则啥都不干,否则删除这个节点
	//先找到这个x,与查找的方法不同,还要找到它的父节点
	//如果now是root,说明它没有parent,需要特殊处理,但是逻辑与下面的相同,只是没有parent的操作
	//如果now没有左右子节点,则parent的子节点为null,根据isLeft判断now是parent的左右节点
	//如果now只有左节点,则根据isleft parent的左右节点为now.left
	//如果now只有右节点,则根据isleft parent的左右节点为now.right
	public void deleteNode(int x){
		if(root==null){
			return;
		}
		TreeNode now=root;
		TreeNode parent=root;
		boolean isLeft=true;
		while(true){
			if(now==null){
				return;
			}
			if(now.val==x){
				break;
			}
			if(now.val<x){
				parent=now;
				now=now.right;
				isLeft=false;
			}
			else {
				parent=now;
				now=now.left;
				isLeft=true;
			}
		}	
		//如果now是root,说明它没有parent,需要特殊处理,但是逻辑与下面的相同,只是没有parent的操作
		if(now==root){
			if(now.left==null&&now.right==null){
				root=null;
				return;
			}
			if(now.left!=null&&now.right==null){
				root=now.left;
				return;
			}
			if(now.left==null&&now.right!=null){
				root=now.right;
				return;
			}
			if(now.left!=null&&now.right!=null){
				TreeNode mostLeft=now.right;
				TreeNode mostLeftParent=now;
				while(mostLeft.left!=null){
					mostLeftParent=mostLeft;
					mostLeft=mostLeft.left;		
				}
				if(mostLeft==now.right){					
					now.right.left=root.left;	
					root=now.right;	
					return;
				}
				else{					
					mostLeftParent.left=mostLeft.right;
					root=mostLeft;
					mostLeft.right=now.right;
					mostLeft.left=now.left;
					return;
				}
				
			}
			
		}				
		//如果now没有左右子节点,则parent的子节点为null,根据isLeft判断now是parent的左右节点
		if(now.left==null&&now.right==null){
			if(isLeft){
				parent.left=null;
				return;
			}
			else{
				parent.right=null;
				return;
			}
		}
		//如果now只有左节点,则根据isleft parent的左右节点为now.left
		if(now.left!=null&&now.right==null){
			if(isLeft){
				parent.left=now.left;
				return;
			}
			else{
				parent.right=now.left;
				return;
			}
		}
		//如果now只有右节点,则根据isleft parent的左右节点为now.right
		if(now.left==null&&now.right!=null){
			if(isLeft){
				parent.left=now.right;
				return;
			}
			else{
				parent.right=now.right;
				return;
			}
		}
		//如果now左右节点都有,则根据isleft parent的左右节点为now的右节点的最左边的那个mostLeft
		//相当于把mostLeft替换掉now
		if(now.left!=null&&now.right!=null){
			TreeNode mostLeft=now.right;
			TreeNode mostLeftParent=now;
			while(mostLeft.left!=null){
				mostLeftParent=mostLeft;
				mostLeft=mostLeft.left;		
			}
			if(mostLeft==now.right){
				if(isLeft){
					parent.left=now.right;
				}
				else{
					parent.right=now.right;
				}
				now.right.left=now.left;				
			}
			else{
				mostLeftParent.left=mostLeft.right;
				if(isLeft){
					parent.left=mostLeft;
				}
				else{
					parent.right=mostLeft;
				}
				mostLeft.right=now.right;
				mostLeft.left=now.left;
			}
			
		}				
	}
	
	
	//递归
	public static void preOrder(TreeNode root){
		if(root==null){
			return;
		}
		System.out.print(root.val+" ");
		preOrder(root.left);
		preOrder(root.right);
	}
	
	public static void inOrder(TreeNode root){
		if(root==null){
			return;
		}
		inOrder(root.left);
		System.out.print(root.val+" ");
		inOrder(root.right);
	}
	
	public static void postOrder(TreeNode root){
		if(root==null){
			return;
		}
		postOrder(root.left);
		postOrder(root.right);
		System.out.print(root.val+" ");
	}
	//通过队列 当前下层节点个数 打印每层的节点和null
	public static void printTree(TreeNode root){
        if(root == null)
            return;
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        
        int current;//当前层 还未打印的结点个数
        int next;//下一层结点个数
        
        queue.offer(root);
        current = 1;
        next = 0;
        while(!queue.isEmpty()){
            TreeNode currentNode = queue.poll();
            if (currentNode!=null) {
            	System.out.print(currentNode.val+" ");
                current--;
               
			}
            else{
            	System.out.print("null ");
            	 current--;
            	 queue.offer(null);
                 next++;
                 queue.offer(null);
                 next++;                
                 if(current ==0){
                     System.out.println();
                     current = next;
                     next = 0;
                     int temp=0;
                     for (TreeNode treeNode : queue) {
						if(treeNode==null){
							temp++;
						}
					}
                     if(temp==current){
                    	 System.out.println("end");
                         break;
                     }
                     
                 }
                continue;
            }
            
            if(currentNode.left != null){
                queue.offer(currentNode.left);
                next++;
            }
            else{
            	queue.offer(null);
                next++;
            }
            if(currentNode.right != null){
                queue.offer(currentNode.right);
                next++;
            }
            else{
            	queue.offer(null);
                next++;
            }
            if(current ==0){
                System.out.println();
                current = next;
                next = 0;
                int temp=0;
                for (TreeNode treeNode : queue) {
					if(treeNode==null){
						temp++;
					}
				}
                if(temp==current){
               	 System.out.println("end");
                    break;
                }
                
            }
            
        }
    }
	
	//宽度优先遍历 是简化的按层遍历,没有了current和next和打印null
	public static void breadthFirstSearch(TreeNode root){
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		if(root==null){
			return;
		}
		queue.offer(root);
		while(!queue.isEmpty()){
			TreeNode now=queue.poll();
			System.out.print(now.val+" ");
			if(now.left!=null){
				queue.offer(now.left);
			}
			if(now.right!=null){
				queue.offer(now.right);
			}
		}
		System.out.println();
	}

	//深度优先遍历
	//用栈 弹出自身 先加入右节点 再加入左节点,这样先弹出左节点,左节点的左右子节点又塞进去,在原右节点上面
	public static void depthFirstSearch(TreeNode root){
		Stack<TreeNode> stack=new Stack<TreeNode>();
		if(root==null){
			return;
		}
		stack.push(root);
		while(!stack.isEmpty()){
			TreeNode now=stack.pop();
			System.out.print(now.val+" ");
			if(now.right!=null){
				stack.push(now.right);
			}
			if(now.left!=null){
				stack.push(now.left);
			}
			
		}
		System.out.println();
	}
	
	
	
	
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值