近期開始了自己高级数据结构之旅,在这次旅行中。我将持续把一些高级的数据结构从理论到编码都过一遍,同一时候通过博客形式分享出来。希望大家指出不足之处!

二叉排序树是一种动态排序的数据结构。支持插入、删除、查找等操作。且平均时间复杂度为O(log(N)),可是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N)。

此时,平衡二叉树的产生了。平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树非常难,于是人们使用AVL、红黑树、Treap、伸展树等来替代平衡二叉树,这些数据结构能够非常好地改善最坏情况。但实现起来并非非常easy的事。

Treap是Heap+Tree,通俗来讲就是堆与树的结合,每一个节点除了keywordkey以及节点之间的连接关系外,还要保存一个优先级priority,注意这里的优先级不同于其它节点的随机数字,随机才干较好的期望平衡度,保证能够非常好维护二叉树的性质。当中在Treap中keywordkey遵循二叉查找树的性质,即:

(1)、空树是一颗二叉查找树。

(2)、若左子树不为空,则左子树中的所有keyword均小于该节点keyword;

(3)、若右子树不为空,则右子树中的所有keyword均不小于该节点keyword。

(4)、若左右子树非空。则左右子树也是一颗二叉查找树。

Treap中的优先级priority遵循Heap的性质,此处的堆已不再是棵全然二叉树,而是用指针取代数组下标实现的树结构,满足全部根节点优先级小于(或大于)左右孩子节点的优先级(在左右孩子存在的情况下,小于为小顶堆,大于为大顶堆)。

因为每一个节点上的优先级是随机产生的,所以期望高度能够达到非常好的程度。

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

Treap支持二叉树的全部操作,且平摊时间复杂度为O(log(N)),便于实现,性能好,克服了二叉查找树最坏情况时间复杂度为O(N)的弊端,有不存在AVL、红黑树等编码和理解难度,与伸展树有类似优点。

以下简要谈谈Treap的几种基本操作。

左旋:

右旋:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGoyNDE5MTc0NTU0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

以上截图来自http://www.cnblogs.com/huangxincheng/archive/2012/07/30/2614484.html。在此表示感谢!

查找:

查找直接用二叉树的性质,參考源码。

插入:

先找到插入位置,在运行插入操作,然后维护堆的性质,即依据优先级调整以维护小顶堆或大顶堆的性质。关于维护队的性质,參考我前面的关于对的博客。

删除:

类比二叉查找树一样,删除结点存在三种情况:

(1)、叶子结点,跟二叉查找树一样,直接释放本节点就可以。

(2)、仅仅有一个还自己节点,跟二叉查找树一样操作。

(3)、有两个孩子节点,能够像二叉查找树一样转换为删除右子树最小节点或左子树最大节点,然后将仅仅赋值到本应删除的节点处,此时能够一起复制优先级,然后向该分支调整,也可不赋值优先级保留原来的优先级,我的程序保留原来优先级。

更新:

先删除原节点,然后插入新节点。

因为期望高度为O(log(N))。所以以上全部操作的平潭时间复杂度为O(log(N))。

代码:

之前写了个带父亲指针的。感觉有点复杂,于是写了以下这段代码。查看带父亲指针的代码点击此处,感觉那个封装的比較好。

#include<iostream>
#include<ctime>
using namespace std; class Treap
{
private:
int num,key,pri;
Treap *child[2];
public:
int compare(int);
Treap(int);
Treap* rotate(Treap*,int);
Treap* erase(Treap*,int);
Treap* leafNode();
bool find(int);
void setNum();
Treap* insert(Treap*,int);
void rotatePrint(Treap*,int);
}; Treap::Treap(int tKey)
{
num=0;
key=tKey;
pri=rand()%1000;
child[0]=child[1]=NULL;
} int Treap::compare(int tKey)
{
return key<tKey?1:0;
} void Treap::setNum()
{
num=1;
if(child[0]!=NULL)
num+=child[0]->num;
if(child[1]!=NULL)
num+=child[1]->num;
} Treap*Treap::rotate(Treap* tRoot,int dir)
{
Treap* ch=tRoot->child[dir];
tRoot->child[dir]=ch->child[dir^1];
ch->child[dir^1]=tRoot;
tRoot->setNum();
ch->setNum();
return ch;
} Treap* Treap::insert(Treap *tRoot,int tKey)
{
if(NULL==tRoot)
return new Treap(tKey);
int dir=this->compare(tKey);
tRoot->child[dir]=tRoot->child[dir]->insert(tRoot->child[dir],tKey);
if(tRoot->pri>tRoot->child[dir]->pri)
tRoot=rotate(tRoot,dir);
else tRoot->setNum();
return tRoot;
} Treap* Treap::leafNode()
{
if(NULL==child[0]&&NULL==child[1])
{
delete this;
return NULL;
}
else if(NULL==child[0])
{
Treap *p=this->child[1];
delete this;
return p;
}
else if(NULL==child[1])
{
Treap *p=this->child[0];
delete this;
return p;
}
} Treap* Treap::erase(Treap* tRoot,int tKey)
{
if(NULL==tRoot)
return NULL;
if(key==tKey)
{
if(child[0]==NULL||child[1]==NULL)
return leafNode();
Treap *q=this,*p=this->child[1];
bool left=false;
while(p->child[0]!=NULL)
{
left=true;
q=p;
p=p->child[0];
}
this->key=p->key;
if(!left)
q->child[1]=p->leafNode();
else q->child[0]=p->leafNode();
return this;
}
int dir=this->compare(tKey);
tRoot->child[dir]=tRoot->child[dir]->erase(tRoot->child[dir],tKey);
return tRoot;
} bool Treap::find(int tKey)
{
if(NULL==this)
return false;
if(key==tKey)
return true;
int dir=this->compare(tKey);
return child[dir]->find(tKey);
} void Treap::rotatePrint(Treap* tRoot,int dep)
{
if(NULL==tRoot)
return ;
rotatePrint(tRoot->child[0],dep+1);
for(int i=0;i<dep;i++)
cout<<" ";
cout<<"("<<tRoot->key<<"。"<<tRoot->pri<<")"<<endl;
rotatePrint(tRoot->child[1],dep+1);
} void menu()
{
//Treap *root=new Treap(10);
Treap *root=NULL;
srand(unsigned(clock()));
int val,choice;
while(true)
{
cout<<"***************菜单*************"<<endl;
cout<<" 1.插入"<<endl;
cout<<" 2.删除"<<endl;
cout<<" 3.查找"<<endl;
cout<<" 4.退出"<<endl;
cout<<"您的选择:[ ]\b\b\b";
cin>>choice;
cout<<"请输入数:";
cin>>val;
if(1==choice)
root=root->insert(root,val);
else if(2==choice)
root=root->erase(root,val);
else if(3==choice)
{
if(root->find(val))
cout<<"查找成功!"<<endl;
else cout<<"查找失败!"<<endl;
}
else if(4==choice)
exit(0);
cout<<"==================="<<endl;
root->rotatePrint(root,0);
}
} int main()
{
while(true)
menu();
}

Treap的读书笔记2的更多相关文章

  1. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  2. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  3. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  4. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  5. C#刨根究底:《你必须知道的.NET》读书笔记系列

    一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...

  6. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

  7. LOMA280保险原理读书笔记

    LOMA是国际金融保险管理学院(Life Office Management Association)的英文简称.国际金融保险管理学院是一个保险和金融服务机构的国际组织,它的创建目的是为了促进信息交流 ...

  8. 《3D Math Primer for Graphics and Game Development》读书笔记2

    <3D Math Primer for Graphics and Game Development>读书笔记2 上一篇得到了"矩阵等价于变换后的基向量"这一结论. 本篇 ...

  9. 《3D Math Primer for Graphics and Game Development》读书笔记1

    <3D Math Primer for Graphics and Game Development>读书笔记1 本文是<3D Math Primer for Graphics and ...

随机推荐

  1. js中this指向问题

    1.在全局范围内使用this的时候  它指向的是全局对象 this Window {top: Window, window: Window, location: Location, external: ...

  2. docNet基础学完感想

    开学后的一个多月因为要准备acm省赛,所以docnet视频基本没看了!不过,虽然在省赛前每天都在做题,赛前刷了80多题吧!!但是比赛的时候就3题,渣啊!只做出了3个水题,后面两个小时搞两题就是出不来, ...

  3. News feed

    1. Level 1.0 Database Schema: a. User UserID Name Age 1 Jason 25 2 Michael 26 b. Friendship Friendsh ...

  4. 使用wininet向FTP服务器发送文件

    .h #pragma once #include <windows.h> #include <tchar.h> #include <string> #include ...

  5. 1.2. chromium源代码分析 - chromiumframe - 入口函数

    ChromiumFrame的入口函数在main.cpp中,打开main.cpp.中包含3个类和_tWinMain函数._tWinMain就是我们要找的入口函数.我做了部分注释: int APIENTR ...

  6. cocos2d-x教程1 hello world

    HelloworldScene.h #ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos ...

  7. 编写带参数decorator

    无参的@log装饰器: def log(f): def fn(x): print 'call ' + f.__name__ + '()...' return f(x) return fn 发现对于被装 ...

  8. poj 1410 计算几何

    /** 注意: 千万得小心..就因为一个分号,调了一个晚上... **/ #include <iostream> #include <algorithm> using name ...

  9. 射频识别技术漫谈(18)——Mifare Desfire

    Mifare  DESFire(MF3 IC D40/D41,本文以D40为例)遵守14443 TypeA协议,卡内的数据以文件形式存储,所以有人认为它是准CPU卡,主要用于安全性要求较高的非接触式领 ...

  10. HDU 3328 Flipper

    题解:直接建n个栈,模拟过程即可…… #include <cstdio> #include <cstring> #include <stack> using nam ...