您的位置:首页 > 其它

自平衡树--伸展树(Splay Tree)

2018-01-28 20:15 393 查看

Splay Tree介绍

BST树的插入、查询、删除的最大时间为O(n),此种情况出现在整个树伸展成只有一个分支。但是自平衡的AVL树和红-黑树的最大时间为O(logn)。

在计算机中。我们经常遇到一个问题:就是80%的访问只仅仅使用20%的数据。我们想在O(1)的时间内能访问到这20%的数据。这就是Splay Tree的主要使用场景,splay tree会把最近访问的项作为tree的跟节点,这使得最近访问的项可以在O(1)的时间内可以被再次访问

所有的Splay Tree的平均操作时间为O(logn),n是树的节点数。任何单一的操作在最糟糕的情况下可能需要O(n)。

Splay Tree搜索

splay tree的搜索操作同BST的搜索操作,但是除了搜索外,它还需要伸展(移动访问的节点到跟节点)。如果搜索成功,则把搜索到的节点移动到根节点。如果搜索不成功,则把搜索到的最后一个节点移动到跟节点。

在进行Splay Tree搜索时,可能有一下四种情况被遇到

访问的节点就是跟元素

我们直接返回跟节点的内容,不作任何处理。

访问的节点是root节点的子节点

此节点没有爷爷节点,此节点要么是root节点的左节点,我们右转。如果此节点是root节点的右节点,我们左转。



访问的节点含有父节点和爷爷节点。

访问的节点是父节点的左孩子。父节点是爷爷节点的左孩子。我们进行两次右转。



访问的节点是父节点的右孩子。父节点时爷爷节点的右孩子。我们进行两次左转。



访问的节点是父节点的左孩子。而父节点是爷爷节点的右孩子。我们可以进行一次左旋、一次右旋:



访问的节点是父节点的右孩子。而父节点是爷爷节点的左孩子。我们可以进行一次右旋、一次左旋。



Splay Tree java实现

public class SplayTree {
private static class Node {
private Node left;
private Node right;
private int val;

public Node(int val) {
this.val = val;
}
}

/**
* 节点树的插入
* @param node
* @param key
*/
private static void insert (Node node ,int key) {

if (key == node.val) {
return ;
}

if (key < node.val) {
if (node.left == null) {
node.left = new Node(key);
}
else {
insert(node.left,key);
}
}
else if (key > node.val) {
if (node.right == null) {
node.right = new Node(key);
} else {
insert(node.right,key);
}
}
}

/**
* 搜索节点
* @param node
* @param key
* @return
*/
public static Node search(Node node,int key) {
if (node == null || node.val == key) {
return node;
}
if (node.val > key) {
//左节点为空,直接返回跟节点
if (node.left == null) {
return node;
}

if (node.left.val > key) {
node.left.left = search (node.left.left,key);
node = roateRight(node);
}

//处理左旋、右旋
else if (node.left.val < key) {
node.left.right = search(node.left.right,key);
if (node.left.right != null) {
node.left = roateLeft(node.left);
}
}

if (node.left != null) {
return roateRight(node);
}
else {
return node;
}
}
else {
if (node.right == null) {
return node;
}
if (node.right.val < key) {
node.right.right = search(node.right.right,key);
node = roateLeft(node);
}
else if (node.right.val > key) {
node.right.left = search(node.right.left,key);
if (node.right.left != null) {
node.right = roateRight(node.right);
}
}
if (node.right != null) {
return roateLeft(node);
} else {
return node;
}
}
}

/**
* 左旋实现
* @param node
* @return
*/
private static Node roateLeft(Node node) {
Node root = node.right;
Node templeft = root.left;
node.right = templeft;
root.left = node;
return root;
}

/**
* 右旋实现
* @param node
* @return
*/
private static Node roateRight(Node node) {
Node root = node.left;
Node tempRight = root.right;

root.right = node;
node.left = tempRight;

return root;
}

/**
* 前序遍历
* @param root
*/
private static void preNode(Node root) {
if (root != null) {
System.out.print(root.val +" ");
preNode(root.left);
preNode(root.right);
}
}

/**
* 层序遍历
* @param args
*/
private static void levelNode(Node root) {
Queue<Node> queue = new LinkedList<SplayTree.Node>();
queue.add(root);
Node topNode = null;
while (!queue.isEmpty()) {
int size = queue.size();
int i = 0;
while (i < size) {
topNode = queue.poll();
System.out.print(topNode.val + " ");
if (topNode.left != null) {
queue.add(topNode.left);
}
if (topNode.right != null) {
queue.add(topNode.right);
}
i = i + 1;
}
System.out.println();
}
}

public static void main(String[] args) {
Node root = new Node(20);
insert(root,10);
insert(root,30);
insert(root,5);
root = search(root,10);
levelNode(root);
}
}


Splay Tree树的插入

在Splay Tree树中插入一个节点有以下几种情况:

如果根节点为null,则直接划分一个新的节点作为一个root节点并返回。

在Splay Tree中,如果对于给定的一个key在Splay Tree中存在,然后把此节点作为根节点。如果给定的一个key在Splay Tree中不存在,然后把最后访问的一个节点作为根节点返回。

如果要插入的节点的值跟root节点的值不同,则不做任何处理。

如果要插入的节点的值跟root节点的值不同,则划分新的节点然后跟root节点的值做比较:

1> 如果插入的key 小于root的key。然后root作为新节点的右孩子,copy root节点的左孩子作为新节点的左孩子。并使root.left = null;

2> 如果插入的key大于root的key。然后root作为新节点的左孩子,copy root节点的右孩子作为新节点的右孩子。并使得root.right = null;

返回新的节点作为根节点。

public static Node insert(Node node,int key) {
if (node == null) {
return new Node(key);
}

node = search(node,key);

if (key == node.val) {
return node;
}

Node newNode = new Node(key);
if (key > node.val) {
newNode.left = node;
newNode.right = node.right;
node.right = null;
}

if (key < node.val) {
newNode.right = node;
newNode.left = node.left;
node.left = null;
}
return newNode;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: