Treap(树堆)


/**
* 如果一个二叉搜索树节点插入的顺序是随机的,这样我们得到的二叉搜索树大多
* 数情况下是平衡的,即使存在一些极端情况,但是这种情况发生的概率很小,
* 所以我们可以这样建立一棵二叉搜索树,而不必要像AVL那样旋转,可以证明随
* 机顺序建立的二叉搜索树在期望高度是O(log n),但是某些时候我们并不能得
* 知所有的待插入节点,打乱以后再插入。所以我们需要一种规则来实现这种想法,
* 并且不必要所有节点。也就是说节点是顺序输入的,我们实现这一点可以用Treap。
* Treap=Tree+Heap。Treap本身是一棵二叉搜索树,它的左子树和右子树
* 也分别是一个Treap,和一般的二叉搜索树不同的是,Treap记录一个额外的
* 数据,就是优先级,Treap在以关键码构成二叉搜索树的同时,还按优先级来
* 满足堆的性质,Treap维护堆性质的方法用到了旋转,堆的优先级是随机的,我们
* 通过维护堆的性质来保证二叉树的平衡,Treap数据结构下的插入与删除操作期
* 望的时间复杂度均为O(log(n)),Treap维护堆的唯一旋转方式:
* * *
* / \ / \
* * * <================> * *
* / \ / \
* * * * *
*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct node
{
int element;
int priority;
struct node * left_node;
struct node * right_node;
};

struct node * alloc_node(int element)
{
struct node * new_node;

new_node = calloc(1, sizeof (struct node));
assert(new_node);

new_node->element = element;
// 为新节点的优先级分配一个随机数
new_node->priority = rand() % 1000;
return new_node;
}

struct node * left_rotate(struct node * root_node)
{
struct node * tmp_node;

tmp_node = root_node->right_node;
root_node->right_node = tmp_node->left_node;
tmp_node->left_node = root_node;
return tmp_node;
}

struct node * right_rotate(struct node * root_node)
{
struct node * tmp_node;

tmp_node = root_node->left_node;
root_node->left_node = tmp_node->right_node;
tmp_node->right_node = root_node;
return tmp_node;
}

struct node * insert(struct node * root_node, int element)
{
if(root_node == NULL)
{
// 分配一个新的节点
root_node = alloc_node(element);
}
else
{
if(root_node->element > element)
{
root_node->left_node = insert(root_node->left_node, element);
if(root_node->priority > root_node->left_node->priority)
root_node = right_rotate(root_node);
}
else if(root_node->element < element)
{
root_node->right_node = insert(root_node->right_node, element);
if(root_node->priority > root_node->right_node->priority)
root_node = left_rotate(root_node);
}
}
return root_node;
}

struct node * del(struct node * root_node, int element)
{
if(root_node != NULL)
{
if(root_node->element == element)
{
struct node * tmp_node;

if(!root_node->left_node || !root_node->right_node)
{
tmp_node = root_node;

if(!root_node->left_node)
root_node = root_node->right_node;
else
root_node = root_node->left_node;

// 释放被删除节点
free(tmp_node);
}
else
{
tmp_node = root_node;

if(root_node->left_node->element < root_node->right_node->element)
{
root_node = right_rotate(root_node);
root_node->right_node = del(tmp_node, element);
}
else
{
root_node = left_rotate(root_node);
root_node->left_node = del(tmp_node, element);
}
}
}
else
{
if(root_node->element < element)
root_node->right_node = del(root_node->right_node, element);
else if(root_node->element > element)
root_node->left_node = del(root_node->left_node, element);
}
}
return root_node;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值