zoukankan      html  css  js  c++  java
  • 二叉查找树



    1. 定义(Binary Sort Tree)

    • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值
    • 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值
    • 任意节点的左、右子树也分别为二叉查找树
    • 没有键值相等的节点

    简单来说:任意节点的根比左子树大,比右子树小,O(log2(n))



    2. 节点

    private class Node{
    	
    	//维护的键值对,应该用泛型的,这里为了方便你懂的
    	public int key;
    	public int value;
    	
    	//左右节点
    	public Node left;
    	public Node right;
    
    	public Node(int key, int value) {
    		this.key = key;
    		this.value = value;
    	}
    }
    


    3. 遍历

    public void preOrder(){
    	preOrder(root);
    }
    /**
     * @param node 根据该节点往下遍历
     */
    private void preOrder(Node node){
    	if(node != null){
    		System.out.println(node.value);
    		preOrder(node.left);
    		preOrder(node.right);
    	}
    }
    


    4. 查找

    最先判断节点是否为空,再考虑大于小于,最后才考虑等于

    public Node get(int key){
    	
    	//最先判断节点是否为空,再考虑大于小于,最后才考虑等于
    	Node node = root;
    	while(node != null){
    		if(key > node.key){
    			node = node.right;
    		}else if(key < node.key){
    			node = node.left;
    		}else {
    			return node;
    		}
    	}
    	return null;
    }
    


    5. 插入

    public void add(int key,int value){
    	Node node = root;
    	//树为空时,要初始化设置根结点
    	if(node == null){
    		root = new Node(key,value);
    		return ;
    	}
    	while(node != null){
    		//往右移
    		if(key > node.key){
                //当右子树为空时,即插入
    			if(node.right == null){
    				node.right = new Node(key,value);
    				return ;
    			}else{
    				node = node.right;
    			}
    		//往左移
    		}else if(key < node.key){
    			if(node.left == null){
    				node.left = new Node(key,value);
    				return ;
    			}else{
    				node = node.left;
    			}
    		//相等替换
    		}else{
    			node.value = value;
    			return ;
    		}
    	}
    }
    


    6. 最值及节点

    二叉查找树的最左节点为最小值,最右为最大值

    public int max(){
    	Node node = max(root);
    	return node.value;
    }
    private Node max(Node node){
    	while(node.right != null){
    		node = node.right;
    	}
    	return node;
    }
    public int min(){
    	Node node = min(root);
    	return node.value;
    }
    private Node min(Node node){
    	while(node.left != null){
    		node = node.left;
    	}
    	return node;
    }
    
    
    /**
     * 删除最小节点
     */
    private Node DelMin(Node node){
        if(node.left == null){
        	return node.right;
        }
        node.left = DelMin(node.left);
        return node;
    }
    


    7. 删除

    删除节点分三种情况

    • 被删节点没有子树(直接删除)
    • 被删节点只有一个子树(孩子节点替换父节点)
    • 被删节点有左右子树(看图)
    public Node delete(int key){
    	return delete(root, key);
    }
    private Node delete(Node node,int key){
    	if(key > node.key){
    		node.right = delete(node.right,key);
    	}else if(key < node.key){
    		node.left = delete(node.left,key);
    	}else{
    		//当被删节点不多于一个子树时
    		if(node.left == null){
    			return node.right;
    		}else if(node.right == null){
    			return node.left;
    		}else{
                //被删节点有左右子树
                //保存被删节点到临时变量
    			Node temp = node;
    			//找到被删节点的右子树中最小的节点,替换原来的节点
    			node = min(temp.right);
    			//看图更易理解
    			node.right = DelMin(temp.right);
    			//搞定左子树
    			node.left = temp.left;
    		}
    	}
    	return node;
    }
    

    假如B为被删节点,步骤:

    • 保存被删节点B到临时变量temp
    • 用B右子树的最小节点G来替换B
    • 用G右子树来代替E左子树
    • 把G的左子树代替为B的左子树


    8. 整体代码

    /**
     * 二叉查找树的实现
     * @author Howl
     * @version 0.0.1
     * @date 20/1/13
     */
    public class BinarySearchTree {
    	
    	
    	//维护一个根结点,与遍历相关的功能都需用到
    	private Node root;
    	
    	
    	
    	/**
    	 * 内部节点类
    	 * @author Howl
    	 */
    	private class Node{
    		
    		//维护的键值对,应该用泛型的,这里为了方便你懂的
    		public int key;
    		public int value;
    		
    		//左右节点
    		public Node left;
    		public Node right;
    
    		public Node(int key, int value) {
    			this.key = key;
    			this.value = value;
    		}
    	}
    	
    	
    	
    	/**
    	 * 先序遍历
    	 */
    	public void preOrder(){
    		preOrder(root);
    	}
    	/**
    	 * @param node 根据该节点往下遍历
    	 */
    	private void preOrder(Node node){
    		if(node != null){
    			System.out.println(node.value);
    			preOrder(node.left);
    			preOrder(node.right);
    		}
    	}
    	
    	
    	
    	/**
    	 * @param key 根据key来查找
    	 * @return 返回key对应的节点,没有就返回null
    	 */
    	public Node get(int key){
    		
    		//最先判断节点是否为空,再考虑大于小于,最后才考虑等于
    		Node node = root;
    		while(node != null){
    			if(key > node.key){
    				node = node.right;
    			}else if(key < node.key){
    				node = node.left;
    			}else {
    				return node;
    			}
    		}
    		return null;
    	}
    	
    	
    
    	/**
    	 * 添加节点
    	 * @param key 键
    	 * @param value 值
    	 * @return 
    	 */
    	public void add(int key,int value){
    		Node node = root;
    		//树为空时,要初始化设置根结点
    		if(node == null){
    			root = new Node(key,value);
    			return ;
    		}
    		while(node != null){
    			//往右移
    			if(key > node.key){
    				if(node.right == null){
    					node.right = new Node(key,value);
    					return ;
    				}else{
    					node = node.right;
    				}
    			//往左移
    			}else if(key < node.key){
    				if(node.left == null){
    					node.left = new Node(key,value);
    					return ;
    				}else{
    					node = node.left;
    				}
    			//相等替换
    			}else{
    				node.value = value;
    				return ;
    			}
    		}
    	}
    	
    	
    	
    	/**
    	 * 查找最值
    	 * @return 最值
    	 */
    	public int max(){
    		Node node = max(root);
    		return node.value;
    	}
    	/**
    	 * 查找最值的节点
    	 * @param node 从该节点开始查找
    	 * @return 返回最值对应的节点
    	 */
    	private Node max(Node node){
    		while(node.right != null){
    			node = node.right;
    		}
    		return node;
    	}
    	public int min(){
    		Node node = min(root);
    		return node.value;
    	}
    	private Node min(Node node){
    		while(node.left != null){
    			node = node.left;
    		}
    		return node;
    	}
    	/**
    	 * 删除最小节点
    	 */
    	private Node DelMin(Node node){
    	    if(node.left == null){
    	    	return node.right;
    	    }
    	    node.left = DelMin(node.left);
    	    return node;
    	}
    	
    	
    	/**
    	 * 删除节点
    	 * @param key 根据key来删除
    	 * @return 被删除的节点
    	 */
    	public Node delete(int key){
    		return delete(root, key);
    	}
    	private Node delete(Node node,int key){
    		if(key > node.key){
    			node.right = delete(node.right,key);
    		}else if(key < node.key){
    			node.left = delete(node.left,key);
    		}else{
    			//找到需要删的节点
    			if(node.left == null){
    				return node.right;
    			}else if(node.right == null){
    				return node.left;
    			}else{
    				Node temp = node;
    				//找到右子树最小的节点,替换原来的节点
    				node = min(temp.right);
    				//
    				node.right = DelMin(temp.right);
    				//搞定左子树
    				node.left = temp.left;
    			}
    		}
    		return node;
    	}
    }
    


    9. 测试

    public static void main(String[] args) {
    	BinarySearchTree bst = new BinarySearchTree();
    	
    	int[] arrs = {12,10,13,8,11,7,9};
    	
    	for (int arr : arrs){
    		bst.add(arr, arr);
    	}
    	bst.delete(8);
    	bst.delete(13);
    	bst.preOrder();
    }
    
    12
    10
    9
    7
    11
    


  • 相关阅读:
    紫书 习题2-4 子序列的和
    紫书 习题2-3 倒三角形
    HDU 1013 Digital Roots(字符串,大数,九余数定理)
    HDU 1308 What Day Is It?(模拟,日期)
    ACM数论-欧几里得与拓展欧几里得算法
    今日计划
    UVA 10340 All in All(字符串,朴素匹配)
    ACM-字符串
    Codeforces Round #424 B. Keyboard Layouts(字符串,匹配,map)
    Codeforces Round #424 A(模拟)
  • 原文地址:https://www.cnblogs.com/Howlet/p/12188436.html
Copyright © 2011-2022 走看看