Splay-Tree理解
简介
splay tree其实就是不停的旋转,没进行一个操作都要进行旋转;例如,当访问某一个结点的时候,会通过旋转其结点使得该结点变为树根,这样保证其的平均复杂度为O(nlogn);
其的操作包括:
-
查找:如果查找成功(找到的话),那么由于伸展操作,被查找的结点成为新的树根;但是如果查找失败的话(没有找到),那么在查找遇到NULL之前的那个结点将会成为新的根,也就是距离要查找的值的最靠近的值的结点;
-
插入:根据BST的性质进行插入到相应的位置,接着执行伸展,将该值旋转到根结点上;
-
查找最大最小:利用BST的性质查找,查找之后要伸展,将查找的值伸展到根上;
-
删除:先将要删除的结点伸展至根上,将左子树上最大的结点伸展至左子树的根结点(保证右子树为空),再将右子树连接到左子树的右结点上,删除跟结点,此时左子树的根结点为根;
-
合并:将两个伸展树S1与S2合并成为一个伸展树。其中S1的所有元素都小于S2的所有元素。首先,我们找到伸展树S1 中最大的一个元素x,再通过Splay(x,S1)将x 调整到伸展树S1 的根。然后再将S2 作为x 节点的右子树。这样,就得到了新的伸展树S。如图:
-
分离:以x 为界,将伸展树S 分离为两棵伸展树S1 和S2,其中S1中所有元素都小于x,S2中的所有元素都大于x。首先执行Find(x,S),将元素x 调整为伸展树的根节点,则x 的左子树就是S1,而右子树为S2。如图:
注意
分为自顶向下和自底向上,自底向上需要关注到每个结点的左右子结点还有父亲结点和祖父结点,但是自顶向下则只需要关注左右子结点;
下面将会有自顶向下和自底向上两种实现方法:
原理
伸展树的重点在于伸展,伸展一共有六种旋转,分别是左单旋转,右单旋转,左左旋转,右右旋转,左右旋转,右左旋转,后四种旋转均可以通过前面两种旋转实现;
1.zig/zag(右单旋转/左单旋转)
我们发现
当结点x是结点y的左子结点时,我们对结点x进行一次右旋,使得结点x是结点y的根结点;
当结点y是结点x的右子结点时,我们对结点y进行一次左旋,使得结点y为结点x的根结点;
需要注意的是,上面的情况是自顶向下的,也就是会对子结点进行旋转,但是如果是自底向上的话,则会对父结点进行旋转;
2.zigzag/zagzig(右左旋转/左右旋转)
这个旋转也称为双旋转;
如图
当结点x的父结点不为根结点,同时x为父结点y的左子结点,y为z的右子结点,则称为右左旋转,先对结点x进行一次右旋转,此时y结点为x结点的右子结点,这时三个结点连成一条线,接着对父结点进行一次左旋转,使得x结点为根结点;
相反操作则称为左右旋转;
3.zigzig/zagzag(左左旋转/右右旋转)
上面两种情况均是之前AVL树中就存在的,但是这个情况是Splay树中才存在的;
当x结点和y结点均为其父结点的左子结点时,则称为zagzag,此时先右旋转y结点,再右旋转x结点;
相反则称为右右旋转,也就是zigzig
实现
自顶向下
//
// main.cpp
// splay
//
// Created by staff on 16/10/28.
// Copyright © 2016年 George1994. All rights reserved.
//
#include <iostream>
/*
* C++ Program to Implement Splay Tree
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
struct splay
{
int key;
splay* lchild;
splay* rchild;
};
class SplayTree
{
public:
SplayTree()
{
}
// RR(Y rotates to the right)
splay* RR_Rotate(splay* k2)
{
splay* k1 = k2->lchild;
k2->lchild = k1->rchild;
k1->rchild = k2;
return k1;
}
// LL(Y rotates to the left)
splay* LL_Rotate(splay* k2)
{
splay* k1 = k2->rchild;
k2->rchild = k1->lchild;
k1->lchild = k2;
return k1;
}
// An implementation of top-down splay tree
splay* Splay(int key, splay* root)
{
if (!root)
return NULL;
splay header;
/* header.rchild points to L tree;
header.lchild points to R Tree */
header.lchild = header.rchild = NULL;
splay* LeftTreeMax = &header;
splay* RightTreeMin = &header;
while (1)
{
if (key < root->key)
{
if (!root->lchild)
break;
if (key < root->lchild->key)
{
root = RR_Rotate(root);
// only zig-zig mode need to rotate once,
if (!root->lchild)
break;
}
/* Link to R Tree */
RightTreeMin->lchild = root;
RightTreeMin = RightTreeMin->lchild;
root = root->lchild;
RightTreeMin->lchild = NULL;
}
else if (key > root->key)
{
if (!root->rchild)
break;
if (key > root->rchild->key)
{
root = LL_Rotate(root);
// only zag-zag mode need to rotate once,
if (!root->rchild)
break;
}
/* Link to L Tree */
LeftTreeMax->rchild = root;
LeftTreeMax = LeftTreeMax->rchild;
root = root->rchild;
LeftTreeMax->rchild = NULL;
}
else
break;
}
/* assemble L Tree, Middle Tree and R tree */
LeftTreeMax->rchild = root->lchild;
RightTreeMin->lchild = root->rchild;
root->lchild = header.rchild;
root->rchild = header.lchild;
return root;
}
splay* New_Node(int key)
{
splay* p_node = new splay;
if (!p_node)
{
fprintf(stderr, "Out of memory!\n");
exit(1);
}
p_node->key = key;
p_node->lchild = p_node->rchild = NULL;
return p_node;
}
splay* Insert(int key, splay* root)
{
static splay* p_node = NULL;
if (!p_node)
p_node = New_Node(key);
else
p_node->key = key;
if (!root)
{
root = p_node;
p_node = NULL;
return root;
}
// 先进行旋转
root = Splay(key, root);
/* This is BST that, all keys <= root->key is in root->lchild, all keys >
root->key is in root->rchild. */
// 再insert
if (key < root->key)
{
p_node->lchild = root->lchild;
p_node->rchild = root;
root->lchild = NULL;
root = p_node;
}
else if (key > root->key)
{
p_node->rchild = root->rchild;
p_node->lchild = root;
root->rchild = NULL;
root = p_node;
}
else
return root;
p_node = NULL;
return root;
}
splay* Delete(int key, splay* root)
{
splay* temp;
if (!root)
return NULL;
root = Splay(key, root);
if (key != root->key)
return root;
else
{
if (!root->lchild)
{
temp = root;
root = root->rchild;
}
else
{
temp = root;
/*Note: Since key == root->key,
so after Splay(key, root->lchild),
the tree we get will have no right child tree.*/
root = Splay(key, root->lchild);
root->rchild = temp->rchild;
}
free(temp);
return root;
}
}
splay* Search(int key, splay* root)
{
return Splay(key, root);
}
void InOrder(splay* root)
{
if (root)
{
InOrder(root->lchild);
cout<< "key: " <<root->key;
if(root->lchild)
cout<< " | left child: "<< root->lchild->key;
if(root->rchild)
cout << " | right child: " << root->rchild->key;
cout<< "\n";
InOrder(root->rchild);
}
}
};
int main()
{
SplayTree st;
int vector[10] = {9,8,7,6,5,4,3,2,1,0};
splay *root;
root = NULL;
const int length = 10;
int i;
for(i = 0; i < length; i++) {
root = st.Insert(vector[i], root);
cout<<"\nInOrder: \n";
st.InOrder(root);
}
int input, choice;
if(1)
{
cout<<"\nSplay Tree Operations\n";
cout<<"1. Insert "<<endl;
cout<<"2. Delete"<<endl;
cout<<"3. Search"<<endl;
cout<<"4. Exit"<<endl;
cout<<"Enter your choice: ";
cin>>choice;
switch(choice)
{
case 1:
cout<<"Enter value to be inserted: ";
cin>>input;
root = st.Insert(input, root);
cout<<"\nAfter Insert: "<<input<<endl;
st.InOrder(root);
break;
case 2:
cout<<"Enter value to be deleted: ";
cin>>input;
root = st.Delete(input, root);
cout<<"\nAfter Delete: "<<input<<endl;
st.InOrder(root);
break;
case 3:
cout<<"Enter value to be searched: ";
cin>>input;
root = st.Search(input, root);
cout<<"\nAfter Search "<<input<<endl;
st.InOrder(root);
break;
case 4:
exit(1);
default:
cout<<"\nInvalid type! \n";
}
}
cout<<"\n";
return 0;
}
自顶向上
.hpp
//
// SBTree.hpp
// SBTree
//
// Created by staff on 16/10/8.
// Copyright © 2016年 George1994. All rights reserved.
//
#ifndef SBTree_hpp
#define SBTree_hpp
namespace SBTree {
template <class T>
class TreeNode {
public:
TreeNode(T value) : value(value), left(nullptr), right(nullptr), parent(nullptr) {}
T value;
TreeNode* left;
TreeNode* right;
TreeNode* parent;
};
template <class T>
class Tree {
public:
Tree();
Tree(TreeNode<T>* root) : root(root) {};
~Tree();
static Tree<T>* getInstance();
static void destroyInstance();
void Insert(T value);
void Delete(T value);
TreeNode<T>* Find(T value);
void Traversal();
T mininum();
T maxmum();
private:
TreeNode<T>* root; // 跟节点
static Tree * tree;
void insertNode(TreeNode<T>* &root, TreeNode<T>* node);
void deleteNode(TreeNode<T>* &root, T value);
TreeNode<T>* searchNode(TreeNode<T>* &root, T value);
void splay(TreeNode<T>* &root, T value);
void traversalNode(TreeNode<T>* root);
void destroy(TreeNode<T>* &root);
// zig:右旋 zag:左旋
void singleLeftRotate(TreeNode<T>* &root);
void singleRightRotate(TreeNode<T>* &root);
void zigzagRotate(TreeNode<T>* &root);
void zagzigRotate(TreeNode<T>* &root);
void zigzigRotate(TreeNode<T>* &root);
void zagzagRotate(TreeNode<T>* &root);
T mininum(TreeNode<T>* &root);
T maximum(TreeNode<T> &root);
};
void insertTest();
void deleteTest();
void searchTest();
void teversalTest();
void maxTest();
void minTest();
}
#endif /* SBTree_hpp */
.cpp
//
// SBTree.cpp
// SBTree
//
// Created by staff on 16/10/8.
// Copyright © 2016年 George1994. All rights reserved.
//
#include "SBTree.hpp"
#include <iostream>
#include <string>
#include <cassert>
#include <vector>
namespace SBTree {
typedef Tree<int> ITree;
int getInputInt(const char* content) {
std::cout << content << ":";
int input;
std::cin >> input;
return input;
}
void LogErr(const char* content) {
assert(content);
std::cout << "Error:" << content << std::endl;
}
template <class T>
Tree<T>::Tree() {
root = nullptr;
}
template <class T>
Tree<T>::~Tree() {
destroy();
}
/**
* 插入结点的同时旋转树把结点旋转为跟节点
*
* @param value <#value description#>
*/
template <class T>
void Tree<T>::Insert(T value) {
TreeNode<T>* node = new TreeNode<T>(value);
if (root == nullptr) {
root = node;
return ;
}
insertNode(root, node);
splay(root, value);
}
template <class T>
void Tree<T>::Delete(T value) {
deleteNode(root, value);
}
template <class T>
TreeNode<T>* Tree<T>::Find(T value) {
splay(root, value);
return root;
}
template <class T>
T Tree<T>::mininum() {
if (!root) {
return -1;
}
TreeNode<T> *node = root;
while (node->left) {
node = node->left;
}
splay(root, node->value);
return node->value;
}
template <class T>
T Tree<T>::maxmum() {
if (!root) {
return -1;
}
TreeNode<T> *node = root;
while (node->right) {
node = node->right;
}
splay(root, node->value);
return node->value;
}
/**
* 目标结点是跟结点的右子结点,对子结点进行左旋
*/
template <class T>
void Tree<T>::singleLeftRotate(TreeNode<T>* &node) {
TreeNode<T> *rchild = node->right;
TreeNode<T> *parent = node->parent;
if (rchild->left) {
rchild->left->parent = node;
}
node->right = rchild->left;
rchild->left = node;
rchild->parent = parent;
if (parent) {
if (parent->left == node) {
parent->left = rchild;
}
else {
parent->right = rchild;
}
}
node->parent = rchild;
node = rchild;
}
/**
* 目标结点是跟结点的左子结点,对子结点进行右旋
*/
template <class T>
void Tree<T>::singleRightRotate(TreeNode<T>* &node) {
TreeNode<T> *lchild = node->left;
TreeNode<T> *parent = node->parent;
if (lchild->right) {
lchild->right->parent = node;
}
node->left = lchild->right;
lchild->parent = parent;
lchild->right = node;
if (parent) {
if (parent->left == node) {
parent->left = lchild;
}
else {
parent->right = lchild;
}
}
node->parent = lchild;
node = lchild;
}
/**
* 目标结点在右边,父结点在左边,即之字型
*/
template <class T>
void Tree<T>::zagzigRotate(TreeNode<T>* &node) {
singleLeftRotate(node->left);
singleRightRotate(node);
if (node->parent == nullptr) {
root = node;
}
std::cout << "zagzigRotate" << std::endl;
}
/**
* 目标结点在左边,父结点在右边,即之字型
*/
template <class T>
void Tree<T>::zigzagRotate(TreeNode<T>* &node) {
singleRightRotate(node->right);
singleLeftRotate(node);
if (node->parent == nullptr) {
root = node;
}
std::cout << "zigzagRotate" << std::endl;
}
/**
* 目标结点和父结点和祖父结点均在右边,为zig-zig,即一字型,先左旋转父结点,再左旋转目标结点
*/
template <class T>
void Tree<T>::zigzigRotate(TreeNode<T>* &node) {
TreeNode<T> *father = node->right;
singleLeftRotate(father);
singleLeftRotate(node);
if (node->parent == nullptr) {
root = node;
}
std::cout << "zigzigRotate" << std::endl;
}
/**
* 目标结点和父结点和祖父结点均在左边,为zag-zag,即一字型,先右旋转父结点,再右旋转目标结点
*/
template <class T>
void Tree<T>::zagzagRotate(TreeNode<T>* &node) {
TreeNode<T> *father = node->left;
singleRightRotate(father);
singleRightRotate(node);
if (node->parent == nullptr) {
root = node;
}
std::cout << "zagzagRotate" << std::endl;
}
/**
* 1.当目标结点是根节点的左子结点或者右子结点,进行单旋转(左旋转和右旋转),将目标结点调整到根结点
* 2.当目标结点和父结点和祖父结点构成“之”字形时,进行双旋转(左右旋转和右左旋转),将目标结点调整到祖父结点
* 3.当目标结点和父结点和祖父结点构成“一”字形时,进行zig-zig旋转(左左旋转和右右旋转),将目标结点调整到祖父结点
*
* @param root <#root description#>
* @param value <#value description#>
*/
template <class T>
void Tree<T>::splay(TreeNode<T>* &node, T value) {
TreeNode<T>* nodeparent = node->parent;
TreeNode<T>* fNode = searchNode(root, value);
if (!fNode || (node->left == nullptr && node->right == nullptr)) {
return;
}
while (fNode->parent != nodeparent) {
if (fNode->parent == node) {
// 单旋转情况
if (node->left == fNode) {
singleRightRotate(node);
}
else {
singleLeftRotate(node);
}
node->parent = fNode;
fNode->parent = nodeparent;
}
else {
TreeNode<T> *parent = fNode->parent;
TreeNode<T> *grandparent = parent->parent;
bool fNodeLeft = parent->left == fNode; // 目标结点的左右情况
bool parentLeft = grandparent->left == parent; // 父结点的左右情况
if (parentLeft) {
if (fNodeLeft) {
zagzagRotate(grandparent); // 左左
}
else {
zagzigRotate(grandparent); // 左右
}
}
else {
if (fNodeLeft) {
zigzagRotate(grandparent); // 右左
}
else {
zigzigRotate(grandparent); // 右右
}
}
}
}
}
template <class T>
void Tree<T>::insertNode(TreeNode<T>* &root, TreeNode<T>* node) {
if (node->value > root->value) {
if (root->right == nullptr) {
root->right = node;
node->parent = root;
}
else {
insertNode(root->right, node);
}
}
else if (node->value <= root->value) {
if (root->left == nullptr) {
root->left = node;
node->parent = root;
}
else {
insertNode(root->left, node);
}
}
}
template <class T>
void Tree<T>::deleteNode(TreeNode<T>* &node, T value) {
splay(node, value);
// TreeNode<T> *ntree;
// 用左子树的最大点替换
if (node->left == nullptr) {
node = node->right;
}
else if (node->right == nullptr) {
node = node->left;
}
else {
// 找到左子树的最大结点,并且将其翻转倒左子树的跟结点位置,也就是跟的左结点
// 然后将跟的右结点连到跟的左结点上
TreeNode<T> *rnode = node->right;
TreeNode<T> *tmpnode = node->left;
while (tmpnode->right != nullptr) {
tmpnode = tmpnode->right;
}
splay(node->left, tmpnode->value);
node = node->left;
node->parent = nullptr;
if (rnode) {
rnode->parent = node;
}
node->right = rnode;
}
node->parent = nullptr;
root = node;
}
template <class T>
TreeNode<T>* Tree<T>::searchNode(TreeNode<T>* &root, T value) {
if (root == nullptr) {
return nullptr;
}
if (value > root->value) {
return searchNode(root->right, value);
}
else if (value < root->value) {
return searchNode(root->left, value);
}
else {
return root;
}
}
template <class T>
void Tree<T>::traversalNode(TreeNode<T>* root) {
if (root == nullptr) return;
if (root->left) traversalNode(root->left);
std::cout << root->value;
if (root->parent) {
if (root->left) {
std::cout << " | left child is:" << root->left->value;
}
if (root->right) {
std::cout << " | right child is:" << root->right->value;
}
std::cout << " | parent is:" << root->parent->value << std::endl;
}
else {
std::cout << " | is root" << std::endl;
}
if (root->right) traversalNode(root->right);
}
template <class T>
void Tree<T>::destroy(TreeNode<T>* &root) {
if (root == nullptr) {
return;
}
if (root->left) destroy(root->left);
if (root->right) destroy(root->right);
delete root;
}
template <class T>
T Tree<T>::mininum(TreeNode<T>* &root) {
}
template <class T>
T Tree<T>::maximum(TreeNode<T> &root) {
}
template <class T>
void Tree<T>::Traversal() {
assert(root != nullptr);
traversalNode(root);
std::cout << std::endl;
}
template <class T>
Tree<T>* Tree<T>::tree = nullptr;
template <class T>
Tree<T>* Tree<T>::getInstance() {
if (tree == nullptr) {
tree = new Tree<T>();
}
return tree;
}
template <class T>
void Tree<T>::destroyInstance() {
assert(tree == nullptr);
delete tree;
}
void insertTest() {
for (int i = 0; i <= 9; i = i + 1) {
ITree::getInstance()->Insert(i);
}
}
void searchTest() {
int input = getInputInt("please input the search value");
TreeNode<int> *node = ITree::getInstance()->Find(input);
std::cout << "Node value:" << node->value << std::endl;
}
void deleteTest() {
int input = getInputInt("please input the delete value");
ITree::getInstance()->Delete(input);
}
void teversalTest() {
ITree::getInstance()->Traversal();
}
void maxTest() {
int result = ITree::getInstance()->maxmum();
std::cout << "max:" << result << std::endl;
}
void minTest() {
int result = ITree::getInstance()->mininum();
std::cout << "min:" << result << std::endl;
}
}
上面这个是我实现的,但是还是有各种各样的bug,还待完善吧。。。
![](https://i.loli.net/2018/11/17/5beff4d639cbb.jpg)
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法