数据结构之:treap 简介(一)

 treap是二叉搜索树的一个改进版,通过在二叉搜索树(BST)中增添优先权信息,使得BST具备堆的性质:树根节点的优先权最大(或最小)。
简言之,treap = tree + heap

解释完了treap是什么,我们再说一下为什么这么做,其实这个应该先讲,否则会让人迷惑。

这么做的原因是防止BST的退化,在向BST中添加节点时,由于输入数据的随机性,极端情况下可能会导致生成的BST变成一个链表树了,这样BST的优势消失了。为了防止这种情况发生,有多种办法(参见Donald.E.Knuth的《The art of computer programming. Volume 3》),AVL树,Red-black树,treap都是解决这个问题所提出的数据结构。

AVL树的实现较复杂,其结点旋转有两种情况,这里不详细阐述。

treap在每个结点添加的时候随机生成一个prior信息赋予该结点,然后通过结点旋转维持整个树为一个堆(最大堆或者最小堆),这样可以在一定概率上保证整棵树不会严重退化。

关于treap的效率,网上有很多评测。
关于treap的讲解,MIT的《算法导论》里面P265有关于随机建立二叉搜索树的讲解。

treap优点在于实现简单,下面附上一个我实现的c++版本:
#include <stdio.h>
#include <stdlib.h>
#include "../../stack/include/sim_stack.h"

/**********************************************************************
 * starstarstarpku@gmail.com
 * Binary Search Tree: BST
 * Heap; Maximum Heap or Minimum Heap
 *
 * insert
 * search
 * delete
 *
 * left_rotate
 * right_rotate
 *
 *        f      b: l_rotate          f                b
 *       / /   --------------->      / /     --->     /
 *      x   y                       x    b           f
 *     / /  //                     //   /           / /
 *    z   m n b                   z  m y           x   y
 *                                      /           //  /
 *                                     n           z m n  
 *
 * ******************************************************************/

typedef int treap_key_type;
inline int compare_treap_key (treap_key_type key1, treap_key_type key2)
{
    return key1 - key2;
}

typedef struct treap_node {
    struct treap_node* left;
    struct treap_node* right;
    signed int prior;
    void* data;
    treap_key_type key;
}treap_node;

typedef treap_node* p_treap_node;

/***************************************************
 * search key in a treap tree
 * return node pointer in tree, or NULL if not found
 * ************************************************/
p_treap_node search_treap (p_treap_node root, treap_key_type key)
{
    while (root && compare_treap_key(key, root->key)) {
        if (compare_treap_key(key, root->key) < 0)
            root = root->left;
        else if (compare_treap_key(key, root->key) > 0)
            root = root->right;
    }
    return root;
}

/*********************************************************************
 * allocate spaces to a new node, whose key comes from parameter key
 * return a node pointer, or NULL if failed
 * ******************************************************************/
p_treap_node make_new_node (treap_key_type key, void* data=0) {
    p_treap_node p = (p_treap_node)malloc(sizeof(treap_node));
    if (p == NULL) { printf("malloc failed/n"); exit(1); }
    p->left = NULL;
    p->right = NULL;
    p->key = key;
    p->prior = (double)rand() / 65535;            // modify here to control treap's capacity
    p->data = data;
    return p;
}

/****************************************************
 * tricky part: rotate root node to left
 * *************************************************/
void left_rotate (p_treap_node& root)
{
    p_treap_node tmp_r        = root->right;
    treap_key_type tmp_key    = root->key;
    signed int tmp_prior    = root->prior;

    root->key    = tmp_r->key;
    root->prior = tmp_r->prior;
    root->right = tmp_r->right;

    tmp_r->right    = tmp_r->left;
    tmp_r->left        = root->left;
    tmp_r->key        = tmp_key;
    tmp_r->prior    = tmp_prior;

    root->left    = tmp_r;
}

/****************************************************
 * as well as the above function
 * tricky part: rotate root node to right
 * *************************************************/
void right_rotate (p_treap_node& root)
{
    p_treap_node tmp_l        = root->left;
    treap_key_type tmp_key    = root->key;
    signed int tmp_prior    = root->prior;

    root->key    = tmp_l->key;
    root->prior    = tmp_l->prior;
    root->left    = tmp_l->left;

    tmp_l->left        = tmp_l->right;
    tmp_l->right    = root->right;
    tmp_l->key        = tmp_key;
    tmp_l->prior    = tmp_prior;

    root->right    = tmp_l;
}

/****************************************************
 * insert key in a treap tree
 * return node pointer of new node, or NULL if failed
 * *************************************************/
void insert_treap (p_treap_node& root, treap_key_type key, void* data=0)
{
    if (!root) {
        root = make_new_node (key, data);
        return;
    }

    if (compare_treap_key(key, root->key) > 0) {
        // insert into root's right subtree
        if (root->right != NULL) {
            insert_treap(root->right, key, data);
        }
        else {
            root->right = make_new_node(key, data);
        }
        if (root->prior < root->right->prior) {    left_rotate(root); }
    }
    else if (compare_treap_key(key, root->key) < 0) {
        // insert into root's left subtree
        if (root->left != NULL) {
            insert_treap(root->left, key, data);
        }
        else {
            root->left = make_new_node(key, data);
        }
        if (root->prior < root->left->prior) { right_rotate(root); }
    }
    else {
        // key already exist in treap tree, do nothing
        printf("key: %d already exists in treap/n", key);
    }
}

/*******************************************************
 * remove node from treap
 * return
 * ****************************************************/
void remove_treap_node (p_treap_node& root, treap_key_type key)
{
    p_treap_node p=root, parent=NULL;
    while (p && compare_treap_key(key, p->key)) {
        parent = p;
        if (compare_treap_key(key, p->key) < 0)
            p = p->left;
        else if (compare_treap_key(key, p->key) > 0)
            p = p->right;
    }
    if (p == NULL)
        return;
    while (p->left || p->right) {
        // we need to record p's parent, in order to later delete his child pointer
        parent = p;
        // find out which subtree has higher prior
        signed int lp = -100000, rp = -100000;
        if (p->left)     lp = p->left->prior;
        if (p->right)    rp = p->right->prior;

        if (lp > rp) {
            // left subtree has higher prior than right subtree, so
            // right_rotate
            right_rotate (p);
            p = p->right;
        }
        else {
            // as above, right subtree has higher prior than left subtree, so
            // left_rotate
            left_rotate (p);
            p = p->left;
        }
    }

    if (parent && parent->right == p)
        parent->right = NULL;
    else if (parent && parent->left == p)
        parent->left = NULL;

    /*if (p->data)
        free (p->data);
    */
    free(p);
    p = NULL;
    return;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值