zoukankan      html  css  js  c++  java
  • Splay



    /*
    为什么要有伸展树 根据80-20黄金法则即80%的访问发生在20%的数据上,所以如果我们能够把经常访问的节点推到靠近根节点的位置, 那么就可以极大的提高访问速度。 根据这个思路,我们提出了 “ 旋转到根 ” 这一思路, 具体的:每次查找、插入、删除一个节点,我们都使用旋转的方法把这个节点旋转到根节点的位置, 并且因为旋转操作能够很好的把其他访问路径上的节点向上移动, 所以最后这经常访问的20%的数据基本上都处于靠近根节点的位置 普通AVL树的旋转和伸展树的旋转有什么不同? AVL树的旋转操作目的是缩小左右子树的高度差,它是全局调控即目的是缩小整棵树的高度, 不会针对某一个节点做优化(例如将经常访问的节点移动到根的位置或靠近根的位置) 相反,伸展树的旋转操作目的就是把经常访问的节点移动到根的位置,它不会考虑整棵树是否平衡,旋转完成后, 伸展树可能成为一个糟糕的单链表,但伸展树保证在此单链表上查找经常访问的20%节点是最快的。 */ #include "stdafx.h" #include <iomanip> #include <iostream> using namespace std; #define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) ) template <class T> class SplayTreeNode { public: T Key; // 关键字(键值) SplayTreeNode *LeftNode; // 左孩子 SplayTreeNode *RightNode; // 右孩子 SplayTreeNode() :LeftNode(NULL), RightNode(NULL) {} SplayTreeNode(T value, SplayTreeNode *l, SplayTreeNode *r) : Key(value), LeftNode(l), RightNode(r) {} }; template <class T> class SplayTree { private: SplayTreeNode<T> *RootNode; // 根结点 public: SplayTree(); ~SplayTree(); // 前序遍历"伸展树" void PreOrder(); // 中序遍历"伸展树" void InOrder(); // 后序遍历"伸展树" void PostOrder(); // (递归实现)查找"伸展树"中键值为Key的节点 SplayTreeNode<T>* Search(T Key); // (非递归实现)查找"伸展树"中键值为Key的节点 SplayTreeNode<T>* IterativeSearch(T Key); // 查找最小结点:返回最小结点的键值。 T MinNumber(); // 查找最大结点:返回最大结点的键值。 T MaxNumber(); // 旋转Key对应的节点为根节点,并返回值为根节点。 void Splay(T Key); // 将结点(Key为节点键值)插入到伸展树中 void InsertNode(T Key); // 删除结点(Key为节点键值) void RemoveNode(T Key); // 销毁伸展树 void DestorySplayTree(); // 打印伸展树 void PrintSplayTree(); private: // 前序遍历"伸展树" void PreOrder(SplayTreeNode<T>* SplayTree) const; // 中序遍历"伸展树" void InOrder(SplayTreeNode<T>* SplayTree) const; // 后序遍历"伸展树" void PostOrder(SplayTreeNode<T>* SplayTree) const; // (递归实现)查找"伸展树x"中键值为Key的节点 SplayTreeNode<T>* Search(SplayTreeNode<T>* x, T Key) const; // (非递归实现)查找"伸展树x"中键值为Key的节点 SplayTreeNode<T>* IterativeSearch(SplayTreeNode<T>* x, T Key) const; // 查找最小结点:返回tree为根结点的伸展树的最小结点。 SplayTreeNode<T>* MinNumber(SplayTreeNode<T>* SplayTree); // 查找最大结点:返回tree为根结点的伸展树的最大结点。 SplayTreeNode<T>* MaxNumber(SplayTreeNode<T>* SplayTree); // 旋转Key对应的节点为根节点,并返回值为根节点。 SplayTreeNode<T>* Splay(SplayTreeNode<T>* SplayTree, T Key); // 将结点(z)插入到伸展树(tree)中 SplayTreeNode<T>* InsertNode(SplayTreeNode<T>* &SplayTree, SplayTreeNode<T>* z); // 删除伸展树(tree)中的结点(键值为Key),并返回被删除的结点 SplayTreeNode<T>* RemoveNode(SplayTreeNode<T>* &SplayTree, T Key); // 销毁伸展树 void DestorySplayTree(SplayTreeNode<T>* &SplayTree); // 打印伸展树 void PrintSplayTree(SplayTreeNode<T>* SplayTree, T Key, int Direction); }; /* * 构造函数 */ template <class T> SplayTree<T>::SplayTree() :RootNode(NULL) { } /* * 析构函数 */ template <class T> SplayTree<T>::~SplayTree() { DestorySplayTree(RootNode); } /* * 前序遍历"伸展树" */ template <class T> void SplayTree<T>::PreOrder(SplayTreeNode<T>* SplayTree) const { if (SplayTree != NULL) { cout << SplayTree->Key << " "; PreOrder(SplayTree->LeftNode); PreOrder(SplayTree->RightNode); } } template <class T> void SplayTree<T>::PreOrder() { PreOrder(RootNode); } /* * 中序遍历"伸展树" */ template <class T> void SplayTree<T>::InOrder(SplayTreeNode<T>* SplayTree) const { if (SplayTree != NULL) { InOrder(SplayTree->LeftNode); cout << SplayTree->Key << " "; InOrder(SplayTree->RightNode); } } template <class T> void SplayTree<T>::InOrder() { InOrder(RootNode); } /* * 后序遍历"伸展树" */ template <class T> void SplayTree<T>::PostOrder(SplayTreeNode<T>* SplayTree) const { if (SplayTree != NULL) { PostOrder(SplayTree->LeftNode); PostOrder(SplayTree->RightNode); cout << SplayTree->Key << " "; } } template <class T> void SplayTree<T>::PostOrder() { PostOrder(RootNode); } /* * (递归实现)查找"伸展树x"中键值为Key的节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::Search(SplayTreeNode<T>* x, T Key) const { if (x == NULL || x->Key == Key) return x; if (Key < x->Key) return Search(x->LeftNode, Key); else return Search(x->RightNode, Key); } template <class T> SplayTreeNode<T>* SplayTree<T>::Search(T Key) { return Search(RootNode, Key); } /* * (非递归实现)查找"伸展树x"中键值为Key的节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::IterativeSearch(SplayTreeNode<T>* x, T Key) const { while ((x != NULL) && (x->Key != Key)) { if (Key < x->Key) x = x->LeftNode; else x = x->RightNode; } return x; } template <class T> SplayTreeNode<T>* SplayTree<T>::IterativeSearch(T Key) { return IterativeSearch(RootNode, Key); } /* * 查找最小结点:返回tree为根结点的伸展树的最小结点。 */ template <class T> SplayTreeNode<T>* SplayTree<T>::MinNumber(SplayTreeNode<T>* SplayTree) { SplayTreeNode<T> *TempNode = SplayTree; if (TempNode == NULL) return NULL; while (TempNode->LeftNode != NULL) TempNode = TempNode->LeftNode; return TempNode; } template <class T> T SplayTree<T>::MinNumber() { SplayTreeNode<T> *p = MinNumber(RootNode); if (p != NULL) return p->Key; return (T)NULL; } /* * 查找最大结点:返回tree为根结点的伸展树的最大结点。 */ template <class T> SplayTreeNode<T>* SplayTree<T>::MaxNumber(SplayTreeNode<T>* tree) { if (tree == NULL) return NULL; while (tree->RightNode != NULL) tree = tree->RightNode; return tree; } template <class T> T SplayTree<T>::MaxNumber() { SplayTreeNode<T> *p = MaxNumber(RootNode); if (p != NULL) return p->Key; return (T)NULL; } /* * 旋转Key对应的节点为根节点,并返回值为根节点。 * * 注意: * (a):伸展树中存在"键值为Key的节点"。 * 将"键值为Key的节点"旋转为根节点。 * (b):伸展树中不存在"键值为Key的节点",并且Key < tree->Key。 * b-1 "键值为Key的节点"的前驱节点存在的话,将"键值为Key的节点"的前驱节点旋转为根节点。 * b-2 "键值为Key的节点"的前驱节点存在的话,则意味着,Key比树中任何键值都小,那么此时,将最小节点旋转为根节点。 * (c):伸展树中不存在"键值为Key的节点",并且Key > tree->Key。 * c-1 "键值为Key的节点"的后继节点存在的话,将"键值为Key的节点"的后继节点旋转为根节点。 * c-2 "键值为Key的节点"的后继节点不存在的话,则意味着,Key比树中任何键值都大,那么此时,将最大节点旋转为根节点。 */ template <class T> SplayTreeNode<T>* SplayTree<T>::Splay(SplayTreeNode<T>* tree, T Key) { SplayTreeNode<T> N, *l, *r, *c; if (tree == NULL) return tree; N.LeftNode = N.RightNode = NULL; l = r = &N; for (;;) { if (Key < tree->Key) { if (tree->LeftNode == NULL) break; if (Key < tree->LeftNode->Key) { c = tree->LeftNode; /* rotate RightNode */ tree->LeftNode = c->RightNode; c->RightNode = tree; tree = c; if (tree->LeftNode == NULL) break; } r->LeftNode = tree; /* link RightNode */ r = tree; tree = tree->LeftNode; } else if (Key > tree->Key) { if (tree->RightNode == NULL) break; if (Key > tree->RightNode->Key) { c = tree->RightNode; /* rotate LeftNode */ tree->RightNode = c->LeftNode; c->LeftNode = tree; tree = c; if (tree->RightNode == NULL) break; } l->RightNode = tree; /* link LeftNode */ l = tree; tree = tree->RightNode; } else { break; } } l->RightNode = tree->LeftNode; /* assemble */ r->LeftNode = tree->RightNode; tree->LeftNode = N.RightNode; tree->RightNode = N.LeftNode; return tree; } template <class T> void SplayTree<T>::Splay(T Key) { RootNode = Splay(RootNode, Key); } /* * 将结点插入到伸展树中,并返回根节点 * * 参数说明: * tree 伸展树的根结点 * Key 插入的结点的键值 * 返回值: * 根节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::InsertNode(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z) { SplayTreeNode<T> *y = NULL; SplayTreeNode<T> *x = tree; // 查找z的插入位置 while (x != NULL) { y = x; if (z->Key < x->Key) x = x->LeftNode; else if (z->Key > x->Key) x = x->RightNode; else { cout << "不允许插入相同节点(" << z->Key << ")!" << endl; delete z; return tree; } } if (y == NULL) tree = z; else if (z->Key < y->Key) y->LeftNode = z; else y->RightNode = z; return tree; } template <class T> void SplayTree<T>::InsertNode(T Key) { SplayTreeNode<T> *z = NULL; // 如果新建结点失败,则返回。 if ((z = new SplayTreeNode<T>(Key, NULL, NULL)) == NULL) return; // 插入节点 RootNode = InsertNode(RootNode, z); // 将节点(Key)旋转为根节点 RootNode = Splay(RootNode, Key); } /* * 删除结点(节点的键值为Key),返回根节点 * * 参数说明: * tree 伸展树的根结点 * Key 待删除结点的键值 * 返回值: * 根节点 */ template <class T> SplayTreeNode<T>* SplayTree<T>::RemoveNode(SplayTreeNode<T>* &tree, T Key) { SplayTreeNode<T> *x; if (tree == NULL) return NULL; // 查找键值为Key的节点,找不到的话直接返回。 if (Search(tree, Key) == NULL) return tree; // 将Key对应的节点旋转为根节点。 tree = splay(tree, Key); if (tree->LeftNode != NULL) { // 将"tree的前驱节点"旋转为根节点 x = splay(tree->LeftNode, Key); // 移除tree节点 x->RightNode = tree->RightNode; } else x = tree->RightNode; delete tree; return x; } template <class T> void SplayTree<T>::RemoveNode(T Key) { RootNode = RemoveNode(RootNode, Key); } /* * 销毁伸展树 */ template <class T> void SplayTree<T>::DestorySplayTree(SplayTreeNode<T>* &tree) { if (tree == NULL) return; if (tree->LeftNode != NULL) DestorySplayTree(tree->LeftNode); if (tree->RightNode != NULL) DestorySplayTree(tree->RightNode); delete tree; } template <class T> void SplayTree<T>::DestorySplayTree() { DestorySplayTree(RootNode); } /* * 打印"伸展树" * * Key -- 节点的键值 * direction -- 0,表示该节点是根节点; * -1,表示该节点是它的父结点的左孩子; * 1,表示该节点是它的父结点的右孩子。 */ template <class T> void SplayTree<T>::PrintSplayTree(SplayTreeNode<T>* tree, T Key, int direction) { if (tree != NULL) { if (direction == 0) // tree是根节点 cout << setw(2) << tree->Key << " is root" << endl; else // tree是分支节点 cout << setw(2) << tree->Key << " is " << setw(2) << Key << "'s " << setw(12) << (direction == 1 ? "RightNode child" : "LeftNode child") << endl; PrintSplayTree(tree->LeftNode, tree->Key, -1); PrintSplayTree(tree->RightNode, tree->Key, 1); } } template <class T> void SplayTree<T>::PrintSplayTree() { if (RootNode != NULL) PrintSplayTree(RootNode, RootNode->Key, 0); } int main() { int i, ilen; static int v1[] = { 10,50,40,30,20,60 }; //注意60插入后 整个树的变化 SplayTree<int>* tree = new SplayTree<int>(); cout << "== 依次添加: "; for (i = 0; i<TBL_SIZE(v1); i++) { cout << v1[i] << " "; tree->InsertNode(v1[i]); } cout << " == 前序遍历: "; tree->PreOrder(); cout << " == 中序遍历: "; tree->InOrder(); cout << " == 后序遍历: "; tree->PostOrder(); cout << endl; cout << "== 最小值: " << tree->MinNumber() << endl; cout << "== 最大值: " << tree->MaxNumber() << endl; cout << "== 树的详细信息: " << endl; tree->PrintSplayTree(); i = 30; cout << " == 旋转节点(" << i << ")为根节点"; tree->Splay(i); cout << " == 树的详细信息: " << endl; tree->PrintSplayTree(); // 销毁二叉树 tree->DestorySplayTree(); return 0; }
    爱程序 不爱bug 爱生活 不爱黑眼圈 我和你们一样 我和你们不一样 我不是凡客 我要做geek
  • 相关阅读:
    sql server SSMS SQL格式化工具
    SQL Server 对象性能计数器
    sql server代理不能执行exe文件
    sql server 书签查找
    non-declaration statement outside function body错误
    golang在数据库中的模糊查询
    windows使用net use命令System error 85 has occurred. The local device name is already in use.There are open files and/or incomplete directory searches pending on the connection to 错误
    前端批量迁移NAS存储
    SVN服务之VisualSVN-Server和TortoiseSVN
    redis-5.0.5 集群部署
  • 原文地址:https://www.cnblogs.com/yifi/p/6420274.html
Copyright © 2011-2022 走看看