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

数据结构-Treap(树堆) 详解 Treap(树堆)是一种弱平衡的搜索树,与平衡树相同,Treap就是由Tree和Heap(树和堆)两种数据结构组合而成的数据结构。 Treap的每个节点上要额外储存一个值prioritypriority,代表每个节点的优先级。因此对于每个节点,不仅要满足二叉搜索树的基本性质,还需额外满足父节点的prioritypriority大于两个子节点的prioritypriority。实际上,这个prioriotypriorioty值又被称为"修正值"。 阅读详情
 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;
}
UE5 AI寻路全攻略:从Nav Mesh基础到动态障碍与多模式导航 在游戏开发中,AI寻路是赋予非玩家角色自主移动能力的关键技术。其核心原理是通过预计算或实时生成一个表示可行走区域的导航网格,AI路径查找算法(如A*)在此网格上规划最优路径。这项技术的价值在于,它能极大提升游戏世界的真实感和交互性,使NPC能够智能地绕开障碍、穿越复杂地形,广泛应用于开放世界、RPG、策略游戏等多种场景。本文聚焦于虚幻引擎5的寻路系统,深入探讨其寻路网格体配置。针对动态环境挑战,文章详细介绍了如何利用寻路修饰体积和动态障碍物组件实现导航网格的实时更新;同时,针对游泳、飞行等特殊移动需求,解析 阅读详情

相关推荐

从solidworks导出URDF模型

一、下载sw_urdf_exporter插件 ROS目前提供了SolidWorks转URDF的插件,叫做sw_urdf_exporter,从http://wiki.ros.org/sw_urdf_exporter下载sw2urdfSetup.exe文件,下载后点击安装,安装完成后就能在solidworks中导出URDF模型了。 二、创建solidworks模型 下面以较为简单的四轮小车为例进行说...

weixin_45168199的博客 4万+

树:Treaps

中完成,因为在每个节点上,人们可以根据比较删除树的一半,因此需要对数比较才能到达正确的节点(要添加或删除元素的位置)。函数在 BST 中搜索正确的位置,并在正确的位置添加节点,即根据 BST 和堆属性向右添加,并在添加后根据需要进行必要的旋转,对于旋转,将分别编写。(每个节点最多有 2 个子节点),这样左边的子节点存储的键小于根节点,右边的子节点存储的键大于根键,这对所有节点递归有效。是节点数,因为必须遍历路径中的所有节点才能到达正确的节点,在最坏的情况下可能是最后一个节点,例如,假设我们想在树中添加。

新华编程特战队 1237

单片机如何获得5V电源

在单片机实际设计中,有时会需要在电路中用到5V电压源,那么这个常见的实验需求有哪些办法解决呢,我综合网上的资料,概括一下: 1)USB    这种方法在我们直接将单片机板与电脑连接调试的时候,算是简单又方便的办法了,但如果我所要得到的成品不直接连接外部的器件,这就得舍弃。     常用的,USB/5V插头线,这是一种专门的电源线,一端是USB通用接口,可以直插USB端口,另一端是内正外负电压

Echo_Ana的博客 3万+

数据结构-非旋TREAP

Treap=Tree+Heap

Ice_teapoy的博客 816

光通信仿真入门:手把手教你用VPI和Matlab搭建第一个联合仿真系统(含避坑指南)

本文详细介绍了如何使用VPI和Matlab搭建光通信联合仿真系统,涵盖软件配置、链路搭建、数据交互等关键环节,并提供常见问题的解决方案。特别适合初学者快速掌握光通信仿真技术,避免常见错误,提升仿真效率。

weixin_28733637的博客 378

FAST-LIO论文公式解析

FAST-LIO论文公式解析

努力努力努力 670

【数据结构】Treap树堆

Treap就是Tree+heap,首先有二叉搜索树(BST)的数据,treapCnt记录当前的节点总数,节点和键值的映射key,每个节点的左右儿子childs,以及一个键可能存在多个副本,用cnt记录副本数,size记录子树大小,用于查找第k大元素。堆相关的数据:每个节点的优先级priority,这个优先级在创建节点时随机生成,保证了Treap的深度不会太大。

qq_23096319的博客 843

C语言从句柄到对象 (一) —— 全局变量的噩梦与“多实例”的救赎

本文探讨了嵌入式开发中句柄(Handle)的概念与应用。通过电机控制案例,分析了传统单例模式在扩展性上的局限,并展示了如何通过句柄实现代码复用:将电机状态封装为结构体,通过指针(句柄)传递实例数据,使同一套逻辑可操作多个实例。文章比较了单例模式与句柄模式的适用场景,建议底层驱动库默认采用句柄模式以提高扩展性。最后指出当前实现仍存在数据暴露风险,预告下期将介绍不透明指针技术实现更安全的封装。全文揭示了句柄作为C语言实现模块化和面向对象设计的关键作用。

一路往蓝-Anbo 的博客 1340

浅析Treap——平衡树

浅析Treap——平衡树

Andy_L の 小窝 372

用 SAP CDS View 和 Fiori Elements 快速打造 CRM Service Order 应用──十分钟跑通从数据模型到上线的全流程

通过CDS 视图 + Fiori Elements的组合,我们得以在极短时间内把传统 CRM Service Order 场景迁移到现代化的 Fiori 界面,而且代码量极小、可维护性高。若后续需要离线能力,可考虑将同一 OData 服务暴露给 Mobile Services,再配合 MDK 或 UI5 Mobile Toolkit;若要支持复杂审批流,则可以在同一 Launchpad 内嵌入 Process Visibility Dashboard,实现端到端可视化。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 390

【ComfyUI专栏】ComfyUI 常用工作流下载与分享网址

首先我们来分享第一个网站,Openart 网站,这个网站同时也能提供比较多的其他类型。但是如果希望下载工作流,我们可以访问到如下的这个站点。作为ComfyUI的学习用户来说,我们通常需要借助他山之石来帮助我们快速成长,因此我们需要找到能够分享和下载的网址。,当前网站是综合性网站,在网站中可以下载各种不同的类型,其中工作流只是可以下载的非常小的部分。这个网站也可以浏览不同的工作流,这个工作流的地址和访问如下的站点。

技术与管理的平衡木- 7792

数据结构之平衡树(Treap)

平衡树是二叉搜索树和堆合并构成的新数据结构,所以它的名字取了Tree和Heap各一半,叫做Treap。 堆和树的性质是冲突的,二叉搜索树满足左子树<根节点<右子树,而堆是满足根节点小于等于(或大于等于)左右儿子。因此在Treap的数据结构中,并不是以单一的键值作为节点的数据域。Treap每个节点的数据域包含2个值,key和weight。 key值,和原来的二叉搜索树一样,满足左子树<根节点<右子

long-long-ago 2万+

【WorkBuddy专栏14】专家不是「换皮」——角色切换、训练机制与自我进化深度拆解

WorkBuddy专栏14】专家不是「换皮」——角色切换、训练机制与自我进化深度拆解

AI人人懂 593

【数据结构】Treap

讲解平衡树中的Treap

OI博客 1696

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

算法导论13-4:Treap

花了一晚上终于解决了《算法导论》13-4 中的思考题 Treap,之前学习的时候就发现这块的内容网上都找不到什么参考资料,面对a---j这几个思考题一筹莫展,今晚静下心来好好研究了下,发现也不是那么难啃。搞算法,就是要沉得住气。

彦祖老师 2633

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Fhq-Treap总结:短小精悍不旋转的神级数据结构

Fhq-Treap 首先我们从二叉搜索树讲起(顺便复习) 我们知道我们访问一个节点所需要的时间复杂度和他的深度有直接的关系,比如说一个N个节点的完全二叉树访问一个节点的最坏复杂度是O(logN)O(logN)O(logN),但是如果在一条N个节点的链中访问一个节点的最坏复杂度就是O(N)O(N)O(N),所以想要速度够快,那么树的结构一定要尽量平衡,保持在logNlogNlogN左右。 为了...

私は Mocha!! 9805

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

fhq-treap简介

\(fhq-treap\)是个好东西啊!无旋转\(treap\)果然是好写,而且还是比较好理解的。 这种数据结构是由神犇fhq发明的。\(Think\ functional!\) fhq神犇说,函数式编程的一大特点就是,不修改,只定义。普通的平衡树,无论是treap还是splay,都需要进行旋转来维护树的平衡性。 fhq神犇是通过可持久化线段树引入的。主席树其实就是一种函数式编程的产物。主席树中没...

weixin_30411819的博客 699

数据结构之Treap

1. 概述 同splay tree一样,treap也是一个平衡二叉树,不过Treap会记录一个额外的数据,即优先级。Treap在以关键码构成二叉搜索树的同时,还按优先级来满足堆的性质。因而,Treap=tree+heap。这里需要注意的是,Treap并不是二叉堆,二叉堆必须是完全二叉树,而Treap可以并不一定是。 2. Treap基本操作 为了使Treap 中的节点同时满足BST性质和最小

bo-jwolf的专栏 1027

数据结构——Treap

数据结构——Treap简介实现节点结构节点信息更新左旋右旋插入删除查询前驱(不大于指定值的最大值)查询后驱(不小于指定值的最小值)查询第K大的值查询排名 简介 树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简单,且能基本实现随机平...

qq_39721774的博客 582

无旋转Treap简介

  无旋转Treap是一个神奇的数据结构,能够支持插入,删除,查询k大,查询某个数的排名,查询前驱后继,支持各种区间操作和持久化。基于旋转的Treap无法实现区间反转等操作,但是无旋Treap可以轻易地支持区间操作。那为什么区间操作不用Splay而要去学无旋转Treap?原因很简单,Splay的时间复杂度是均摊的不能可持久化,而且无旋转Treap的代码量少得起飞(明明是yyf的Spl...

adx33526的博客 370

Treap简介

树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。

forezxl的博客 601

[数据结构]Treap简介

[写在前面的话]   如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋转,建议自行上百度)[here]   Treap(= binary search Tree + Heap),中文通常译作树堆,为每个节点附加一个优先值,让优先值满足堆的...

adx33526的博客 133

谈谈数据结构-Treap

谈谈数据结构-Treap 分类:Data Structure Treap 1. Treap原理 Treap=(Binary Search)Tree + Heap。 Treap 去掉fix域和rotate过程,就是一个很简单的排序二叉树BST。 虽然在插入数据完全离散的情况下,BST的期望复杂度也是O(logn)O(log⁡n)O(\log n),但是,无论是在算法竞赛中,还是实际情...

Fighting! 598

浅谈无旋treap(fhq_treap)

一、简介 无旋Treap(fhq_treap),是一种不用旋转的treap,其代码复杂度不高,应用范围广(能代替普通treap和splay的所有功能),是一种极其强大的平衡树。 无旋Treap是一个叫做范浩强的大佬发明的(快%啊!) 在我们一起学习无旋Treap之前,本蒟蒻有几句活想说: 1.无旋Treap我个人认为是最容易理解的一种平衡树,而且编程复杂度不高,功能还那么强大。 ...

aaa3201的博客 1646

C++数据结构 —— 平衡树Treap

介绍并实现了平衡树Treap

m0_46329175的博客 1140

【无旋Treap】数据结构课程项目报告

数据结构课程项目报告 (建议使用Typora打开此报告) 此博客仅供学习交流,请勿抄袭 设计一个合理的数据结构,使用尽量少的时间复杂度和空间复杂度,支持一些常见操作。此外,尽可能多的支持扩展操作。 一.基本思路 1.结构选择 ​ 在本项目中,我将实现一个名为LinearTable的数据结构,来支持一些常见操作。对于最基本的操作,可以使用deque的实现思路解决,但当需要做到任意中间位置插入元素的时候,大部分线性连接结构的性能将会大幅下降至O(n)O(n)O(n)。因此,本项目会采用更为灵活的

George_Plover的博客 628
上一篇: ubuntu下使用scim输入特殊符号
下一篇: 数据结构之:treap 简介(二)
unicode1985
博客等级 码龄22年 2粉丝 29原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值