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伸展树的非递归实现(自底向上)的更多相关文章

  1. Best Coder Round#25 1003 树的非递归访问

    虽然官方解释是这题目里的树看作无向无环图,从答案来看还是在“以1作为根节点”这一前提下进行的,这棵树搭建好以后,从叶节点开始访问,一直推到根节点即可——很像动态规划的“自底向上”. 但这棵树的搭建堪忧 ...

  2. [SinGuLaRiTy] SplayTree 伸展树

    [SinGuLaRiTy-1010]Copyrights (c) SinGuLaRiTy 2017. All Rights Reserved. Some Method Are Reprinted Fr ...

  3. 伸展树(一)之 图文解析 和 C语言的实现

    概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...

  4. 伸展树(二)之 C++的实现

    概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...

  5. 伸展树的实现——c++

     一.介绍 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造.(01) 伸展树属于二叉 ...

  6. 归并排序(非递归,Java实现)

    归并排序(非递归):自底向上 public class MergeSort { /** * @param arr 待排序的数组 * @param left 本次归并的左边界 * @param mid ...

  7. 伸展树--java

    文字转载自:http://www.cnblogs.com/vamei 代码转载自:http://www.blogjava.net/javacap/archive/2007/12/19/168627.h ...

  8. wikioi 1396 伸展树(两个模板)

    题目描写叙述 Description Tiger近期被公司升任为营业部经理.他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来 ...

  9. 伸展树(SplayTree)的实现

    优点:伸展树(splay tree)是一种能自我调整的二叉搜索树(BST).虽然某一次的访问操作所花费的时间比较长,但是平摊(amortized) 之后的访问操作(例如旋转)时间能达到O(logn)的 ...

随机推荐

  1. MongoDB图形化管理工具

    NoSQL的运动不止,MongoDB 作为其中的主力军发展迅猛,也带起了一股开发图形化工具的风潮:气死反过来说,看一个产品是否得到认可,可以侧面看其第三方工具的数量和成熟程度:简单的收集了MongoD ...

  2. linux服务器调整参数支持高并发

    服务端调整系统的参数,在/etc/sysctl.conf中: ◦net.core.somaxconn = 2048◦net.core.rmem_default = 262144◦net.core.wm ...

  3. android 6.0权限判断 音频 拍照 相册

    ------------------------------------------打开音频权限------------------------------------------------ if ...

  4. CentOS 7.2 搭建 Ghost 博客

    因为平时记录一些文档或想法基本使用 markdown 的语法,Mac 下推荐一款 markdown 的编辑器 Haroopad:上周无意发现 Ghost 有支持 Mac 的桌面版本了,并且同样开源 h ...

  5. [原创]Android自定义View之IndicatorView,显示当前tab页所处位置的View

    概述 Android IndicatorView的灵感来源于SlidingTabView,虽然有句"不重复"造轮子在先,本着练手的目的,还是写了一个功能较为简单的类似view. 其 ...

  6. android 抓包 使用 tcpdmp + Wireshark

         下载地址tcpdump: http://www.androidtcpdump.com/      使用su用户, 给/system/可写的权限 mount -o remount,rw -t ...

  7. 在Windows2008系统中利用IIS建立FTP服务器

    一.服务器管理器   1.2008的系统使用服务器管理器,选择角色,因为我之前已经开启了IIS服务器角色,所以我现在只要添加角色服务即可,如果你没有开启过的话,直接添加角色即可.   2.选择WEB服 ...

  8. WinStore控件之TextBlock

    1  TextBlock简单实例应用 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}&quo ...

  9. 6x12了快2个月,累的不行……

    6x12了快2个月,累的不行…… 咱就是传说中的会iOS, Android, .NET,JAVA, JAVASCRIPT,SQL SERVER的 Full stack developer (全端工程师 ...

  10. JS实现TITLE悬停长久显示效果

    canrun <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www. ...