伸展树的读书笔记

来源:互联网 发布:node fetch 编辑:程序博客网 时间:2024/05/17 08:04

原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

由于各种原因,可能存在诸多不足,欢迎斧正!        

    最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处!

       二叉排序树是一种动态排序的数据结构,支持插入、删除、查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N)。此时,平衡二叉树的产生了。平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树很难,于是人们使用AVL、红黑树、Treap、伸展树等来替代平衡二叉树,这些数据结构可以很好地改善最坏情况。但实现起来并不是很容易的事。

        伸展树较其他的数据结构,有着明显的特点。与纯的二叉查找树比起来,伸展树的查找、插入、删除等操作的平摊时间复杂度O(log(N)),且与AVL、红黑树比起来实现简单、空间效率高。关于伸展树的具体原理,可以参考算法合集之《伸展树的基本操作与应用》,这是国家队大牛写的,可读性很强。

       伸展树的基本原理是80—20原则,学计算机的人对这个原则的内容肯定不陌生:计算机80%的数据访问在集中在20%的数据上,如存储器中的Cache就是用的这个原理,并且效果很不错。伸展树正是利用这样的设计思想来进行的,将当前操作的数据通过伸展操作移到根节点,在这个过程中保持二叉查找树的性质,从而是整个过程的平摊时间复杂度降到O(log(N))。当然,对于单个操作,时间复杂度可能到达O(N),但基于整体考虑以及计算机特定规律,伸展树还是有着很好的效率的。在伸展的过程中,主要涉及两个旋转操作,左旋或右旋。在设计算法时,我们通常将时间复杂度放在首位,这点无可厚非,但有时我们的结合具体题目要求,在时间复杂度、空间复杂度、编程实现难度间寻找平衡,于是伸展树被认为是拥有很重要现实价值的”平衡二叉树“。

                         

                                                      

      上面从左到右为右旋,从右到左为左旋,其他所有操作都是由这两种基本操作组合起来的。如下

       以上3副图包含了伸展树所有的Splay操作,而基本的左旋右选得到。

      普通伸展树支持插入、删除、修改、查询等操作。关于伸展树,有自顶向下和自底向上两种实现方法,这里我选用的是自底向上的实现方法,由于在节点中有父节点,故不用记录路径。

下面贴上我的代码:

//伸展树节点头文件SplayTreeNode.h#include<iostream>using namespace std;/***********************************功能:防止头文件多次包含**********************************/#ifndef SPLAYTREENODE_H#define SPLAYTREENODE_Hclass SplayTreeNode{public:SplayTreeNode *leftChild;SplayTreeNode *rightChild;SplayTreeNode *parent;int key;SplayTreeNode(int key){this->key=key;this->leftChild=NULL;this->rightChild=NULL;this->parent=NULL;}};#endif SPLAYTREENODE_H


 

//伸展树源文件SplayTree.cpp#include<iostream>#include"SplayTreeNode.h"using namespace std;class SplayTree{private:SplayTreeNode *root;void LeftRotate(SplayTreeNode *);void RightRotate(SplayTreeNode *);void Splay(SplayTreeNode *);void PreOrderSTPrint(SplayTreeNode *);void InOrderSTPrint(SplayTreeNode *);void RotateSTPrint(SplayTreeNode *,int);void SufOrderSTPrint(SplayTreeNode *);void DeleteNoOrOneChildSTNode(SplayTreeNode *,SplayTreeNode *);public:SplayTree();void InsertSplayTree(int);bool DeleteSplayTree(int);bool UpdataSplayTree(int,int);SplayTreeNode *FindSplayTree(int);void PreOrderSTPrint();void InOrderSTPrint();void RotateSTPrint();void SufOrderSTPrint();};SplayTree::SplayTree(){this->root=NULL;} /***************************************************************参数:待左旋的节点*返回值:空*功能:左旋***************************************************************/void SplayTree::LeftRotate(SplayTreeNode *tempSTNode){SplayTreeNode *rChild=tempSTNode->rightChild;if(NULL!=tempSTNode->parent)//不为根节点{if(tempSTNode->parent->leftChild==tempSTNode)tempSTNode->parent->leftChild=rChild;else tempSTNode->parent->rightChild=rChild;}rChild->parent=tempSTNode->parent;tempSTNode->parent=rChild;if(rChild->leftChild!=NULL)rChild->leftChild->parent=tempSTNode;tempSTNode->rightChild=rChild->leftChild;rChild->leftChild=tempSTNode;if(NULL==rChild->parent)this->root=rChild;}/***************************************************************参数:待右旋的节点*返回值:空*功能:右旋***************************************************************/void SplayTree::RightRotate(SplayTreeNode *tempSTNode){SplayTreeNode *lChild=tempSTNode->leftChild;if(NULL!=tempSTNode->parent)//不为根节点{if(tempSTNode->parent->rightChild==tempSTNode)tempSTNode->parent->rightChild=lChild;else tempSTNode->parent->leftChild=lChild;}lChild->parent=tempSTNode->parent;tempSTNode->parent=lChild;if(lChild->rightChild!=NULL)lChild->rightChild->parent=tempSTNode;tempSTNode->leftChild=lChild->rightChild;lChild->rightChild=tempSTNode;if(NULL==lChild->parent)this->root=lChild;}/***************************************************************参数:待伸展的节点*返回值:空*功能:将当前节点伸展的根节点***************************************************************/void SplayTree::Splay(SplayTreeNode *tempSTNode){while(NULL!=tempSTNode&&NULL!=tempSTNode->parent){if(tempSTNode->parent->leftChild==tempSTNode)//父亲节点右旋RightRotate(tempSTNode->parent);else LeftRotate(tempSTNode->parent);}}/***************************************************************参数:带插入元素*返回值:空*功能:将当前元素插入伸展树***************************************************************/void SplayTree::InsertSplayTree(int tempKey){SplayTreeNode *pre=NULL,*cur=this->root;while(cur!=NULL){pre=cur;if(cur->key>tempKey)//tempKey插到左子树cur=cur->leftChild;else cur=cur->rightChild;//插到左子树}SplayTreeNode *tempSTNode=new SplayTreeNode(tempKey);tempSTNode->parent=pre;if(pre==NULL)//若插入的为根节点{this->root=tempSTNode;}else if(pre->key>tempSTNode->key)pre->leftChild=tempSTNode;else pre->rightChild=tempSTNode;Splay(tempSTNode);}/***************************************************************参数:带查找元素*返回值:返回查找元素在伸展树中的位置*功能:查找当前元素是否在伸展树***************************************************************/SplayTreeNode *SplayTree::FindSplayTree(int tempKey){SplayTreeNode *cur=this->root;while(cur!=NULL){if(cur->key==tempKey)break;else if(cur->key>tempKey)cur=cur->leftChild;else cur=cur->rightChild;}Splay(cur);return cur;}/***********************************************************参数:pre待删除节点的父节点,cur待删除节点*返回值:空*功能:删除左右孩子有为空的情况************************************************************/void SplayTree::DeleteNoOrOneChildSTNode(SplayTreeNode *pre,SplayTreeNode *cur){if(NULL==cur->leftChild&&NULL==cur->rightChild)//左右孩子为空{if(NULL==pre)this->root=NULL;else if(pre->leftChild==cur)pre->leftChild=NULL;else pre->rightChild=NULL;delete cur;}else if(cur->rightChild!=NULL)//若右子树不为空{if(NULL==pre){this->root=cur->rightChild;cur->rightChild->parent=NULL;}else if(pre->leftChild==cur){pre->leftChild=cur->rightChild;cur->rightChild->parent=pre;}else {pre->rightChild=cur->rightChild;cur->rightChild->parent=pre;}delete cur;}else if(cur->leftChild!=NULL)//若左子树不为空{if(NULL==pre){this->root=cur->leftChild;cur->leftChild->parent=NULL;}else if(pre->leftChild==cur){pre->leftChild=cur->leftChild;cur->leftChild->parent=pre;}else{pre->rightChild=cur->leftChild;cur->leftChild->parent=pre;}delete cur;}}/***********************************************************参数:待删除节点元素*返回值:空*功能:删除元素主函数************************************************************/bool SplayTree::DeleteSplayTree(int tempKey){SplayTreeNode *pre=NULL,*cur=root;while(cur!=NULL)//寻找待删除元素{if(cur->key==tempKey)break;else{pre=cur;if(cur->key>tempKey)cur=cur->leftChild;else cur=cur->rightChild;}}if(NULL==cur)return false;if(NULL==cur->leftChild||NULL==cur->rightChild){DeleteNoOrOneChildSTNode(pre,cur);Splay(pre);}else //左右子树都不为空{SplayTreeNode *rPre=cur,*rCur=cur->rightChild;//找到右子树最小元素while(rCur->leftChild!=NULL){rPre=rCur;rCur=rCur->leftChild;}cur->key=rCur->key;DeleteNoOrOneChildSTNode(rPre,rCur);Splay(rPre);}return true;}/***********************************************************参数:待修改节点元素、修改后的元素*返回值:返回修改是否成功*功能:修改函数************************************************************/bool SplayTree::UpdataSplayTree(int oldKey,int newKey){if(DeleteSplayTree(oldKey)){InsertSplayTree(newKey);return true;}return false;}/***********************************************************参数:当前子树根节点*返回值:空*功能:前序遍历二叉查找树************************************************************/void SplayTree::PreOrderSTPrint(SplayTreeNode *tempSTNode){if(NULL==tempSTNode)return ;cout<<tempSTNode->key<<"    ";PreOrderSTPrint(tempSTNode->leftChild);PreOrderSTPrint(tempSTNode->rightChild);}void SplayTree::PreOrderSTPrint(){PreOrderSTPrint(this->root);}/***********************************************************参数:当前子树根节点*返回值:空*功能:中序遍历二叉查找树************************************************************/void SplayTree::InOrderSTPrint(SplayTreeNode *tempSTNode){if(NULL==tempSTNode)return ;InOrderSTPrint(tempSTNode->leftChild);cout<<tempSTNode->key<<"   ";InOrderSTPrint(tempSTNode->rightChild);}void SplayTree::InOrderSTPrint(){InOrderSTPrint(this->root);}/***********************************************************参数:当前子树根节点*返回值:空*功能:后序遍历二叉查找树树************************************************************/void SplayTree::SufOrderSTPrint(SplayTreeNode *tempSTNode){if(NULL==tempSTNode)return ;SufOrderSTPrint(tempSTNode->leftChild);SufOrderSTPrint(tempSTNode->rightChild);cout<<tempSTNode->key<<"    ";}void SplayTree::SufOrderSTPrint(){SufOrderSTPrint(this->root);}/***********************************************************参数:当前子树根节点,缩进列数*返回值:空*功能:翻转打印伸展树************************************************************/void SplayTree::RotateSTPrint(SplayTreeNode *tempSTNode,int tempColumn){if(NULL==tempSTNode)return ;RotateSTPrint(tempSTNode->leftChild,tempColumn+1);for(int i=0;i<tempColumn;i++)cout<<"    ";cout<<"---"<<tempSTNode->key<<endl;RotateSTPrint(tempSTNode->rightChild,tempColumn+1);}void SplayTree::RotateSTPrint(){RotateSTPrint(this->root,0);}void Menu(){int val,choice,newVal;SplayTree mySplayTree;while(true){do{cout<<"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"<<endl;cout<<"       1.插入"<<endl;cout<<"       2.删除"<<endl;cout<<"       3.修改"<<endl;cout<<"       4.查找"<<endl;cout<<"       5.显示"<<endl;cout<<"       6.返回"<<endl;cout<<"请输入你的选项[ ]\b\b";cin>>choice; }while(choice!=1&&choice!=2&&choice!=3&&choice!=4&&choice!=5&&choice!=6);if(1==choice){cin>>val;mySplayTree.InsertSplayTree(val);}else if(2==choice){cin>>val;if(mySplayTree.DeleteSplayTree(val))cout<<"删除成功!"<<endl;else cout<<"删除失败!"<<endl;}else if(3==choice){cin>>val>>newVal;if(mySplayTree.UpdataSplayTree(val,newVal))cout<<"修改成功!"<<endl;else cout<<"修改失败!"<<endl;}else if(4==choice){cin>>val;if(NULL!=mySplayTree.FindSplayTree(val))cout<<"查找成功!"<<endl;else cout<<"查找失败!"<<endl;}else if(5==choice){cout<<endl<<"*****************************"<<endl;cout<<endl<<"==========前序=============="<<endl;mySplayTree.PreOrderSTPrint();cout<<endl<<"==========中序================"<<endl;mySplayTree.InOrderSTPrint();cout<<endl<<"==========后续==============="<<endl;mySplayTree.SufOrderSTPrint();cout<<endl<<"==========对称+旋转==============="<<endl;mySplayTree.RotateSTPrint();cout<<endl<<"*****************************"<<endl;}else return ;}}int main(){while(true)Menu();system("pause");return 0;}

 

关于伸展树的其他操作,后续在其他博客中补上。由于时间有限,缺乏测试,可能有错,欢迎大家斧正!

 

 

 

0 0
原创粉丝点击