SplayTree伸展树的非递归实现(自底向上)
Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得Splay Tree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的期望的时间复杂度还是O(nlogn)的。
下图是对伸展树查询节点1和删除节点6的结果,利用我的伸展树来实现

头文件————————————————————————————
#ifndef _SPLAY_TREE_H_
#define _SPLAY_TREE_H_ #include <iostream>
#include <iomanip>
#include <cassert>
#include <stack> typedef struct splay_tree_node_t
{
int data;
struct splay_tree_node_t *left;
struct splay_tree_node_t *right;
} splay_tree_node, *position, *splay_tree; void print_splay_tree(splay_tree st, int depth, int ctrl);//ctrl:0=root 1=left 2=right
position find_max(splay_tree st);
void insert_splay_tree(splay_tree *pst, int x);
void delete_splay_tree(splay_tree *pst, int x);
int find_splay_tree(splay_tree *pst, int x); splay_tree rotate3(position child, position parent, position grand_parent, int *type);
splay_tree rotate2(position child, position parent); inline void fcn(int type, position cur, position parent, position grand_parent);
#endif 源文件——————————————————————————————
#include "./SplayTree.h" splay_tree rotate3(position child, position parent, position grand_parent, int *type)
{
assert(child != NULL && parent != NULL && grand_parent != NULL); if(parent->left == child && grand_parent->left == parent)//child, parent, grand_parent一字形东北方向 0
{
*type = ;
grand_parent->left = parent->right;
parent->right = grand_parent; parent->left = child->right;
child->right = parent;
}
else if(parent->right == child && grand_parent->right == parent)//child, parent, grand_parent一字形西北方向 1
{
*type = ;
grand_parent->right = parent->left;
parent->left = grand_parent; parent->right = child->left;
child->left = parent;
}
else if(parent->right == child && grand_parent->left == parent)//child, parent, grand_parent之字形<
{
*type = ;
grand_parent->left = child->right;
parent->right = child->left;
child->left = parent;
child->right = grand_parent;
}
else if(parent->left == child && grand_parent->right == parent)//child, parent, grand_parent之字形>
{
*type = ;
grand_parent->right = child->left;
parent->left = child->right;
child->right = parent;
child->left - grand_parent;
} return child;
}
splay_tree rotate2(position child, position parent)
{
assert(child != NULL && parent != NULL);
if(parent->left == child)
{
parent->left = child->right;
child->right = parent;
}
else//parent->right == child
{
parent->right = child->left;
child->left = parent;
}
return child;
} position find_max(splay_tree st)
{
while(NULL != st && NULL != st->right)
st = st->right;
return st;
} void print_splay_tree(splay_tree st, int depth, int ctrl)
{
if(NULL != st)
{
std::cout<<std::setw(depth);
if( == ctrl)
std::cout<<"root:";
else if( == ctrl)
std::cout<<"left";
else if( == ctrl)
std::cout<<"right";
std::cout<<st->data<<std::endl;
print_splay_tree(st->left, depth+, );
print_splay_tree(st->right, depth+, );
}
}
void insert_splay_tree(splay_tree *pst, int x)
{
if(NULL == *pst)
{
position tmp = new splay_tree_node;
if(NULL == tmp)
return ;
tmp->data = x;
tmp->left = tmp->right = NULL;
*pst = tmp;
}
else if(x < (*pst)->data)
insert_splay_tree(&((*pst)->left), x);
else if(x > (*pst)->data)
insert_splay_tree(&((*pst)->right), x);
else
return ;
}
void delete_splay_tree(splay_tree *pst, int x)
{
assert(NULL != pst);
int res = find_splay_tree(pst, x);
if(res == )//not found
return ;
//此时root指向的就是要删除的节点,因为find_splay_tree操作将节点推至向根
position root = *pst;
splay_tree splay_left = root->left;
splay_tree splay_right = root->right;
position tmp = find_max(splay_left);
if(NULL == tmp)//无左子树
*pst = splay_right;//将右子树为新树
else
{
find_splay_tree(&splay_left, tmp->data);
splay_left->right = splay_right;//将右子树为左子树的新右子树
*pst = splay_left;//将左子树为新树
}
}
int find_splay_tree(splay_tree *pst, int x)
{
assert(NULL != pst);
position cur = *pst;
std::stack<position> s; while(cur != NULL && cur->data != x)//沿着查找路径将树节点以此压入栈中
{
if(x < cur->data)
{
s.push(cur);
cur = cur->left;
}
else
{
s.push(cur);
cur = cur->right;
}
} if(NULL == cur)//not found
return false; position parent, grand_parent;
int type = -;//0一字形东北方向; 1一字形西北方向; 2之字形<; 3之字形<
//每次取父节点和祖父节点和当前节点进行伸展调节
while(s.size() >= )
{
parent = s.top();
s.pop();
//fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展
fcn(type, cur, parent, grand_parent);
grand_parent = s.top();
s.pop();
cur = rotate3(cur, parent, grand_parent, &type);//after rotate, cur is the new "root"
}
if(s.empty())
*pst = cur;
else //rotate cur and the old root
{
parent = s.top();
s.pop();
fcn(type, cur, parent, grand_parent);
//此时只对cur和根节点进行伸展,完成后find_splay_tree函数结束
*pst = rotate2(cur, parent);
} return true;
} //fcn判断伸展的类型以便重新调整原来的树指针,调整好了才可以再次伸展
inline void fcn(int type, position cur, position parent, position grand_parent)
{
if(type == )
{
if(grand_parent == parent->left)
parent->left = cur;
else if(grand_parent == parent->right)
parent->right = cur;
}
else if(type == )
{
if(grand_parent == parent->left)
parent->left = cur;
else if(grand_parent == parent->right)
parent->right = cur;
}
else if(type == )
{
if(grand_parent == parent->left)
parent->left = cur;
else if(grand_parent == parent->right)
parent->right = cur;
}
else if(type == )
{
if(grand_parent == parent->left)
parent->left = cur;
else if(grand_parent == parent->right)
parent->right = cur;
}
}
SplayTree伸展树的非递归实现(自底向上)的更多相关文章
- Best Coder Round#25 1003 树的非递归访问
虽然官方解释是这题目里的树看作无向无环图,从答案来看还是在“以1作为根节点”这一前提下进行的,这棵树搭建好以后,从叶节点开始访问,一直推到根节点即可——很像动态规划的“自底向上”. 但这棵树的搭建堪忧 ...
- [SinGuLaRiTy] SplayTree 伸展树
[SinGuLaRiTy-1010]Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. Some Method Are Reprinted Fr ...
- 伸展树(一)之 图文解析 和 C语言的实现
概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...
- 伸展树(二)之 C++的实现
概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...
- 伸展树的实现——c++
一.介绍 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造.(01) 伸展树属于二叉 ...
- 归并排序(非递归,Java实现)
归并排序(非递归):自底向上 public class MergeSort { /** * @param arr 待排序的数组 * @param left 本次归并的左边界 * @param mid ...
- 伸展树--java
文字转载自:http://www.cnblogs.com/vamei 代码转载自:http://www.blogjava.net/javacap/archive/2007/12/19/168627.h ...
- wikioi 1396 伸展树(两个模板)
题目描写叙述 Description Tiger近期被公司升任为营业部经理.他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来 ...
- 伸展树(SplayTree)的实现
优点:伸展树(splay tree)是一种能自我调整的二叉搜索树(BST).虽然某一次的访问操作所花费的时间比较长,但是平摊(amortized) 之后的访问操作(例如旋转)时间能达到O(logn)的 ...
随机推荐
- Android MonoGame坑记
1.Content 加载声音API错误: 2.TouchPanel.GetState()属于抢占式的,用一次后面不能继续使用,否则状态尚属第一次: 3.TouchPanel 坐标来自于硬件本身: 4. ...
- javascript基础08
发现今天居然没有要写,那我就写写之前做的笔记吧. 这是事件的深入: 拖拽逻辑: 第一个: onmousedown : 选择元素 第二个: onmousemove : 移动元素 第三个:onmouseu ...
- VC++注册,卸载OCX控件,以及判断是否注册
注册OCX控件 BOOL CYourClass::RegistOcx() { HINSTANCE hLib = LoadLibrary("NTGraph.ocx"); / ...
- RFID 读写器 Reader Writer Cloner
RFID读写器的工作原理 RFID的数据采集以读写器为主导,RFID读写器是一种通过无线通信,实现对标签识别和内存数据的读出和写入操作的装置. 读写器又称为阅读器或读头(Reader).查询器(Int ...
- JS中的各种检测
//null 只在肯定返回null值时才使用null比较 var element = document.getElementById("my-div"); if (element ...
- Dom4J解析xml文件动态转换为List<Bean>或者Map集合
大家在解析大量相似xml文件的时候是否会遇到这样一个问题:冗余的代码去set定义的实体对象Bean的值,基本都是一样的操作 而且毫无任何代码价值可言所以在这写了一个简单的例子,类封装了几个方法你只 ...
- Why数学图像生成工具
该软件能够以给定的数学公式及算法生成各种绚烂的数学图像.软件中有两种生成图像的方法: (1)通过一种我自定义的脚本语言生成: 软件中定义一套简单易学的脚本语言,用于描述数学表达式.使用时需要先要将数学 ...
- 修改nginx服务器类型
通常nginx服务器不隐藏服务器类型及版本信息 curl -I http://www.aaa.com 获取web服务器的类型和版本代码 HTTP/1.1 200 OK Server: ...
- IOS中的网络编程
在移动互联网时代,几乎所有应用都需要用到网络下载,比如图片的加载,音乐的下载,安装包的下载,等等,下面我们来看看如何进行下载 一.文件的下载我们用get来请求数据,并对请求的二进制数据进行解析存入文件 ...
- State状态设计模式
1.状态模式:改变对象的行为 一个用来改变类的(状态的)对象. 2:问题:当你自己实现 State 模式的时候就会碰到很多细节的问题,你必须根据自己的需要选择合适的实现方法, 比如用到的状态(Stat ...