自平衡树--伸展树(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; }
相关文章推荐
- Splay Tree - 伸展树
- (转)伸展树 ( Splay tree )
- 伸展树 ( Splay tree )
- hdu 2871 Memory Control(伸展树splay tree)
- 树-伸展树(Splay Tree)
- hdu 1754 splay tree伸展树 初战(单点更新,区间属性查询)
- splay tree(伸展树)详解
- 【算法笔记】伸展树 Splay Tree
- 伸展树(splay tree)
- 伸展树模板小结(Splay Tree)
- 树堆Treap、伸展树Splay Tree
- 伸展树splay tree
- 伸展树(Splay tree)
- hdu 2871 Memory Control(伸展树splay tree)
- 纸上谈兵:伸展树(splay tree)
- Splay Tree(伸展树)
- 伸展树(splay tree)实现
- hdu 4699 Editor(splay tree 伸展树)
- [从头学数学] 第258节 Python实现数据结构:伸展树(splay tree)
- 数据结构Note:伸展树(Splay Tree)