Java数据结构与算法(20)

树的主要算法有插入,查找,显示,遍历,删除,其中显示和删除略微复杂。

package chap08.tree;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

class Node {

    public int iData;
    public double dData;
    
    public Node leftChild;
    public Node rightChild;

    public void displayNode() {
        System.out.print("{" + iData + ", " + dData + "}");
    }
}

class Tree {
    
    // first node of tree
    private Node root; 

    public Tree() {
        
        root = null;
    } 

    /*
     * 查找
     */
    public Node find(int key) { 
        
        // (assumes non-empty tree)
        Node current = root; // start at root
        
        while (current.iData != key) // while no match,
        {
            if (key < current.iData) { 
                current = current.leftChild;
            }
            else {
                current = current.rightChild;
            }
            if (current == null) {
                return null; 
            }
        }
        return current; // found it
    } 

    /*
     * 插入
     */
    public void insert(int id, double dd) {
        
        Node newNode = new Node(); // make new node
        newNode.iData = id; // insert data
        newNode.dData = dd;
        
        if (root == null) { // no node in root
            root = newNode;
        }
        else // root occupied
        {
            Node current = root; // start at root
            Node parent;
            
            while (true) // (exits internally)
            {
                parent = current;
                if (id < current.iData) {
                    current = current.leftChild;
                    if (current == null) { 
                        // insert on left
                        parent.leftChild = newNode;
                        return;
                    }
                } 
                else {
                    current = current.rightChild;
                    if (current == null) { 
                        // insert on right
                        parent.rightChild = newNode;
                        return;
                    }
                } 
            } 
        } 
    } 

    /*
     * 删除
     */
    public boolean delete(int key) 
    { 
        // (assumes non-empty list)
        Node current = root;
        Node parent = root;
        boolean isLeftChild = true;

        // search for node
        while (current.iData != key) 
        {
            parent = current;
            if (key < current.iData) // go left?
            {
                isLeftChild = true;
                current = current.leftChild;
            } 
            else 
            {
                isLeftChild = false;
                current = current.rightChild;
            }
            if (current == null) // end of the line,
                return false; // didn't find it
        } 

        // if no children, simply delete it
        if (current.leftChild == null && current.rightChild == null) {
            if (current == root) {
                root = null; 
            }
            else if (isLeftChild) {
                parent.leftChild = null; // disconnect
            }
            else {
                // from parent
                parent.rightChild = null;
            }
        }

        // if no right child, replace with left subtree
        else if (current.rightChild == null) {
            if (current == root) {
                root = current.leftChild;
            }
            else if (isLeftChild) {
                parent.leftChild = current.leftChild;
            }
            else {
                parent.rightChild = current.leftChild;
            }
        }

        // if no left child, replace with right subtree
        else if (current.leftChild == null)
            if (current == root)
                root = current.rightChild;
            else if (isLeftChild)
                parent.leftChild = current.rightChild;
            else
                parent.rightChild = current.rightChild;

        // 有两个孩子,则用中序后继替代
        else 
        {
            // get successor of node to delete (current)
            Node successor = getSuccessor(current);

            // connect parent of current to successor instead
            if (current == root) {
                root = successor;
            }
            else if (isLeftChild) {
                parent.leftChild = successor;
            }
            else {
                parent.rightChild = successor;
            }

            // connect successor to current's left child
            successor.leftChild = current.leftChild;
        } 
        
        return true; 
    } 

    /*
     * 获取后继
     * 返回具有倒数第二高的值的节点
     * 找到右孩子,然后右孩子的左子孙
     */
    private Node getSuccessor(Node delNode) {
        
        Node successorParent = delNode;
        Node successor = delNode;
        
        // go to right child
        Node current = delNode.rightChild; 
        
        while (current != null) { 
            successorParent = successor;
            successor = current;
            // go to left child
            current = current.leftChild; 
        }
        
        // if successor not right child
        if (successor != delNode.rightChild) { 
            
            // make connections
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;
        }
        return successor;
    }

    public void traverse(int traverseType) {
        switch (traverseType) {
        case 1:
            System.out.print("
Preorder traversal: ");
            preOrder(root);
            break;
        case 2:
            System.out.print("
Inorder traversal:  ");
            inOrder(root);
            break;
        case 3:
            System.out.print("
Postorder traversal: ");
            postOrder(root);
            break;
        }
        System.out.println();
    }

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

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

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

    /*
     * 在控制台打印显示树 
     * 
     */
    public void displayTree() {
        
        // 全局栈,初始放入树的根节点
        Stack globalStack = new Stack();
        globalStack.push(root);
        
        // 打印空格的数量
        int nBlanks = 32;
        
        // 是否为空的标识
        boolean isRowEmpty = false;
        
        while (isRowEmpty == false) {
            
            // 本地栈
            Stack localStack = new Stack();
            
            // 设置标识为空,后边再根据实际情况判断其是否不为空
            isRowEmpty = true;

            // 打印一定数量的空格,为了将节点 放置在适当的位置以满足视觉效果上树的形状
            for (int j = 0; j < nBlanks; j++) {
                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 j = 0; j < nBlanks * 2 - 1; j++) {
                    System.out.print(' ');
                }
            } 
            
            System.out.println();
            System.out.println();
            
            nBlanks /= 2;
            
            while (localStack.isEmpty() == false) {
                // 将本地栈的节点放入全局栈,进行反序,从而保证先处理左孩子
                globalStack.push(localStack.pop());
            }
        } 
    } 
} 

class TreeApp {
    public static void main(String[] args) throws IOException {
        int value;
        Tree theTree = new Tree();

        theTree.insert(50, 1.5);
        theTree.insert(25, 1.2);
        theTree.insert(75, 1.7);
        theTree.insert(12, 1.5);
        theTree.insert(37, 1.2);
        theTree.insert(43, 1.7);
        theTree.insert(30, 1.5);
        theTree.insert(33, 1.2);
        theTree.insert(87, 1.7);
        theTree.insert(93, 1.5);

        while (true) {
            System.out.print("Enter first letter of show, insert, find, delete, or traverse: ");

            int choice = getChar();
            switch (choice) {
            case 's':
                theTree.displayTree();
                break;
            case 'i':
                System.out.print("Enter value to insert: ");
                value = getInt();
                theTree.insert(value, value + 0.9);
                break;
            case 'f':
                System.out.print("Enter value to find: ");
                value = getInt();
                Node found = theTree.find(value);
                if (found != null) {
                    System.out.print("Found: ");
                    found.displayNode();
                    System.out.print("
");
                } 
                else {
                    System.out.print("Could not find ");
                }
                System.out.print(value + '
');
                break;
            case 'd':
                System.out.print("Enter value to delete: ");
                value = getInt();
                boolean didDelete = theTree.delete(value);
                if (didDelete) {
                    System.out.print("Deleted " + value + '
');
                }
                else {
                    System.out.print("Could not delete ");
                }
                System.out.print(value + '
');
                break;
            case 't':
                System.out.print("Enter type 1, 2 or 3: ");
                value = getInt();
                theTree.traverse(value);
                break;
            default:
                System.out.print("Invalid entry
");
            } 
        } 
    } 

    /*
     * 获取输入 
     */
    public static String getString() throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        
        String s = br.readLine();
        return s;
    }

    public static char getChar() throws IOException {
        String s = getString();
        return s.charAt(0);
    }

    public static int getInt() throws IOException {
        String s = getString();
        return Integer.parseInt(s);
    }
} 
原文地址:https://www.cnblogs.com/thlzhf/p/4088972.html