为防止广告,目前nocow只有登录用户能够创建新页面。如要创建页面请先登录/注册(新用户需要等待1个小时才能正常使用该功能)。
Splay Tree
参考WC2004,杨思雨论文
目录 |
[编辑] 介绍
本节描述一种相对简单的数据结构,叫做伸展树(splay tree),它保证从空树开始任意连续M次对树的操作最多花费O(MlogN)时间。虽然这种保证并不排除任意单次操作花费O(N)时间的可能,而且这样的界也不如每次操作最坏情形的界为O(logN)时那么强,但是实际效果是一样的:不存在不好的输入序列。
Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得Splay Tree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的均摊时间复杂度还是O(logn)的。
这里先介绍一下左旋(zag)和右旋(zig)的操作 文件:Http://hi.csdn.net/attachment/201107/21/0 13112275721N3Z.gif
然后就是Splay Tree进行Splay操作的具体步骤,主要分两种情况:
文件:Http://hi.csdn.net/attachment/201107/21/0 1311227785J1FJ.gif 先看图中的左边,查找到的x节点的父节点是y,x是y的左子树,y的父节点z是根节点,y也是z的左子树,要把x旋转到根节点的位置,就要进行zig(y),然后再进行zig(x)操作
再看图中的右边,查找到的z节点的父节点是y,z是y的右子树,y的父节点x是根节点,y也是x的右子树,要把z旋转到根节点的位置,就要进行zag(y),然后进行zag(x)操作
文件:Http://hi.csdn.net/attachment/201107/21/0 1311228052Kr0Y.gif
若是途中的情况,若需要把x移动到根节点,则需要先进行zig(x),然后再进行zag(x)操作
还有一种y是z的左子树,x是y的右子树的情况,这时就需要先进行zag(x),然后再进行zig(x)操作了
[编辑] 操作
[编辑] 伸展Splay
/** * Internal method to perform a top-down splay. * The last accessed node becomes the new root. * This method may be overridden to use a different * splaying algorithm, however, the splay tree code * depends on the accessed item going to the root. * x is the target item to splay around. * t is the root of the subtree to splay. */ void splay( const Comparable & x, BinaryNode * & t ) { BinaryNode *leftTreeMax, *rightTreeMin; static BinaryNode header; header.left = header.right = nullNode; leftTreeMax = rightTreeMin = &header; nullNode->element = x; // Guarantee a match for( ; ; ) if( x < t->element ) { if( t->left == nullNode ) break; if( x < t->left->element ) rotateWithLeftChild( t ); // Link Right rightTreeMin->left = t; rightTreeMin = t; t = t->left; } else if( t->element < x ) { if( t->right == nullNode ) break; if( t->right->element < x ) rotateWithRightChild( t ); // Link Left leftTreeMax->right = t; leftTreeMax = t; t = t->right; } else break; leftTreeMax->right = t->left; rightTreeMin->left = t->right; t->left = header.right; t->right = header.left; }
[编辑] 插入Insert
void insert( const Comparable & x ) { static BinaryNode *newNode = NULL; if( newNode == NULL ) newNode = new BinaryNode; newNode->element = x; if( root == nullNode ) { newNode->left = newNode->right = nullNode; root = newNode; } else { splay( x, root ); if( x < root->element ) { newNode->left = root->left; newNode->right = root; root->left = nullNode; root = newNode; } else if( root->element < x ) { newNode->right = root->right; newNode->left = root; root->right = nullNode; root = newNode; } else return; } newNode = NULL; // So next insert will call new }
[编辑] 查找Find
[编辑] 删除Delete
void remove( const Comparable & x ) { BinaryNode *newTree; // If x is found, it will be at the root if( !contains( x ) ) return; // Item not found; do nothing if( root->left == nullNode ) newTree = root->right; else { // Find the maximum in the left subtree // Splay it to the root; and then attach right child newTree = root->left; splay( x, newTree ); newTree->right = root->right; } delete root; root = newTree; }