首页 > 代码库 > 【算法导论学习-25】 二叉树专题3:Treaps

【算法导论学习-25】 二叉树专题3:Treaps

参考1:算法导论333页

一、Treaps介绍

参考2: http://www.cnblogs.com/huangxincheng/archive/2012/07/30/2614484.html

1.   为什么要用Treaps

1) Treap简明易懂。Treap只有两种调整方式,左旋和右旋。而且即使没有严密的数学证明和分析,Treap的构造方法啊,平衡原理也是不难理解的。只要能够理解 BST和堆的思想,理解Treap当然不在话下。 

2) Treap易于编写。Treap只需维护一个满足堆序的修正值,修正值一经生成无需修改。相比较其他各种平衡树, Treap拥有最少的调整方式,仅仅两种相互对称的旋转。所以 Treap当之无愧是最易于编码调试的一种平衡树。 

3) Treap稳定性佳。Treap的平衡性虽不如 AVL,红黑树,SBT等平衡树,但是 Treap也不会退化,可以保证期望 O(logN)的深度。

4) Treap具有严密的数学证明。Treap期望O(logN)的深度,是有严密的数学证明的。但这不是介绍的重点,大多略去。 

5) Treap具有良好的实践效果。各种实际应用中, Treap的稳定性表现得相当出色,没有因为任何的构造出的数据而退化。于是在信息学竞赛中,不少选手习惯于使用 Treap,均取得了不俗的表现。

二、Treaps的java实现

参考1:http://www.blogjava.net/xmatthew/archive/2012/05/16/347297.html

参考2:http://www.cnblogs.com/huangxincheng/archive/2012/07/30/2614484.html

1、节点类

注意,这里的节点类中的prioity其实应该是随机生成的,但是这里给注释掉了,同时开放了setPrioity(int prioity)函数用于人工设置prioity的值,方便模拟。

/**
 * @author 曹艳丰
 *类说明:主要既要有key,又要有prioity
 */
public class TreapsNode<T> {
    private int key;
    private T satelliteData;
    private int prioity;
    private TreapsNode<T> leftChild,rightChild;
    /*构造一个没有左右子树的treapNod作为treap的root节点*/
    public TreapsNode(int key,T satelliteData) {
        // TODO 自动生成的构造函数存根
//      prioity=new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE);
//      prioity=new Random(System.currentTimeMillis()).nextInt(20);
        prioity=new Random().nextInt(20);
        this.key=key;
        this.satelliteData=http://www.mamicode.com/satelliteData;>

2、treaps的主体,实现了add()函数

/**
 * @author 曹艳丰
 * 类说明:只实现了add()函数
 */
public class Treap<T> {
    TreapsNode<T> root;
    public Treap() {
        // TODO 自动生成的构造函数存根
        root=null;
    }
    public Treap(TreapsNode<T> root) {
        // TODO 自动生成的构造函数存根
        this.root=root;
    }
    /*插入过程,只用判断两种情况 */
    public TreapsNode<T> add(TreapsNode<T> root,TreapsNode<T> node){
        if (root==null) {
            root=new TreapsNode<T>(node.getKey(), node.getSatelliteData());
        }
        if (node.getKey()<root.getKey()) {
            TreapsNode<T> tempNode=add(root.getLeftChild(), node);
            root.setLeftChild(tempNode);
            //插入点为最后一次递归,根据小根堆性质,需要”左左情况旋转”
             if (root.getLeftChild().getPrioity()<root.getPrioity()) {
                root=rightRotate(root);
            }
        }
        if (node.getKey()>root.getKey()) {
            TreapsNode<T> tempNode=add(root.getRightChild(), node);
            root.setRightChild(tempNode);
            //根据小根堆性质,需要”右右情况旋转”
            if (root.getRightChild().getPrioity()<root.getPrioity()) {
                root=leftRotate(root);
            }
           
        }
//      if (node.getKey()==root.getKey()) {
//          root.setLeftChild(node);
//      }
 
        return root;
    }
    public void add(TreapsNode<T> node){
        root=add(root, node);
    }
    /*右旋*/
    public TreapsNode<T> rightRotate(TreapsNode<T> node){
        /*tempNode是插入的节点,node是其父节点*/
        TreapsNode<T> tempNode=node.getLeftChild();
        node.setLeftChild(tempNode.getRightChild());
        tempNode.setRightChild(node);
        return tempNode;
    }
    /*左旋*/
    public TreapsNode<T> leftRotate(TreapsNode<T> node){
        /*tempNode是插入的节点,node是其父节点*/
        TreapsNode<T> tempNode=node.getRightChild();
        node.setRightChild(tempNode.getLeftChild());
        tempNode.setLeftChild(node);
        return tempNode;
    }
    public void inOrderTreeWalk(TreapsNode<T> node) {
        if (node != null) {
            inOrderTreeWalk(node.getLeftChild());
            System.out.println(node.getKey() + ":"
                    + node.getSatelliteData());
            inOrderTreeWalk(node.getRightChild());
        }
    }
   
    /*☆较简单——前序遍历递归过程 */
    private void recursePreOrder(TreapsNode<T> node) {
        if (node != null) {
            System.out.println(node.getKey() + ":"
                    + node.getSatelliteData());
            recursePreOrder(node.getLeftChild());
            recursePreOrder(node.getRightChild());
        }
    }
    /*☆较简单——前序遍历递归过程 */
    public void recursePreOrder() {
        recursePreOrder(root);
 
    }
    public void inOrderTreeWalk() {
    inOrderTreeWalk(root);
    }
}

3、测试

public class TreapsTest {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
       TreapsNode<String> root=new TreapsNode<String>(7, "G");
       root.setPrioity(4);
       TreapsNode<String> node1=new TreapsNode<String>(2, "B");
       node1.setPrioity(2);
       TreapsNode<String> node2=new TreapsNode<String>(1, "A");
       node2.setPrioity(1);
       TreapsNode<String> node3=new TreapsNode<String>(5, "E");
       node3.setPrioity(23);
       TreapsNode<String> node5=new TreapsNode<String>(8, "H");
       node5.setPrioity(5);
       TreapsNode<String> node6=new TreapsNode<String>(11, "K");
       node6.setPrioity(63);
       TreapsNode<String> node8=new TreapsNode<String>(9, "I");
       node8.setPrioity(73);
       Treap<String> treap=new Treap<>(root);
       treap.add(node1);
       treap.add(node2);
       treap.add(node3);
       treap.add(node5);
       treap.add(node6);
       treap.add(node8);
       treap.recursePreOrder();
       
       
    }
}

**************************************************************

控制台输出:前序和中序符合算法导论中335页图13.10(a)






【算法导论学习-25】 二叉树专题3:Treaps