您的位置:首页 > 其它

treap(树堆)

2015-09-06 16:58 387 查看


treap(树堆)

一棵treap是一棵修改了结点顺序的二叉查找树,如图,显示一个例子,通常树内的每个结点x都有一个关键字值key[x],另外,还要为结点分配priority[x],它是一个独立选取的随机数。

假设所有的优先级是不同的,所有的关键字也是不同的。treap的结点排列成让关键字遵循二叉查找树性质,并且优先级遵循最小堆顺序性质:

1.如果v是u的左孩子,则key[v] < key[u].

2.如果v是u的右孩子,则key[v] > key[u].

3.如果v是u的孩子,则priority[u] > priority[u].

这两个性质的结合就是为什么这种树被称为“treap”的原因,因为它同时具有二叉查找树和堆的特征。



用以下方式考虑treap会有帮助。假设插入关联关键字的结点x1,x2,...,xn到一棵treap内。结果的treap是将这些结点以它们的优先级(随机选取)的顺序插入一棵正常的二叉查找树形成的,亦即priority[xi] < priority[xj]表示xi在xj之前被插入。

在算法导论的12.4节中,其证明了随机构造的二叉查找树的期望高度为O(lgn),因而treap的期望高度亦是O(lgn)。
treap插入操作:

1.按照二叉树的插入方法,将结点插入到树中

2.根据堆的性质(我们这里为最小堆)和优先级的大小调整结点位置。
treap删除操作:

1.找到相应的结点

2.若该结点为叶子结点,则直接删除;

若该结点为只包含一个叶子结点的结点,则将其叶子结点赋值给它;

若该结点为其他情况下的节点,则进行相应的旋转,直到该结点为上述情况之一,然后进行删除。
旋转主要涉及到右旋转的左旋转,下面把右旋转的图画在下面:



代码如下:(已通过GCC和VC编译)
PS:请教一下大家,在C语言中是没有引用的,因而在treap_insert(Node* root, int key, int priority)函数中(第40行),由于root要跟着改变,因而必须传root地址,即&root(第131行),因而导致在写代码时,显得很不好看,如传root的left的地址为参数,必须写成&((*root)->left)(第72行)。如果用C++写,直接用引用,则代码看起来简洁很多,不知在C语言中如何操作?

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4
5 typedef struct node_t* Node;
6 typedef struct treap_t* Treap;
7
8 struct node_t
9 {
10   Node left;//左节点
11   Node right;//右节点
12   int priority;//优先级
13   int key;//存储的关键字
14 };
15
16 struct treap_t
17 {
18   Node root;
19 };
20
21 //左旋转
22 void rotate_left(Node* node)
23 {
24   Node x = (*node)->right;
25   (*node)->right = x->left;
26   x->left = *node;
27   *node = x;
28 }
29
30 //右旋转
31 void rotate_right(Node* node)
32 {
33   Node x = (*node)->left;
34   (*node)->left = x->right;
35   x->right = *node;
36   *node = x;
37 }
38
39 //插入操作
40 void treap_insert(Node* root, int key, int priority)
41 {
42   //根为NULL,则直接创建此结点为根结点
43   if (*root == NULL)
44   {
45     *root = (Node)malloc(sizeof(struct node_t));
46     (*root)->left = NULL;
47     (*root)->right = NULL;
48     (*root)->priority = priority;
49     (*root)->key = key;
50   }
51   //向右插入结点
52   else if (key < (*root)->key)
53   {
54     treap_insert(&((*root)->left), key, priority);
55     if ((*root)->left->priority < (*root)->priority)
56       rotate_right(root);
57   }
58   //向左插入结点
59   else
60   {
61     treap_insert(&((*root)->right), key, priority);
62     if ((*root)->right->priority < (*root)->priority)
63       rotate_left(root);
64   }
65 }
66
67 void treap_delete(Node* root, int key)
68 {
69   if (*root != NULL)
70   {
71     if (key < (*root)->key)
72       treap_delete(&((*root)->left), key);
73     else if (key > (*root)->key)
74       treap_delete(&((*root)->right), key);
75     else
76     {
77       //左右孩子都为空不用单独写出来
78       if ((*root)->left == NULL)
79         *root = (*root)->right;
80       else if ((*root)->right == NULL)
81         *root = (*root)->left;
82       else
83       {
84         //先旋转,然后再删除
85         if ((*root)->left->priority < (*root)->right->priority)
86         {
87           rotate_right(root);
88           treap_delete(&((*root)->right), key);
89         }
90         else
91         {
92           rotate_left(root);
93           treap_delete(&((*root)->left), key);
94         }
95       }
96     }
97   }
98 }
99
100 //中序遍历
101 void in_order_traverse(Node root)
102 {
103   if (root != NULL)
104   {
105     in_order_traverse(root->left);
106     printf("%d\t", root->key);
107     in_order_traverse(root->right);
108   }
109 }
110
111 //计算树的高度
112 int depth(Node node)
113 {
114     if(node == NULL)
115         return -1;
116     int l = depth(node->left);
117     int r = depth(node->right);
118
119     return (l < r)?(r+1):(l+1);
120 }
121
122 int main()
123 {
124   Treap treap = (Treap)malloc(sizeof(struct treap_t));
125   treap->root = NULL;
126   int i = 0;
127
128   srand(time(0));
129
130   for (i = 0; i < 100; i++)
131     treap_insert(&(treap->root), i, rand());
132   in_order_traverse(treap->root);
133   printf("\n高度:%d\n", depth(treap->root));
134
135   printf("---分割线---\n");
136
137   for (i = 23; i < 59; i++)
138     treap_delete(&(treap->root), i);
139   in_order_traverse(treap->root);
140   printf("\n高度:%d\n", depth(treap->root));
141   return 0;
142 }


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: