数据结构06之树形结构

树形结构拥有,有序数组和链表的所有优点,在树形结构中查找数据和在数组中一样快,在树形结构中插入数据和链表中一样简单!树是由链接和节点组成的!

根:一棵树只有一个根!

路径:从一个节点到另一个节点,所经过节点的顺序排列称为路径!

父节点:每一个节点都恰好有一条边向上链接到一个点,称为父节点!在树形结构中不能一个节点拥有两个父节点!那就不是树了!

子节点:每一个节点都可能有一个或多个向下的节点,称为子节点!父节点还是子节点都是相对的!

叶节点 :没有子节点的节点称之为叶节点!

层: 一个节点的层是指从根开始到这个节点有多少”代“,

子树:每个节点都可以当做子树的根,他和她所有的子节点都含在子树中就想家族中的那样,一个根节点包含所有的子孙!但是这个根却是另一个树的子节点! 

遍历:遍历树的意思是指按照特定顺序访问每一个节点,有三种简单遍历树的方法,前序、中序、后序!最常用的是中序!不管什么序遍历访问每一个节点就行!

二叉树是一种特殊的树形结构,也就是每个节点最多有两个分支,普通的树里面可能会有更多的节点称为多路树!

用数组标示树:

 

定义节点:

public class Node 

{
 int iData; // data used as key value
 double dData; // other data
 Node leftChild; // this Node's left child
 Node rightChild; // this Node's right child

 public void displayNode()
 {
  // (see Listing 8.1 for method body)
  System.out.print("{" + iData + ", " + dData + "} ");
 }
}

 二叉树............

public class Tree {
    private Node root; // the only data field in Tree

    public Node find(int key) // find Node with given key
    { // (assumes non-empty tree)
        Node current = root; // start at root
        while (current.iData != key) // while no match,
        {
            if (key < current.iData) // go left?
                current = current.leftChild;
            else
                current = current.rightChild; // or go right?
            if (current == null// if no child,
                return null// didn't find it
        }
        return current; // found it
    }

    public Node minimum() // returns Node with minimum key value
    {
        Node current, last = null;
        current = root; // start at root
        while (current != null// until the bottom,
        {
            last = current; // remember Node
            current = current.leftChild; // go to left child
        }
        return last;
    }

    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) // go left?
                {
                    current = current.leftChild;
                    if (current == null// if end of the line,
                    { // insert on left
                        parent.leftChild = newNode;
                        return;
                    }
                } // end if go left
                else // or go right?
                {
                    current = current.rightChild;
                    if (current == null// if end of the line
                    { // insert on right
                        parent.rightChild = newNode;
                        return;
                    }
                } // end else go right
            } // end while
        } // end else not root
    } // end insert()

    public boolean delete(int key) // delete Node with given key
    { // (assumes non-empty list)
        Node current = root;
        Node parent = root;
        boolean isLeftChild = true;
        while (current.iData != key) // search for Node
        {
            parent = current;
            if (key < current.iData) // go left?
            {
                isLeftChild = true;
                current = current.leftChild;
            } else // or go right?
            {
                isLeftChild = false;
                current = current.rightChild;
            }
            if (current == null// end of the line,
                return false// didn't find it
        } // end while
            
// found Node to delete
            
// continues...

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

        
// delete() continued...
        
// if no right child, replace with left subtree
        else if (current.rightChild == null)
            if (current == root)
                root = current.leftChild;
            else if (isLeftChild) // left child of parent
                parent.leftChild = current.leftChild;
            else
                // right child of parent
                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) // left child of parent
                parent.leftChild = current.rightChild;
            else
                // right child of parent
                parent.rightChild = current.rightChild;
        // continued...

        
// delete() continued
        else // two children, so replace with inorder successor
        {
            // 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;
        } // end else two children
            
// (successor cannot have a left child)
        return true;
    } // end delete()

    public void printTree() {
        System.out.print("前序遍历:");
        preOrder(root);
        System.out.println();
        System.out.print("中序遍历:");
        inOrder(root);
        System.out.println();
        System.out.print("后序遍历:");
        postOrder(root);
        System.out.println();
    }

    // returns Node with next-highest value after delNode
    
// goes to right child, then right child's left descendants
    private Node getSuccessor(Node delNode) {
        Node successorParent = delNode;
        Node successor = delNode;
        Node current = delNode.rightChild; // go to right child
        while (current != null// until no more
        { // left children,
            successorParent = successor;
            successor = current;
            current = current.leftChild; // go to left child
        }
        // if successor not
        if (successor != delNode.rightChild) // right child,
        { // make connections
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;// ?
        }
        return successor;
    }

    private void preOrder(Node localRoot) {
        if (localRoot != null) {
            localRoot.displayNode();
            preOrder(localRoot.leftChild);
            preOrder(localRoot.rightChild);
        }
    }

    private void inOrder(Node localRoot) {
        if (localRoot != null) {
            inOrder(localRoot.leftChild);
            localRoot.displayNode();
            inOrder(localRoot.rightChild);
        }
    }

    private void postOrder(Node localRoot) {
        if (localRoot != null) {
            postOrder(localRoot.leftChild);
            postOrder(localRoot.rightChild);
            localRoot.displayNode();
        }
    }
    
     public static void main(String[] args)
     {
      Tree theTree = new Tree(); // make a tree
      theTree.insert(50, 1.5); // insert 3 Nodes
      theTree.insert(25, 1.7);
      theTree.insert(75, 1.9);
      Node found = theTree.find(25); // find Node with key 25
      if(found != null)
       System.out.println("Found the Node with key 25");
      else
       System.out.println("Could not find node with key 25");
      //theTree.minimum().displayNode();
      theTree.printTree();
      System.out.println("删除后...");
      theTree.delete(25);
      theTree.printTree();
     } // end main()

红黑树............

红黑树很好的解决了二叉树搜索难的问题!

红黑规则:

根节点是黑色

子节点不是黑色就是红色

如果节点是红色则子节点必须是黑色

从根节点到叶节点的每条路径必须包含相同数目的黑节点 

import java.util.*; 
public class RedBlackTree<T extends Comparable>
{
    //定义红黑树的颜色
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
    static class Node
    {
        Object data;
        Node parent; 
        Node left;
        Node right;
        //节点的默认颜色是黑色
        boolean color = BLACK;
        public Node(Object data , Node parent 
            , Node left , Node right)
        {
            this.data = data;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }
        public String toString()
        {
            return "[data=" + data
                + ", color=" + color + "]"; 
        }
        public boolean equals(Object obj)
        {
            if (this == obj)
            {
                return true;
            }
            if (obj.getClass() == Node.class)
            {
                Node target = (Node)obj;
                return data.equals(target.data)
                    && color == target.color
                    && left == target.left
                    && right == target.right
                    && parent == target.parent;
            }
            return false;
        }
    }
    private Node root;
    //两个构造器用于创建排序二叉树
    public RedBlackTree()
    {
        root = null;
    }
    public RedBlackTree(T o)
    {
        root = new Node(o , null , null , null);
    }
    //添加节点
    public void add(T ele)
    {
        //如果根节点为null
        if (root == null)
        {
            root = new Node(ele , null , null , null);
        }
        else
        {
            Node current = root;
            Node parent = null;
            int cmp = 0;
            //搜索合适的叶子节点,以该叶子节点为父节点添加新节点
            do
            {
                parent = current;
                cmp = ele.compareTo(current.data);
                //如果新节点的值大于当前节点的值
                if (cmp > 0)
                {
                    //以右子节点作为当前节点
                    current = current.right;
                }
                //如果新节点的值小于当前节点的值
                else
                {
                    //以左子节点作为当前节点
                    current = current.left;
                }
            }
            while (current != null);
            //创建新节点
            Node newNode = new Node(ele , parent , null , null);
            //如果新节点的值大于父节点的值
            if (cmp > 0)
            {
                //新节点作为父节点的右子节点
                parent.right = newNode;
            }
            //如果新节点的值小于父节点的值
            else
            {
                //新节点作为父节点的左子节点
                parent.left = newNode;
            }
            //维护红黑树
            fixAfterInsertion(newNode);
        }
    }
    //删除节点
    public void remove(T ele)
    {
        //获取要删除的节点
        Node target = getNode(ele);
        //如果被删除节点的左子树、右子树都不为空
        if (target.left != null && target.right != null
        {
            //找到target节点中序遍历的前一个节点
            
//s用于保存target节点的左子树中值最大的节点
            Node s = target.left;
            //搜索target节点的左子树中值最大的节点
            while (s.right != null)
            {
                s = s.right;
            }
            //用s节点来代替p节点
            target.data = s.data;
            target = s;
        } 
        //开始修复它的替换节点,如果该替换节点不为null
        Node replacement = (target.left != null ? target.left : target.right);
        if (replacement != null
        {
            // 让replacement的parent指向target的parent
            replacement.parent = target.parent;
            //如果target的parent为null,表明target本身是根节点
            if (target.parent == null)
            {
                root = replacement;
            }
            //如果target是其父节点的左子节点
            else if (target == target.parent.left)
            {
                //让target的父节点left指向replacement
                target.parent.left  = replacement;
            }
            //如果target是其父节点的右子节点
            else
            {
                //让target的父节点right指向replacement
                target.parent.right = replacement;
            }
            //彻底删除target节点
            target.left = target.right = target.parent = null;

            // 修复红黑树
            if (target.color == BLACK)
            {
                fixAfterDeletion(replacement);
            }
        }
        //target本身是根节点
        else if (target.parent == null
        {
            root = null;
        } 
        else 
        {
            //target没有子节点,把它当成虚的替换节点。
            
//修复红黑树
            if (target.color == BLACK)
            {
                fixAfterDeletion(target);
            }
            if (target.parent != null
            {
                //如果target是其父节点的左子节点
                if (target == target.parent.left)
                {
                    //将target的父节点left设为null
                    target.parent.left = null;
                }
                //如果target是其父节点的右子节点
                else if (target == target.parent.right)
                {
                    //将target的父节点right设为null
                    target.parent.right = null;
                }
                //将target的parent设置null
                target.parent = null;
            }
        }
    }
    //根据给定的值搜索节点
    public Node getNode(T ele)
    {
        //从根节点开始搜索
        Node p = root;
        while (p != null
        {
            int cmp = ele.compareTo(p.data);
            //如果搜索的值小于当前p节点的值
            if (cmp < 0)
            {
                //向左子树搜索
                p = p.left;
            }
            //如果搜索的值大于当前p节点的值
            else if (cmp > 0)
            {
                //向右子树搜索
                p = p.right;
            }
            else
            {
                return p;
            }
        }
        return null;
    }
    //广度优先遍历
    public List<Node> breadthFirst()
    {
        Queue<Node> queue = new ArrayDeque<Node>();
        List<Node> list = new ArrayList<Node>();
        if( root != null)
        {
            //将根元素入“队列”
            queue.offer(root);
        }
        while(!queue.isEmpty())
        {
            //将该队列的“队尾”的元素添加到List中
            list.add(queue.peek());
            Node p = queue.poll();
            //如果左子节点不为null,将它入“队列”
            if(p.left != null)
            {
                queue.offer(p.left);
            }
            //如果右子节点不为null,将它入“队列”
            if(p.right != null)
            {
                queue.offer(p.right);
            }
        }
        return list;
    }
    //插入节点后修复红黑树
    private void fixAfterInsertion(Node x) 
    {
        x.color = RED;
        //直到x节点的父节点不是根,且x的父节点不是红色
        while (x != null && x != root 
            && x.parent.color == RED) 
        {
            //如果x的父节点是其父节点的左子节点
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) 
            {
                //获取x的父节点的兄弟节点
                Node y = rightOf(parentOf(parentOf(x)));
                //如果x的父节点的兄弟节点是红色
                if (colorOf(y) == RED) 
                {
                    //将x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //将x的父节点的兄弟节点设为黑色
                    setColor(y, BLACK);
                    //将x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                }
                //如果x的父节点的兄弟节点是黑色
                else
                {
                    //如果x是其父节点的右子节点
                    if (x == rightOf(parentOf(x))) 
                    {
                        //将x的父节点设为x
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    //把x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //把x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } 
            //如果x的父节点是其父节点的右子节点
            else 
            {
                //获取x的父节点的兄弟节点
                Node y = leftOf(parentOf(parentOf(x)));
                //如果x的父节点的兄弟节点是红色
                if (colorOf(y) == RED) 
                {
                    //将x的父节点设为黑色。
                    setColor(parentOf(x), BLACK);
                    //将x的父节点的兄弟节点设为黑色
                    setColor(y, BLACK);
                    //将x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    //将x设为x的父节点的节点
                    x = parentOf(parentOf(x));
                }
                //如果x的父节点的兄弟节点是黑色
                else 
                {
                    //如果x是其父节点的左子节点
                    if (x == leftOf(parentOf(x))) 
                    {
                        //将x的父节点设为x
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    //把x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //把x的父节点的父节点设为红色
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        //将根节点设为黑色
        root.color = BLACK;
    }
    //删除节点后修复红黑树
    private void fixAfterDeletion(Node x) 
    {
        //直到x不是根节点,且x的颜色是黑色
        while (x != root && colorOf(x) == BLACK) 
        {
            //如果x是其父节点的左子节点
            if (x == leftOf(parentOf(x)))
            {
                //获取x节点的兄弟节点
                Node sib = rightOf(parentOf(x));
                //如果sib节点是红色
                if (colorOf(sib) == RED)
                {
                    //将sib节点设为黑色
                    setColor(sib, BLACK);
                    //将x的父节点设为红色
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    //再次将sib设为x的父节点的右子节点
                    sib = rightOf(parentOf(x));
                }
                //如果sib的两个子节点都是黑色
                if (colorOf(leftOf(sib)) == BLACK
                    && colorOf(rightOf(sib)) == BLACK) 
                {
                    //将sib设为红色
                    setColor(sib, RED);
                    //让x等于x的父节点
                    x = parentOf(x);
                } 
                else 
                {
                    //如果sib的只有右子节点是黑色
                    if (colorOf(rightOf(sib)) == BLACK) 
                    {
                        //将sib的左子节点也设为黑色
                        setColor(leftOf(sib), BLACK);
                        //将sib设为红色
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    //设置sib的颜色与x的父节点的颜色相同
                    setColor(sib, colorOf(parentOf(x)));
                    //将x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //将sib的右子节点设为黑色
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            }
            //如果x是其父节点的右子节点
            else
            {
                //获取x节点的兄弟节点
                Node sib = leftOf(parentOf(x));
                //如果sib的颜色是红色
                if (colorOf(sib) == RED) 
                {
                    //将sib的颜色设为黑色
                    setColor(sib, BLACK);
                    //将sib的父节点设为红色
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }
                //如果sib的两个子节点都是黑色
                if (colorOf(rightOf(sib)) == BLACK 
                    && colorOf(leftOf(sib)) == BLACK) 
                {
                    //将sib设为红色
                    setColor(sib, RED);
                    //让x等于x的父节点
                    x = parentOf(x);
                }
                else 
                {
                    //如果sib只有左子节点是黑色
                    if (colorOf(leftOf(sib)) == BLACK) 
                    {
                        //将sib的右子节点也设为黑色
                        setColor(rightOf(sib), BLACK);
                        //将sib设为红色
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    //将sib的颜色设为与x的父节点颜色相同
                    setColor(sib, colorOf(parentOf(x)));
                    //将x的父节点设为黑色
                    setColor(parentOf(x), BLACK);
                    //将sib的左子节点设为黑色
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }
        setColor(x, BLACK);
    }
    //获取指定节点的颜色
    private boolean colorOf(Node p)
    {
        return (p == null ? BLACK : p.color);
    }
    //获取指定节点的父节点
    private Node parentOf(Node p) 
    {
        return (p == null ? null: p.parent);
    }
    //为指定节点设置颜色
    private void setColor(Node p, boolean c)
    {
        if (p != null)
        {
            p.color = c;
        }
    }
    //获取指定节点的左子节点
    private Node leftOf(Node p) 
    {
        return (p == null) ? null: p.left;
    }
    //获取指定节点的右子节点
    private Node rightOf(Node p) 
    {
        return (p == null) ? null: p.right;
    }
    /**
     * 执行如下转换
     *  p        r
     *     r   p   
     *  q        q
     
*/
    private void rotateLeft(Node p) 
    {
        if (p != null
        {
            //取得p的右子节点
            Node r = p.right;
            Node q = r.left;
            //将r的左子节点链到p的右节点链上
            p.right = q;
            //让r的左子节点的parent指向p节点
            if (q != null)
            {
                q.parent = p;
            }
            r.parent = p.parent;
            //如果p已经是根节点
            if (p.parent == null)
            {
                root = r;
            }
            //如果p是其父节点的左子节点
            else if (p.parent.left == p)
            {
                //将r设为p的父节点的左子节点
                p.parent.left = r;
            }
            else
            {
                //将r设为p的父节点的右子节点
                p.parent.right = r;
            }
            r.left = p;
            p.parent = r;
        }
    }
    /**
     * 执行如下转换
     *     p       l
     *  l              p
     *     q       q
     
*/
    private void rotateRight(Node p) 
    {
        if (p != null)
        {
            //取得p的左子节点
            Node l = p.left;
            Node q = l.right;
            //将l的右子节点链到p的左节点链上
            p.left = q;
            //让l的右子节点的parent指向p节点
            if (q != null
            {
                q.parent = p;
            }
            l.parent = p.parent;
            //如果p已经是根节点
            if (p.parent == null)
            {
                root = l;
            }
            //如果p是其父节点的右子节点
            else if (p.parent.right == p)
            {
                //将l设为p的父节点的右子节点
                p.parent.right = l;
            }
            else 
            {
                //将l设为p的父节点的左子节点
                p.parent.left = l;
            }
            l.right = p;
            p.parent = l;
        }
    }
    //实现中序遍历
    public List<Node> inIterator()
    {
        return inIterator(root);
    }
    private List<Node> inIterator(Node node)
    {
        List<Node> list = new ArrayList<Node>();
        //递归处理左子树
        if (node.left != null)
        {
            list.addAll(inIterator(node.left));
        }
        //处理根节点
        list.add(node);
        //递归处理右子树
        if (node.right != null)
        {
            list.addAll(inIterator(node.right));
        }
        return list;
    }
    
    public static void main(String[] args) 
    {
        RedBlackTree<Integer> tree 
            = new RedBlackTree<Integer>();
        //添加节点
        tree.add(5);
        tree.add(20);
        tree.add(10);
        tree.add(3);
        tree.add(8);
        tree.add(15);
        tree.add(30);
        System.out.println(tree.breadthFirst());
        //删除节点
        tree.remove(20);
        System.out.println(tree.breadthFirst());
//        System.out.println(tree.inIterator());
        
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2012-04-12 15:27  _公孓℡  阅读(270)  评论(0编辑  收藏  举报