首页 > 其他分享 >平衡樹專題Treap

平衡樹專題Treap

时间:2024-07-02 10:08:49浏览次数:19  
标签:int tree pos Treap lson 專題 平衡 size

前言:题单在此:HL平衡树0701 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

平衡树

什么是平衡树?

首先我们需要知道二叉查找树的内容。

二叉查找树(BST:Binary Search Tree)

首先,他是一棵二叉树

其次,他的左子树的权值<根节点的权值<右子树的权值

最后,也是最重要的,他的中序遍历顺序等于他的順序遍歷

這些特性使得一棵二叉查找樹支持很多操作

比如查詢,插入,刪除等...

我們從Treap開始

引用Steven24的博客原文,Treap=Tree+Heap

所以照此意思,Treap就應該是樹和堆的結合

的確如此。

但是兩種數據結構看起來是矛盾的,怎麼解決?

所以很巧妙

給每個鍵值一個隨機附加的優先級,讓鍵值滿足BST的結構,讓優先級滿足堆的結構

我們想一種特殊情況

就是我們每一個父親節點只有右兒子,那麼一個BST就變成了一條鏈

不僅如此,插入刪除的時候也很麻煩。因為如果插入或者刪除,整個樹原來的結構就會被打亂,這會為遍歷和查找帶來災難性的後果。

所以我們推出了平衡樹。就是通過將樹旋轉來動態維護這個樹形態是平衡的,這樣查找的複雜度就是O(log)級別的,是一種穩定的複雜度。

樹堆是一種平衡樹,它通過為鍵值(也就是我們需要維護成BST的)賦予優先順序,使之也滿足堆結構來進行旋轉,成為一棵平衡樹。

但是我們需要注意一點:樹堆的優先順序是隨機賦予的。也就是說,這個資料結構其實是一個隨機化的資料結構。這不是樹堆的缺點,因為只有隨機化賦予優先順序,才有可能保證樹堆的複雜度是O(log)的級別。

那麼,上述性質也說明了,樹堆並不是一個規則形態的二叉樹,更不是堆需要滿足的完全二叉樹。甚至它也不符合平衡樹的定義:每個節點左右子樹高度相差≤1≤1,所以我們說樹堆是近似實現平衡

但是通過形態定義二叉樹的方式並不絕對。我們換一種方式來對平衡樹進行定義:

能夠保證時間複雜度的BST,就是平衡樹。

Treap的操作

光看這個箭頭的話,還是很容易理解什麼是旋轉的。但是可能給讀者造成困擾的是:這個B節點的父親怎麼變了?

原因是這樣的:我們在進行旋轉操作的時候,要保證BST的節點遍歷順序是一樣的,而BST的節點遍歷順序是中序遍歷(這個是按BST的定義來的),也就是說只有這樣才能保證遍歷序不變的情況下調換節點位置。

所以,針對這個圖,我們把“P/F”看成一對節點,就能很好地理解這個“左/右旋”的操作了。

插入

首先我們瞭解一下BST的插入方式。其實很簡單,就是一個新節點插進去,從根節點開始不停地與當前節點比大小,一直到這個節點成為葉子節點為止。

因為Treap要同時維護BST和堆,所以我們還需要在裡面加上旋轉操作。

如果是右兒子的話要左旋,左兒子要右旋(旋轉操作請結合上圖理解)。

然後我們又多統計了一個size的資料,這個資料表示子樹大小,在統計當前數x是第幾大的時候會很方便。

應該很簡單。

Treap插入

struct node
{
    int val,pri,size,lson,rson;//val键值,pri优先级,size子树大小。
}tree[maxn];
int tot;
void L_rotate(int &pos)
{
    node x=tree[tree[pos].rson];//x表示要转到上面的节点
    tree[pos].rson=x.lson;
    x.lson=pos;
    x.size=tree[pos].size;
    maintain(pos);
    tree[pos]=x;
}
void R_rotate(int &pos)
{
    node x=tree[tree[pos].lson];
    tree[pos].lson=x.rson;
    x.size=tree[pos].size;
    maintain(pos);
    tree[pos]=x;
}
void maintain(int pos)
{
    tree[pos].size=tree[tree[pos].lson].size+tree[tree[pos].rson].size+1;
}
void insert(int &pos,int x)
{
    if(!pos)
    {
        pos=++tot;
        tree[pos].val=x;
        tree[pos].pri=rand();
    }
    if(x<tree[pos].val)
    {
        insert(tree[pos].lson,x);
        if(tree[pos].pri<tree[lson].pri)//如果优先级不匹配,就旋转(这里维护的是大根堆)
          R_rotate(pos);
    }
    else
    {
        insert(tree[pos].rson,x);
        if(tree[pos].pri<tree[rson].pri)
          L_rotate(pos);
    }
    maintain(pos);
}

Treap刪除

刪除操作的大體思路和插入是一樣的。也是要保證刪除前後滿足Treap的雙重結構。

大致是這樣的思路:首先找到這個點在哪。然後,如果這個點已經是葉子節點,就直接將其刪除,如果不是,就一層層地將它轉到底部,然後進行刪除。這和我們的插入操作有異曲同工之妙,就是進行操作的一定是葉子節點,如果不是葉子的話是不能粗暴刪除的。需要轉。

Treap刪除
 void remove(int &pos,int x)
{
    if(!pos)
      return;
    if(x==tree[pos].val)
    {
        if(tree[pos].lson|tree[pos].rson)//如果非叶子节点
        {
            if(tree[tree[pos].lson].pri>tree[tree[pos].rson].pri)
              R_rotate(pos),remove(tree[pos].lson,x);
            else
              L_rotate(pos),remove(tree[pos].rson,x);
            maintain(pos);
        }
        else
          pos=0;
    }
    else
    {
        if(x<tree[pos].val)
          remove(tree[pos].lson,x);
        else
          remove(tree[pos].rson,x);
    }
    if(pos)
      maintain(pos);
}

Treap查詢I

也就是對某數進行排名

查詢操作不涉及修改,根據樹堆的雙重性質,其操作是跟BST是一樣的。

Treap查詢I
int rank(int pos,int x)
{
    if(!pos)
      return 1;
    if(x<tree[pos].val)
      return rank(tree[pos].lson,x);
    else
      return rank(tree[pos].rson,x)+tree[tree[pos].lson].size+1;
}
int rank(int pos,int x,int &cnt)
{
    if(!pos)
      return -1;
    if(x==tree[pos].val)
      return cnt+=tree[tree[pos].lson].size;
    else
    {
        if(x<tree[pos].val)
          rank(tree[pos].lson,x,cnt);
        else
          cnt+=(tree[tree[pos].lson].size+1),rank(tree[pos].rson,x,cnt);
    }
}

Treap查詢II

查詢第k大的數

Treap查詢II
 int kth(int pos,int k)
{
    if(!pos || k<=0 || k>tree[pos].size)
      return -1;
    if(k==tree[tree[pos].lson].size+1)
      return tree[pos].val;
    else if(k<=tree[tree[pos].lson].size)
      return kth(tree[pos].lson,k);
    else
      return kth(tree[pos].rson,k-tree[tree[pos].lson].size-1);
}

Treap查詢III

查詢前驅或後繼

Treap查詢III
 #define INF 1e9
int prev(int pos,int x)
{
    if(!pos)
      return -INF;
    if(x<tree[pos].val)
      return prev(tree[pos].lson,x);
    else
      return max(tree[pos].val,prev(tree[pos].rson,x));
}
int nxt(int pos,int x)
{
    if(!pos)
      return INF;
    if(x>=tree[pos].val)
      return nxt(tree[pos].rson,x);
    else
      return min(tree[pos].val,nxt(tree[pos].lson,x));
}

Treap遍歷

中序遍歷,left->root->right

Treap遍歷
 void dfs(int pos)
{
    if(tree[pos].lson)
      dfs(tree[pos].lson);
    printf("%d ",tree[pos].val);
    if(tree[pos].rson)
      dfs(tree[pos].rson);
}

标签:int,tree,pos,Treap,lson,專題,平衡,size
From: https://www.cnblogs.com/MerlinForLee/p/18279359

相关文章

  • 测试开发比,能代表质效平衡吗?
    看到一个很有意思的话题:测试团队需要保障质量,同时也要考虑测试效率,质量和效率之间的平衡,其实很大程度上取决于测试和开发的人数占比。只有先保证资源上的平衡,才能在保障质量的同时保证一定的测试效率。这个话题背后的逻辑成立吗?我仔细思考了这个问题,表面看似合乎逻辑,但经不起分......
  • 47、基于连续Hopfield神经网络的不稳定平衡
    1、连续Hopfield神经网络的不稳定平衡原理及流程连续Hopfield神经网络是一种用于模式识别和记忆的神经网络模型,其基本原理是通过权重矩阵来存储并检索各种模式。不稳定平衡指的是在Hopfield网络中,输入的模式通过网络的动态演化最终会达到一个平衡状态,该状态可能是存储的模式之......
  • 智能优化算法应用:基于平衡优化器算法PID参数优化 - 附代码
    智能优化算法应用:基于平衡优化器算法PID参数优化-附代码文章目录智能优化算法应用:基于平衡优化器算法PID参数优化-附代码1.PID简介2.平衡优化器算法简介3.适应度函数设计4.算法实验与结果5.参考文献:6.Matlab代码摘要:本文主要介绍如何用平衡优化器算法进行PID参......
  • B树的阶数:平衡与效率的关键
    在计算机科学中,B树是一种专为系统I/O操作优化的多路搜索树。它通过其独特的结构和性质,确保了数据的快速存取和高效的空间利用率。B树的阶数是定义B树结构和行为的一个基本参数,对于理解B树的工作原理至关重要。B树的定义与特性B树是一种n阶树,其中每个节点可以拥有的最大子......
  • [题解]P3391 文艺平衡树 - Splay解法
    P3391【模板】文艺平衡树给定序列\(1,2,\dots,n\),接下来\(m\)次操作,每次操作给定\(l,r\),你需要翻转\([l,r]\)。所有操作结束后,请输出这个序列。我们先从“普通平衡树”这一题出发,思考一下Splay操作的本质。我们把一个节点Splay到根节点后,中序遍历在自己前面的节点都在左边,中......
  • 算法课程笔记——FHQ-Treap(无旋)
    算法课程笔记——FHQ-Treap(无旋)......
  • [lnsyoj118/luoguP3369]普通平衡树
    题意维护一个数据结构,要求支持插入,删除,根据排名查数,根据数查排名,查询前驱,查询后继\(6\)个操作sol考虑到后四个查询的操作,会发现使用二叉搜索树(BST)完全可以实现为了完成这四个操作,需要在每个节点记录\(3\)个值:\(key\)表示当前节点的数\(cnt\)表示当前节点的数的个数(为了......
  • 平衡树
    1.splay普通权值平衡树【模板】普通平衡树二叉查找树:又:二叉搜索树、二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左、右子树也分别......
  • C语言二叉平衡搜索树
    AVL(二叉平衡搜索树)的概念和思路任意一个节点左子树高度-右子树高度<=1要想让BST保持平衡,必须在每一次插入、删除之后,检查是否其左右子树满足平衡的定义如果不满足,就做“旋转”操作,使其恢复平衡加入以上平衡策略算法后的BST,称为AVL,AVL是一种绝对平衡的二叉树#include......
  • Day17| 110.平衡二叉树、 257. 二叉树的所有路径 、 404.左叶子之和
    110.平衡二叉树(优先掌握递归)再一次涉及到,什么是高度,什么是深度,可以巩固一下。题目链接/文章讲解/视频讲解:https://programmercarl.com/0110.平衡二叉树.html#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):......