数据结构 - 伸展树 Splay Tree

目录

一、什么是伸展树?

80-20黄金法则显示,日常中我们80%的访问发生在20%的数据上。

如果我们能够把经常访问的节点推到靠近根节点的位置,那么就可以极大的提高访问速度。

这就是伸展树的出发点,并实现了以下方案:每次查找节点之后对树进行重构(旋转操作),把被查找的节点搬移到树根。

与二叉平衡树相比,伸展树不会保证树一直是平衡的,甚至可能是一个糟糕的单链表,但是它各种操作的平摊时间复杂度是O(log n)。

二、Splay操作的设计模式

伸展树的设计有两种设计模式,一种“自底向上”,一种“自顶向下”。

由于伸展树的操作需要访问其父结点和祖父结点,那么“自底向上”的设计就需要额外的指针指向结点的父结点,来为我们提供访问的方式,这就需要额外的空间了。

//自底向上
struct SplayNode{
	int value;
	SplayNode *parent; //额外指针指向父结点
	SplayNode *left, *right;
	SplayNode(int val):value(val), left(NULL), right(NULL){}
};

因此本文主要讨论“自顶向下”的模式,因此延展树的定义如下。

//自顶向下
struct SplayNode{
	int value;
	SplayNode *left, *right;
	SplayNode(int val):value(val), left(NULL), right(NULL){}
};

class SplayTree{
public:
	SplayTree(): root(NULL){}
	SplayTree(vector<int> &arr);
	void Splay(int val);
	//....
private:
	//....
	SplayNode* root;
};

三、伸展树的旋转操作

假设X是一个非根点的被访问结点:

  • 如果X的父结点是root,那我们可以直接旋转X和root。
  • 如果X除了有父结点P,还有一个祖父结点G,那么就有两种情景(实际是四种,但是镜像),分别为Zig-Zag和Zig-Zig。

3.1 父结点是root

3.1.1 左旋

访问结点X在父结点的左边,旋转操作:P的左子树挂载X的右子树,然后P成为X的右子树。

在这里插入图片描述

SplayNode* SplayTree::LeftRotation(SplayNode* G){
	SplayNode* X = G->left;
	G->left = X->right;
	X->right = G;
	return X;
}
3.1.2 右旋

访问结点X在父结点P的右边,旋转操作:P的右子树挂载X的左子树,然后P成为X的左子树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值