JAVA之伸展树

来源:互联网 发布:食堂刷卡机数据采集 编辑:程序博客网 时间:2024/06/06 05:07
  • 伸展树与二叉平衡查找树
    AVL树(带有平衡条件的树)查找的时候最坏的情形为0(N)并不坏,只要它不经常发生就可以。任何一次访问,即使花费0(N),任然可能非常快。具有最坏运行时间0(N)但保证对任意M次连续操作最多花费O(MlogN)运行时间确实让人满意了。
    伸展树和其它树的区别就是没访问一个节点的时候,那个节点就会成为根节点,这样下次访问的时候时间为0(1)并且与二叉平衡查找树比少了高度的属性和判断平衡信息,因此从某种程度上简化代码。

在伸展树中最主要的一部分就是伸展,分为两种情况第一种是之字形(zig-zag)情形,第二种就是一字形(zig-zig)
这里写图片描述
这里写图片描述

package tree;/* * 伸展树:他保证从空树开始连续M次对树的操作最多花费0(MlogN)时间 */public class STree<AnyType extends Comparable<? super AnyType>>{    private Node root;    private class Node{        public Node left;//左孩子        public Node right;//右孩子        public Node parent;//父亲节点        public AnyType x;//data数据        public Node(AnyType x){            this.x = x;            parent = null;            left = null;            right = null;        }    }    public STree(){        root = null;    }    //查找    public AnyType find(AnyType key){        root = find(root, key);        if(root == null || root.x.compareTo(key) != 0) return null;        return root.x;    }    private Node find(Node p, AnyType key){        if(p == null || key == null) return null;        Node prep = null;        while(p != null){            prep = p;            int cmp = key.compareTo(p.x);            if(cmp < 0) p = p.left;            else if(cmp > 0) p = p.right;            else break;        }        root = splay(prep);        return root;    }    //插入    public void insert(AnyType data){        if(data == null) return;        if(root == null){            root = new Node(data);            return;        }        Node t = find(root, data);        int cmp = data.compareTo(t.x);        if(cmp == 0){//更新value            root.x = data;            return;        }        root = new Node(data);        //先把T分为左右子树,再合并        if(cmp < 0){//插入新根,以t->lchild和t为左/右孩子            Node x = t.left;            root.left = x;            root.right = t;            t.parent = root;            if(x != null){                x.parent = root;                t.left = null;            }        }else if(cmp > 0){            Node x = t.right;            root.left = t;            root.right = x;            t.parent = root;            if(x != null){                x.parent = root;                t.right = null;            }        }    }    //删除    public void delect(AnyType key){        if(key == null) return;        Node t = find(root, key);        if(t == null || key.compareTo(t.x) != 0)            return;        if(t.right == null){//右子树为空            root = root.left;            root.parent = null; return;        }        //右子数不空        //1.删除T节点, 得到子树tl, tr        Node tl = t.left, tr = t.right;        tr.parent = null;        //2.将右子树最小节点min伸展至右子树树根,min一定没有左子节点        Node min = min(tr);        //3.将tl作为左子树链接到min上        min.left = tl;        if(tl != null) tl.parent = min;        root = min;    }    public AnyType min(){        if(root == null)    return null;        root = min(root);        return root.x;    }    private Node min(Node x){        if(x == null)   return null;        while(x.left != null)            x = x.left;        x = splay(x);        return x;    }    public AnyType max(){        if(root == null)    return null;        root = max(root);        return root.x;    }    private Node max(Node x){        if(x == null) return null;        while(x.right != null)            x = x.right;        x = splay(x);        return x;    }    private Node splay(Node v){//v是找到的节点        if(v == null) return null;        Node p, g; //v的父亲与祖父        //自上而下,反复对v做双层伸展        while((p = v.parent) != null && (g = p.parent) != null){            Node gg = g.parent;//(great-grand parent)为父            if(isLChild(v)){                if(isLChild(p)){//zig-zig(g)先g结点右旋,zig(p)在p右旋                    attachAsLChild(g, p.right);                    attachAsRChild(p, g);                    attachAsLChild(p, v.right);                    attachAsRChild(v, p);                }else{//zig-zag(p)先p右旋,再g左旋zag(g)                    attachAsLChild(p, v.right);                    attachAsRChild(v, p);                    attachAsRChild(g, v.left);                    attachAsLChild(v, g);                }            }else{                if(isRChild(p)){//zag-zag,zag(g)先g结点左旋,zig(p)再p左旋                    attachAsRChild(g, p.left);                    attachAsLChild(p.left, g);                    attachAsRChild(p, v.left);                    attachAsLChild(v, p);                }else{//zag-zig,先p左旋,zag(p),再g右旋zig(g)                    attachAsRChild(p, v.left);                    attachAsLChild(v, p);                    attachAsLChild(g, v.right);                    attachAsRChild(v, g);                }            }            //若v原先的曾祖父gg不存在, 则v现在应为树根            if(gg == null) v.parent = null;            else{//否则,gg此后应该以v作为左或右孩子                if(gg.left == g) attachAsLChild(gg, v);                else attachAsRChild(gg, v);            }        }        //双层伸展结束时,必有g == null, 但p可能非空        //若p果真非空,则额外在做一次单旋        if(p != null && p == v.parent){            if(isLChild(v)){//zig                attachAsRChild(p, v.right);                attachAsRChild(v, p);            }else{//zag                attachAsRChild(p, v.left);                attachAsLChild(v, p);            }        }        v.parent = null;        return v;    }    //判断n是否是父节点的左孩子    private boolean isLChild(Node n){        Node p = n.parent;        return p.left == n;    }    //判断n是否是父节点的右孩子    private boolean isRChild(Node n){        Node p = n.parent;        return p.right == n;    }    //在节点p与rc(可能为空)之间建立父(左)子关系    private void attachAsLChild(Node parent, Node lchild){        parent.left = lchild;        if(lchild != null)            lchild.parent = parent;    }    //在节点p与rc(可能为空)之间建立父(右)子关系    private void attachAsRChild(Node parent, Node rchild){        parent.right = rchild;        if(rchild != null)            rchild.parent = parent;    }    public void prearder(){        prearder(root);        System.out.println("前序遍历");        System.out.println();    }    private void prearder(Node p){        if(p == null) return;        System.out.print(p.x+" ");        prearder(p.left);        prearder(p.right);    }    //测试    public static void main(String[] args){        STree<Integer> st = new STree<Integer>();        for(int i=0; i<10; i++)            st.insert(i);        st.find(5);        st.prearder();    }}
0 0
原创粉丝点击