首页 > 其他 > 详细

数据结构学习笔记4.5--二叉树效率

时间:2014-02-13 14:31:46      阅读:517      评论:0      收藏:0      [点我收藏+]

之前的第4部分提到了二叉搜索树的查找,插入,删除操作,那二叉树的效率如何呢?

在一个满树中,大约有一半的节点在最低层,因此,查找、插入、删除节点的操作大约有一半都需要找到最低层的节点。

按照满树的计算方法,树的操作复杂度为O(logN)。但是遍历树相对来说要慢上许多,因此,如果不涉及到遍历操作的,二叉搜索树是一种很多好的数据结构。

 

二叉树完整代码:包含查找,插入,删除,遍历操作。

bubuko.com,布布扣
package Charp04.BinaryTree;

import java.util.Stack;

public class Tree
{
    /*
     * 根节点
     */
    private Node root;

    /**
     * 构造函数
     */
    public Tree()
    {
        root = null;
    }

    /**
     * 查找节点
     * 
     * @param key 输入key值
     * @return 返回节点值
     */
    public Node find(int key)
    {
        // 当前节点,相当于一个指针,引用会随着查找变化
        Node current = root;

        // 遍历查询节点
        // 查找方法:根据二叉树的特点,左子节点值总是比父节点值小,右子节点值总比父节点值大
        while (current.iData != key)
        {
            // 比较当前节点值,
            if (key < current.iData)
            {
                // 如果值小于key,则将当前节点current引用变化为左子节点,此时不用判断引用是否为null
                current = current.leftChild;
            }
            else
            {
                // 如果值大于key,则将当前节点current引用变化为右子节点,此时不用判断引用是否为null
                current = current.rightChild;
            }

            // 如果当前节点为空,则表示无法找到key对应的节点
            if (current == null)
            {
                return null;
            }
        }

        return current;
    }

    /**
     * 插入节点,跟查找节点代码类似,只是在遇到null时,将节点插入,修改引用
     * 
     * @param id key值
     * @param dd value值
     */
    public void insert(int id, double dd)
    {
        // 插入的节点
        Node newNode = new Node();
        newNode.iData = id;
        newNode.dData = dd;

        // 如果根节点为空,则插入节点为根节点
        if (root == null)
        {
            root = newNode;
        }
        else
        {
            // 当前节点,引用会随在查找变化
            // 由于查找要插入的节点是从根基点开始,所以root引用赋值给current
            Node current = root;

            // 父节点
            // 有父节点的引用,才能够给子节点leftChild或者rightChild赋值
            Node parent;

            while (true)
            {
                // 保存父节点的引用,因为后面在查找时,current的引用一定会为null,
                // 此时说明已经找到插入节点的位置了
                parent = current;

                // 插入节点在左子树
                if (id < current.iData)
                {
                    current = current.leftChild;
                    if (current == null)
                    {
                        parent.leftChild = newNode;
                        return;
                    }
                }
                // 插入节点在右子树
                else
                {
                    current = current.rightChild;
                    if (current == null)
                    {
                        parent.rightChild = newNode;
                        return;
                    }
                }
            }
        }
    }

    /**
     * 删除节点
     * 
     * @param key 删除节点key值
     * @return 返回值
     */
    public boolean delete(int key)
    {
        Node current = root; // 当前节点
        Node parent = root; // 父节点,用于标记删除节点的父节点
        boolean isLeftChild = true; // 是否是左子节点

        // 查找要删除的节点
        while (current.iData != key)
        {
            // 保存父节点的引用
            parent = current;

            // 删除节点在左子树
            if (key < current.iData)
            {
                isLeftChild = true;
                current = current.leftChild;
            }
            // 删除节点在左子树
            else
            {
                isLeftChild = false;
                current = current.rightChild;
            }

            // 找不到删除节点,返回
            if (current == null)
            {
                return false;
            }
        }

        // 删除没有子节点的节点
        // 即删除节点为current,此时其左子节点、右子节点的应用都为null
        if (current.leftChild == null && current.rightChild == null)
        {
            if (current == root)
            {
                root = null;
            }
            else if (isLeftChild)
            {
                // 修改current父节点左子节点的引用
                parent.leftChild = null;
            }
            else
            {
                // 修改current父节点右子节点的引用
                parent.rightChild = null;
            }
        }
        // 删除节点current的右子节点为空,即只有左子节点
        else if (current.rightChild == null)
        {
            // 判断是否为根
            if (current == root)
            {
                root = current.leftChild;
            }
            // 如果删除节点为parent的左子节点,则引用赋值为左子树
            else if (isLeftChild)
            {
                parent.leftChild = current.leftChild;
            }
            // 如果删除节点为parent的右子节点,则引用赋值为右子树
            else
            {
                parent.rightChild = current.leftChild;
            }
        }
        // 删除节点current的左子节点为空,即只有右子节点
        else if (current.leftChild == null)
        {
            // 判断是否为根
            if (current == root)
            {
                root = current.rightChild;
            }
            // 如果删除节点为parent的左子节点,则引用赋值为左子树
            else if (isLeftChild)
            {
                parent.leftChild = current.rightChild;
            }
            // 如果删除节点为parent的右子节点,则引用赋值为右子树
            else
            {
                parent.rightChild = current.rightChild;
            }
        }
        else
        {
            // 找到后继
            Node successor = getSuccessor(current);

            // 判断删除节点是否为根的情形
            if (current == root)
            {
                root = successor;
            }
            else if (isLeftChild)
            {
                // 连接删除节点的父节点与后继节点
                parent.leftChild = successor;
            }
            else
            {
                // 连接删除节点的父节点与后继节点
                parent.rightChild = successor;
            }

            // 连接后继左子节点
            successor.leftChild = current.leftChild;
        }

        return true;
    }

    /**
     * 获取后继节点
     * @param delNode 删除节点
     * @return 后继节点
     */
    private Node getSuccessor(Node delNode)
    {
        Node successorParent = delNode; // 存放后继节点的父节点,因为需要断开后继节点,需要保存父节点的引用
        Node successor = delNode; // 存放后继节点
        Node current = delNode.rightChild; // 当前节点

        // 循环查找后继节点,最后currnt一定为null
        while (current != null)
        {
            successorParent = successor;
            successor = current;
            current = current.leftChild;
        }

        // 后继节点不是右子节点,即沿着左子节点路径寻找的情形
        if (successor != delNode.rightChild)
        {
            // 将后继节点的右子节点(有可能是右子树)的引用赋值给后继的父节点,即连接父节点与孙节点
            // 这样才能将后继节点断开,同时保持后继节点的子节点关系
            successorParent.leftChild = successor.rightChild;
            
            // 将删除节点的右子节点引用赋值给后继节点
            // 由于后继替换到删除节点的位置,因此需要改变删除节点右子节点的连接关系
            successor.rightChild = delNode.rightChild;
        }

        return successor;
    }

    /**
     * 二叉树遍历
     * 
     * @param traverseType 遍历类型
     */
    public void traverse(int traverseType)
    {
        switch (traverseType)
        {
        case 1:
            // 前序遍历
            System.out.print("\nPreorder traversal:");
            preOrder(root);
            break;
        case 2:
            // 中序遍历
            System.out.print("\nInorder traversal:");
            inOrder(root);
            break;
        case 3:
            // 后序遍历
            System.out.print("\nPostorder traversal:");
            postOrder(root);
            break;
        default:
            break;
        }
    }

    /**
     * 前序遍历
     * 
     * @param localRoot 节点值
     */
    private void preOrder(Node localRoot)
    {
        if (localRoot != null)
        {
            System.out.print(localRoot.iData + " ");
            preOrder(localRoot.leftChild);
            preOrder(localRoot.rightChild);
        }
    }

    /**
     * 中序遍历
     * 
     * @param localRoot 节点值
     */
    private void inOrder(Node localRoot)
    {
        if (localRoot != null)
        {
            inOrder(localRoot.leftChild);
            System.out.print(localRoot.iData + " ");
            inOrder(localRoot.rightChild);
        }
    }

    /**
     * 后续遍历
     * 
     * @param localRoot 节点值
     */
    private void postOrder(Node localRoot)
    {
        if (localRoot != null)
        {
            postOrder(localRoot.leftChild);
            postOrder(localRoot.rightChild);
            System.out.print(localRoot.iData + " ");
        }
    }

    /**
     * 打印二叉树
     */
    public void displayTree()
    {
        Stack<Node> globalStack = new Stack<Node>();
        globalStack.push(root);
        int nBlanks = 32;
        boolean isRowEmpty = false;
        System.out.println("......................................");

        while (isRowEmpty == false)
        {
            Stack<Node> localStack = new Stack<Node>();
            isRowEmpty = true;

            for (int i = 0; i < nBlanks; i++)
            {
                System.out.print(‘ ‘);
            }

            while (globalStack.isEmpty() == false)
            {
                Node temp = (Node) globalStack.pop();
                if (temp != null)
                {
                    System.out.print(temp.iData);
                    localStack.push(temp.leftChild);
                    localStack.push(temp.rightChild);

                    if (temp.leftChild != null || temp.rightChild != null)
                    {
                        isRowEmpty = false;
                    }
                }
                else
                {
                    System.out.print("--");
                    localStack.push(null);
                    localStack.push(null);
                }

                for (int i = 0; i < nBlanks * 2 - 2; i++)
                {
                    System.out.print(‘ ‘);
                }
            }

            System.out.println();
            nBlanks /= 2;
            while (localStack.isEmpty() == false)
            {
                globalStack.push(localStack.pop());
            }
        }

        System.out.println("......................................");
    }
}
bubuko.com,布布扣

数据结构学习笔记4.5--二叉树效率

原文:http://www.cnblogs.com/winlrou/p/3547403.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!