zoukankan      html  css  js  c++  java
  • 数据结构实现(四)二叉查找树java实现

    转载 http://www.cnblogs.com/CherishFX/p/4625382.html

    二叉查找树的定义:

      二叉查找树或者是一颗空树,或者是一颗具有以下特性的非空二叉树:

        1. 若左子树非空,则左子树上所有节点关键字值均小于根节点的关键字;

        2. 若右子树非空,则右子树上所有节点关键字值均大于根节点的关键字;

        3. 左、右子树本身也分别是一颗二叉查找树。

    二叉查找树的实现,功能有:

      1. 用一个数组去构建二叉查找树

      2. 二叉查找树的中序遍历和层次遍历

      3. 插入节点

      4. 查找节点

          5. 查找二叉树中的最大值和最小值

      6.  得到节点的直接父节点

      7. 得到节点的直接前驱和直接后继节点

      8. 删除节点

    package dataStructures;
    
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.Scanner;
    import java.util.Stack;
    
    public class BinarySearchTree {
        private TreeNode<Integer> root = null; // 根节点
    
        public BinarySearchTree() {
        }
    
        // 用一个数组去构建二叉查找树
        public TreeNode<Integer> buildBST(Integer[] array) {
            if (array.length == 0) {
                return null;
            } else {
                root = null; // 初始化树为空树
                for (int i = 0; i < array.length; i++) { // 依次将每个元素插入
                    root = insertNode(root, array[i]);
                }
                return root;
            }
        }
    
        // 在二叉查找树中插入一个数据域为data的结点,新插入的结点一定是某个叶子节点
        private TreeNode<Integer> insertNode(TreeNode<Integer> node, Integer data) {
            if (node == null) { // 原树为空,新插入的记录为根节点
                node = new TreeNode<Integer>(data, null, null);
            } else {
                if (node.data != data) { // 树中不存在相同关键字的结点
                    if (node.data > data) { // 根节点>插入数据,插入到左子树中
                        node.lchild = insertNode(node.lchild, data);
                    } else { // 根节点<插入数据,插入到右子树中
                        node.rchild = insertNode(node.rchild, data);
                    }
                }
            }
            return node;
        }
    
        // 二叉查找树的中序遍历,可以得到一个递增的有序数列
        public void inOrder(TreeNode<Integer> node) {
            if (node != null) {
                inOrder(node.lchild);
                System.out.print(node.data + " ");
                inOrder(node.rchild);
            }
        }
    
        // 二叉查找树的层次遍历
        public void levelOrder(TreeNode<Integer> root) {
            Queue<TreeNode<Integer>> nodeQueue = new LinkedList<TreeNode<Integer>>();
            TreeNode<Integer> node = null;
            nodeQueue.add(root); // 将根节点入队
            while (!nodeQueue.isEmpty()) { // 队列不空循环
                node = nodeQueue.peek();
                System.out.print(node.data + " ");
                nodeQueue.poll(); // 队头元素出队
                if (node.lchild != null) { // 左子树不空,则左子树入队列
                    nodeQueue.add(node.lchild);
                }
                if (node.rchild != null) { // 右子树不空,则右子树入队列
                    nodeQueue.add(node.rchild);
                }
            }
        }
    
        // 查找数据域为data的结点,若不存在,返回null
        public TreeNode<Integer> searchNode(TreeNode<Integer> node, Integer data) {
            while (node != null && node.data != data) {
                if (node.data > data) {
                    node = node.lchild; // 根节点>数据,向左走
                } else {
                    node = node.rchild; // 根节点<数据,向右走
                }
            }
            return node;
        }
    
        // 查找最大值:不断地寻找右子节点
        public TreeNode<Integer> getMaxData(TreeNode<Integer> node) {
            if (node.rchild == null) {
                return node;
            } else {
                return getMaxData(node.rchild);
            }
        }
    
        // 查找最小值:不断地寻找左子节点
        public TreeNode<Integer> getMinData(TreeNode<Integer> node) {
            if (node.lchild == null) {
                return node;
            } else {
                return getMinData(node.lchild);
            }
        }
    
        // 得到数据域为data的结点的直接父节点parentNode
        public TreeNode<Integer> getParentNode(TreeNode<Integer> root, Integer data) {
            TreeNode<Integer> parentNode = root;
            if (parentNode.data == data) { // 根节点的父节点返回为null
                return null;
            }
            while (parentNode != null) {
                // 查找当前节点的父节点的左右子节点,若是相等,则返回该父节点
                if ((parentNode.lchild != null && parentNode.lchild.data == data)
                        || (parentNode.rchild != null && parentNode.rchild.data == data)) {
                    return parentNode;
                } else {
                    if (parentNode.data > data) { // 向左查找父节点
                        parentNode = parentNode.lchild;
                    } else {
                        parentNode = parentNode.rchild; // 向右查找父节点
                    }
                }
            }
            return null;
        }
    
        /**
         * 得到结点node的直接前趋 a.该节点左子树不为空:其前驱节点为其左子树的最大元素
         * b.该节点左子树为空:其前驱节点为其祖先节点(递归),且该祖先节点的右孩子也为其祖先节点 (就是一直往其parent找,出现左拐后的那个祖先节点)
         */
        public TreeNode<Integer> getPrecessor(TreeNode<Integer> root, TreeNode<Integer> node) {
            if (node == null) {
                return null;
            }
            // a.该节点左子树不为空:其前驱节点为其左子树的最大元素
            if (node.lchild != null) {
                return getMaxData(node.lchild);
            } else { // b.该节点左子树为空: 其前驱节点为其祖先节点(递归)
                TreeNode<Integer> parentNode = getParentNode(root, node.data);
                while (parentNode != null && node == parentNode.lchild) {
                    node = parentNode;
                    parentNode = getParentNode(root, parentNode.data);
                }
                return parentNode;
            }
        }
    
        /**
         * 得到结点node的直接后继(后继节点就是比要删除的节点的关键值要大的节点集合中的最小值) a.该节点右子树不为空,其后继节点为其右子树的最小元素
         * b.该节点右子树为空,则其后继节点为其祖先节点(递归),且此祖先节点的左孩子也是该节点的祖先节点,
         * 就是说一直往上找其祖先节点,直到出现右拐后的那个祖先节点:
         */
        public TreeNode<Integer> getSuccessor(TreeNode<Integer> root, TreeNode<Integer> node) {
            if (node == null) {
                return null;
            }
            // a.该节点右子树不为空,其后继节点为其右子树的最小元素
            if (node.rchild != null) {
                return getMinData(node.rchild);
            } else { // b.该节点右子树为空,则其后继节点为其最高祖先节点(递归)
                TreeNode<Integer> parentNode = getParentNode(root, node.data);
                while (parentNode != null && node == parentNode.rchild) {
                    node = parentNode;
                    parentNode = getParentNode(root, parentNode.data);
                }
                return parentNode;
            }
        }
    
        /**
         * 删除数据域为data的结点 按三种情况处理: a.如果被删除结点z是叶子节点,则直接删除,不会破坏二叉查找树的性质
         * b.如果节点z只有一颗左子树或右子树,则让z的子树成为z父节点的子树,代替z的位置
         * c.若结点z有左、右两颗子树,则令z的直接后继(或直接前驱)替代z,
         * 然后从二叉查找树中删去这个直接后继(或直接前驱),这样就转换为第一或第二种情况
         * 
         * @param node
         *            二叉查找树的根节点
         * @param data
         *            需要删除的结点的数据域
         * @return
         */
        public boolean deleteNode(TreeNode<Integer> node, Integer data) {
            if (node == null) { // 树为空
                throw new RuntimeException("树为空!");
            }
            TreeNode<Integer> delNode = searchNode(node, data); // 搜索需要删除的结点
            TreeNode<Integer> parent = null;
            if (delNode == null) { // 如果树中不存在要删除的关键字
                throw new RuntimeException("树中不存在要删除的关键字!");
            } else {
                parent = getParentNode(node, data); // 得到删除节点的直接父节点
                // a.如果被删除结点z是叶子节点,则直接删除,不会破坏二叉查找树的性质
                if (delNode.lchild == null && delNode.rchild == null) {
                    if (delNode == parent.lchild) { // 被删除节点为其父节点的左孩子
                        parent.lchild = null;
                    } else { // 被删除节点为其父节点的右孩子
                        parent.rchild = null;
                    }
                    return true;
                }
                // b1.如果节点z只有一颗左子树,则让z的子树成为z父节点的子树,代替z的位置
                if (delNode.lchild != null && delNode.rchild == null) {
                    if (delNode == parent.lchild) { // 被删除节点为其父节点的左孩子
                        parent.lchild = delNode.lchild;
                    } else { // 被删除节点为其父节点的右孩子
                        parent.rchild = delNode.lchild;
                    }
                    delNode.lchild = null; // 设置被删除结点的左孩子为null
                    return true;
                }
                // b2.如果节点z只有一颗右子树,则让z的子树成为z父节点的子树,代替z的位置
                if (delNode.lchild == null && delNode.rchild != null) {
                    if (delNode == parent.lchild) { // 被删除节点为其父节点的左孩子
                        parent.lchild = delNode.rchild;
                    } else { // 被删除节点为其父节点的右孩子
                        parent.rchild = delNode.rchild;
                    }
                    delNode.rchild = null; // 设置被删除结点的右孩子为null
                    return true;
                }
                // c.若结点z有左、右两颗子树,则删除该结点的后继结点,并用该后继结点取代该结点
                if (delNode.lchild != null && delNode.rchild != null) {
                    TreeNode<Integer> successorNode = getSuccessor(node, delNode); // 得到被删除结点的后继节点
                    deleteNode(node, successorNode.data); // 删除该结点的后继结点
                    delNode.data = successorNode.data; // 用该后继结点取代该结点
                    return true;
                }
            }
            return false;
    
        }
    
        /**
         * 某些方法的非递归实现 1. 插入节点insertNode(): 2. 二叉查找树的中序遍历: 3. 得到二叉查找树的最大值和最小值:
         */
        // 1. 在二叉查找树中插入一个数据域为data的结点,新插入的结点一定是某个叶子节点
        public TreeNode<Integer> insertNode2(TreeNode<Integer> node, Integer data) {
            TreeNode<Integer> newNode = new TreeNode<Integer>(data, null, null);
            TreeNode<Integer> tmpNode = node; // 遍历节点
            TreeNode<Integer> pnode = null; // 记录当前节点的父节点
    
            if (node == null) { // 原树为空,新插入的记录为根节点
                node = newNode;
                return node;
            }
            while (tmpNode != null) {
                pnode = tmpNode;
                if (tmpNode.data == data) { // 树中存在相同关键字的结点,什么也不做
                    return node;
                } else {
                    if (tmpNode.data > data) { // 根节点>插入数据,插入到左子树中
                        tmpNode = tmpNode.lchild;
                    } else { // 根节点<插入数据,插入到右子树中
                        tmpNode = tmpNode.rchild;
                    }
                }
            }
            if (pnode.data > data) {
                pnode.lchild = newNode;
            } else {
                pnode.rchild = newNode;
            }
            return node;
        }
    
        // 2. 二叉查找树的中序遍历LNR,可以得到一个递增的有序数列
        public void inOrder2(TreeNode<Integer> node) {
            Stack<TreeNode<Integer>> nodeStack = new Stack<TreeNode<Integer>>();
            TreeNode<Integer> tempNode = node; // 遍历指针
            while (tempNode != null || !nodeStack.isEmpty()) {
                if (tempNode != null) {
                    nodeStack.push(tempNode);
                    tempNode = tempNode.lchild;
                } else {
                    tempNode = nodeStack.pop();
                    System.out.print(tempNode.data + " ");
                    tempNode = tempNode.rchild;
                }
            }
        }
    
        // 3.1 查找最大值:不断地寻找右子节点
        public TreeNode<Integer> getMaxData2(TreeNode<Integer> node) {
            TreeNode<Integer> tempNode = node;
            while (tempNode.rchild != null) {
                tempNode = tempNode.rchild;
            }
            return tempNode;
        }
    
        // 3.2 查找最小值:不断地寻找左子节点
        public TreeNode<Integer> getMinData2(TreeNode<Integer> node) {
            TreeNode<Integer> tempNode = node;
            while (tempNode.lchild != null) {
                tempNode = tempNode.lchild;
            }
            return tempNode;
        }
    
        public static void main(String[] args) {
            Integer[] array = { 8, 3, 10, 1, 6, 14, 4, 7, 13 };
            BinarySearchTree bst = new BinarySearchTree();
            TreeNode<Integer> root = bst.buildBST(array);
            System.out.print("层次遍历:");
            bst.levelOrder(root);
    
            System.out.print("
    " + "中序遍历:");
            bst.inOrder(root);
    
            System.out.println();
            System.out.print("得到最大值:");
            System.out.println(bst.getMaxData(root).data);
            System.out.print("得到最小值:");
            System.out.println(bst.getMinData(root).data);
    
            System.out.print("向二叉查找树中插入一个节点,请输入需插入节点的数据域:");
            Scanner input = new Scanner(System.in);
            int data = input.nextInt();
            System.out.print("插入节点" + data + "后,中序遍历的结果:");
            root = bst.insertNode(root, data);
            bst.inOrder(root);
    
            System.out.println("
    " + "在二叉查找树中查找元素," + "请输入需要查找的结点值:");
            data = input.nextInt();
            if (bst.searchNode(root, data) == null) {
                System.out.println("false");
            } else {
                System.out.println("true");
            }
    
            System.out.println("查找节点的直接父节点," + "请输入需要查找的结点值:");
            data = input.nextInt();
            System.out.print("节点" + data + "的父节点是:");
            if (bst.getParentNode(root, data) == null) {
                System.out.println("null");
            } else {
                System.out.println(bst.getParentNode(root, data).data);
            }
    
            System.out.println("删除结点," + "请输入需要删除的结点值:");
            data = input.nextInt();
            if (bst.deleteNode(root, data)) {
                System.out.print("删除结点后的层次遍历:");
                bst.levelOrder(root);
                System.out.print("
    " + "删除结点后的中序遍历:");
                bst.inOrder(root);
            }
    
        }
    
    }

    逻辑图

  • 相关阅读:
    mysql零碎问题合集
    mysql 纵表转横表 需要用join不能直接where连接
    eclipse导出可执行jar包 报main function not found错误
    shell脚本将mysql查询结果制作成csv格式
    linux shell中把句子中的单词提取作为变量值 主要是使用了数组
    linux下文件字符编码转换
    Banner使用
    recyclerview的博客网址需要的权限
    okhttp权限
    Okhttp代码
  • 原文地址:https://www.cnblogs.com/xdyixia/p/9212532.html
Copyright © 2011-2022 走看看