数据结构 二叉查找树

数据结构 二叉查找树

Eclipse java 工程:
demo: http://download.csdn.net/detail/keen_zuxwang/9877670

数组:有序的通过二分查找
链表:查找要从头开始,只有知道了前一个元素的地址才能知道下一个地址
二叉排序树(Binary Sort Tree):
又称为二叉查找树,它或者是一棵空树,或者是具有下列性质的二叉树:
对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X.
它的左、右子树也分别为二叉排序树(递归),二叉查找树所有的节点都可以进行排序

二叉查找树是java的TreeSet和TreeMap类实现的基础.
由于树的递归定义,二叉查找树的代码实现也基本上都是使用递归的函数,二叉查找树的平均深度是O(logN).

因为二叉查找树要求所有的节点都可以进行排序.所以编写时代码时需要一个Comparable泛型接口,当需要对类中的对象进行排序的时候,就需要实现这个泛型接口,
里边定义了一个public int compareTo(Object o)方法, 接受一个Object作为参数,java中String,Integer等类都实现了这个接口.

二叉搜索树的描述主要从查询节点、添加节点、遍历、最大值、最小值、删除节点来描述

广度优先遍历(Breadth-first traversal)、深度优先遍历(Depth-first Traversal)
深度优先遍历又分为:
前序遍历(Preorder Traversal)
Parent->Childl->Childr

后序遍历(Postorder Traversal)
Childl->Childr->Parent

中序遍历(Inorder Traversal)(中序遍历只有对二叉树才有意义)
Childl->Parent->Childr

深度优先遍历—>栈
广度优先遍历—>队列(利用队列的fifo特性,完成二叉树的入队、出队)

remove方法:
1、被删除节点是树叶节点,直接删除,将该节点置为null即可
2、被删除节点有一个子节点(左子树或右子树): 是该节点的父节点指向该节点的子节点(左或右)
3、被删除节点有两个子节点: 用其右子树中的最小值代替该节点上的值,删除其右子树上的最小值

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Stack;

import mybinarytree.BinaryTree0.TreeNode;

public class BinaryTree {
    static class TreeNode {  
        public int keyValue;    //关键字值  
        public TreeNode leftNode;//左节点  
        public TreeNode rightNode;//右节点  

        public TreeNode(){}  
        public TreeNode(int Key){  
            this.keyValue = Key;  
        }  
    }

    public TreeNode root;// 根节点

    //查找集合中是否有元素value,有返回true
    public boolean search(int value){ 
        return search(value,root);
    }

    // 查找节点
    private boolean search(int value, TreeNode t) {
        if(t==null){
            return false;
        }
        Integer ivalue = new Integer(value);
        int result = ivalue.compareTo(t.keyValue);
        if(result<0){
            return search(value,t.leftNode);
        }else if(result>0){
            return search(value,t.rightNode);
        }else{
            return true;
        }
    }

    // 添加节点
    public void insert0(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;
                    }
                }
            }
        }
    }

    //插入元素
    public void insert(int value){       
        root =insert(value,root);
    }

    private TreeNode insert(int value, TreeNode t) {
        if(t==null){
            return new TreeNode(value);
        }
        Integer ivalue = new Integer(value);
        int result=ivalue.compareTo(t.keyValue);
        if(result<0){
            t.leftNode = insert(value,t.leftNode);
        }else if(result>0){
            t.rightNode = insert(value,t.rightNode);
        }
        return t;    
    }

    //获取最大深度
    public int getMaxDepth(){
        return getMaxDepth(root);
    }

    private int getMaxDepth(TreeNode root) {    
        if (root == null)
            return 0;
        else {
            int left = getMaxDepth(root.leftNode);
            int right = getMaxDepth(root.rightNode);
            return Math.max(left, right)+1;
        }
    }

    // 获取最大宽度 
    public int getMaxWidth() {
        return getMaxWidth(root);
    }

    // 上一层遍历完成后,下一层的所有节点已经放到队列中,此时队列中的元素个数就是下一层的宽度
    private int getMaxWidth(TreeNode root) {
        if (root == null)
            return 0;

        Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
        int layer = 0;
        int maxWitdth = 1; // 最大宽度
        queue.add(root); // 入队

        while (true) {
            int len = queue.size(); // 当前层的节点个数
            if (len == 0)
                break;
            layer++;
            System.out.print("\n第"+layer+"层, sum = "+queue.size()+":  ");  

            while (len > 0) {// 如果当前层,还有节点
                TreeNode t = queue.poll();
                System.out.print(t.keyValue+"  "); 
                len--;
                if (t.leftNode != null)
                    queue.add(t.leftNode); // 下一层节点入队
                if (t.rightNode != null)
                    queue.add(t.rightNode);// 下一层节点入队
            }
            maxWitdth = Math.max(maxWitdth, queue.size());
        }
        System.out.print("\n");
        return maxWitdth;
    }

    //节点个数  
    public int size(){  
        return size(root);  
    }  

    private int size(TreeNode t){  
        if(t==null){  
            return 0;  
        }else{  
            return 1+size(t.leftNode)+size(t.rightNode);  
        }  
    }  

    // 中序遍历树: 递归
    public void display() {
        display(root);
    }   

    // 中序遍历树
    private void display(TreeNode node) {
        if (node != null) {
            display(node.leftNode);
            System.out.print(node.keyValue + "  ");
            display(node.rightNode);
        }
    }

    //深度优先遍历: 中序, 需要辅助数据结构:栈  (栈的LIFO特性)
    public void InOrder(){
        InOrder(root);
    }

    //中序遍历的非递归实现  
    private void InOrder(TreeNode p){  
        ArrayDeque<TreeNode> stack =new ArrayDeque<TreeNode>();  
        TreeNode node =p;  
        while(node!=null||stack.size()>0){  
            //存在左子树  
            while(node!=null){  
                stack.push(node);  
                node=node.leftNode;  
            }  
            //栈非空  
            if(stack.size()>0){  
                node=stack.pop();  
                System.out.print(node.keyValue+"  "); 
                node=node.rightNode;  
            }  
        }  
    }  

    //广度优先遍历(层次遍历) ,需要辅助数据结构:队列 (利用队列的FIFO特性)
    public void levelTraversal(){  
        if(root==null){  
            System.out.println("empty tree");  
            return;  
        }  
        ArrayDeque<TreeNode> queue=new ArrayDeque<TreeNode>();  
        queue.offer(root); //或queue.offer()
        while(queue.isEmpty()==false){  
            TreeNode node=queue.poll();  
            System.out.print(node.keyValue+"  ");  
            if(node.leftNode!=null){  
                queue.offer(node.leftNode);  
            }  
            if(node.rightNode!=null){  
                queue.offer(node.rightNode);  
            } 
        }  
        System.out.print("\n");  
    }

    // 最大值
    public int findMax() {
        TreeNode node = root;
        TreeNode parent = null;
        while (node != null) {
            parent = node;
            node = node.rightNode;
        }
        return parent.keyValue;
    }

    // 最小值
    public int findMin() {
        return findMin(root).keyValue;  
    }

    // 最小值
    private TreeNode findMin(TreeNode root) {
        TreeNode node = root;
        TreeNode parent = null;
        while (node != null) {
            parent = node;
            node = node.leftNode;
        }
        return parent;
    }

    // 删除节点分三种方式删除节点
    // 1、删除没有子节点的节点,直接让该节点的父节点的左节点或右节点指向空
    // 2、删除有一个子节点的节点,直接让该节点的父节点指向被删除节点的剩余节点
    // 3、删除有三个节点的子节点,找到要删除节点的后继节点, 用该节点替代删除的节点
    public boolean delete(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;
    }

    //移除元素
    public void remove(int value){
        root=remove(root, value);
    }

    private TreeNode remove(TreeNode t, int value) {
        if(t==null){
            return t;
        }
        Integer ivalue = new Integer(value);
        //Integer tvalue = new Integer(t.keyValue);

        int result = ivalue.compareTo(t.keyValue);//value.compareTo(t.keyValue);

        if(result<0){
            t.leftNode=remove(t.leftNode,value);
        }else if(result>0){
            t.rightNode = remove(t.rightNode, value);
        }else if(t.leftNode!=null&&t.rightNode!=null){//如果被删除节点有两个儿子
            //1.当前节点值被其右子树的最小值代替
            t.keyValue = findMin(t.rightNode).keyValue;
            //将右子树的最小值删除
            t.rightNode=remove(t.rightNode, t.keyValue);
        }else{
            //如果被删除节点是一个叶子 或只有一个儿子
            t=(t.leftNode!=null)?t.leftNode:t.rightNode;
        }

        return t;
    }

    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;
    }

    public static void main(String[] args) {  
        BinaryTree bst=new BinaryTree(); //Integer

        bst.insert(5);
        bst.insert(7);
        bst.insert(3);
        bst.insert(1);
        bst.insert(9);
        bst.insert(6);
        bst.insert(4);

        System.out.print("二叉树深度\n"); 
        System.out.print(bst.getMaxDepth());

        System.out.print("\n");  
        System.out.print("二叉树宽度"); 
        System.out.print(bst.getMaxWidth());
        System.out.print("\n"); 

        System.out.print("\n");  
        System.out.print("二叉树大小:"); 
        System.out.print(bst.size());
        System.out.print("\n");  

        System.out.println("最大值:"+bst.findMax());
        System.out.println("最小值:"+bst.findMin());

        System.out.print("\n");
        System.out.println("中根遍历二叉树");
        bst.display();

        System.out.print("\n");
        System.out.println("查找元素9是否存在: "+bst.search(9));
        System.out.println("移除元素9");
        bst.remove(9);
        System.out.println("查找元素9是否存在: "+bst.search(9));

        System.out.print("\n\n");
        System.out.println("中根遍历二叉树");
        bst.display();

        System.out.print("\n\n");
        System.out.println("中根遍历二叉树、非递归");
        bst.InOrder();

        System.out.print("\n\n");
        System.out.println("广度优先遍历遍历");
        bst.levelTraversal();    
    }
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值