您的位置:首页 > 理论基础 > 数据结构算法

[C++]数据结构:跳表SkipList的实现与使用

2012-12-03 20:00 465 查看
#include<iostream>
#include <math.h>
using namespace std;

//E是查询值,K是返回值
template<class E,class K>
class SkipNode{
public:
SkipNode(int size){link=new SkipNode<E,K>*[size];}
~SkipNode(){delete []link;}
E data ;
SkipNode<E,K>**link;//一维指针数组
};

template<class E,class K>
class SkipList{
public:
SkipList(K large,int MaxE = 10000,float p=0.5);
//MaxE是字典的最大容量
//一个节点既在i-1级链上又在i级链上的概率为p
//Large是一个比字典中任意一个数均大的值,尾节点的值为Large
//0级链上的值(不包括头结点,因其没有值)从左到右顺序排列
~SkipList();
bool Search(const K&k,E&e)const;
SkipList<E,K>&Insert(const E&e);
SkipList<E,K>&Delete(const K&k,E&e);
void Output(ostream& out)const;

int Level();
SkipNode<E,K>*SaveSearch(const K&k);
int MaxLevel;//所允许的最大级数
int Levels;//当前非空链的个数
int CutOff;//用于确定级号
K TailKey;//一个很大的key值
SkipNode<E,K>*head;//头结点指针
SkipNode<E,K>*tail;//尾节点指针
SkipNode<E,K>**last;//指针数组
};

//重载操作符
template<class E,class K>
ostream& operator<<(ostream& out,const SkipList<E,K>&x){
x.Output(out);
return out;
}

//输出该跳表的内容
template<class E,class K>
void SkipList<E,K>::Output(ostream& out)const
{
SkipNode<E,K> *y=head->link[0];
for(;y->data!=TailKey;y=y->link[0])
cout<<y->data<<" ";
cout<<endl;
}

template<class E,class K>
SkipList<E,K>::SkipList(K Large,int MaxE,float p){
CutOff=p*RAND_MAX;
MaxLevel=ceil(log(MaxE)/log(1/p))-1;
TailKey = Large;
//randomize();//初始化随机发生器
Levels = 0;//对级号进行初始化

//创建头结点、尾节点以及数组last
head= new SkipNode<E,K>(MaxLevel+1);
tail= new SkipNode<E,K>(0);
last= new SkipNode<E,K>*[MaxLevel+1];
tail->data=Large;

//将所有级都置空且将head指向tail
for (int i=0;i<=MaxLevel;i++){
head->link[i]=tail;
}
}

//删除所有节点以及数组last
template<class E,class K>
SkipList<E,K>::~SkipList(){
SkipNode<E,K>*next;

//通过删除0级链来删除所有的节点
while(head!=tail){
next=head->link[0];
delete head;
head=next;
}
delete tail;
delete []last;
}

//跳表的操作符重载
class element{
public:
operator long()const{return key;}
element& operator=(long y){
key = y;
return *this;
}
int data;
long key;
};

//搜索与k相匹配的元素,并将找到的元素放入e中
//如果不存在这样的元素则返回false
template<class E,class K>
bool SkipList<E,K>::Search(const K&k,E&e)const{
if(k>=TailKey)
return false;

//调整指针p使其恰好指向可能与k匹配的节点的前一个节点
SkipNode<E,K>*p=head;
for (int i=Levels;i>=0;i--){
while(p->link[i]->data<k){
p=p->link[i];
}
}

//检查是否下一个节点拥有关键值k
e=p->link[0]->data;
return (e==k);
}

//搜索k并且保存最终得到的位置
//在每一级链中搜索
template<class E,class K>
SkipNode<E,K>*SkipList<E,K>::SaveSearch(const K&k){
SkipNode<E,K>*p=head;
//调整指针p使其恰好指向可能与k匹配的节点的前一个节点
for (int i=Levels;i>=0;i--){
while(p->link[i]->data<k)
p=p->link[i];
last[i]=p;
}
return (p->link[0]);
}

//产生一个随机级号<=MaxLevel
template<class E,class K>
int SkipList<E,K>::Level(){
int lev = 0;
while(rand()<=CutOff)
lev++;
return (lev<=MaxLevel)?lev:MaxLevel;
}

class BadInput{
public:
BadInput(){
cout<<"Bad Input!"<<endl;
}
};

//若不存在重复则插入e
template<class E,class K>
SkipList<E,K>& SkipList<E,K>::Insert(const E&e){
K k = e;
if(k>=TailKey)
throw BadInput();//关键值太大了

//检验是否重复
SkipNode<E,K>*p=SaveSearch(k);
if(p->data==e)
throw BadInput();//关键值重复

//不重复则为新节点创建级号
int lev = Level();
//fix level to be <=Levels+1
if (lev>Levels)
{
lev=++Levels;
last[lev]=head;
}

//产生新节点并且将其插入在p之后
SkipNode<E,K>*y = new SkipNode<E,K>(lev+1);
y->data=e;
for (int i=0;i<=lev;i++){
//插入到第i级链
y->link[i]=last[i]->link[i];
last[i]->link[i]=y;
}
return *this;
}

//从跳表中删除与k相匹配的元素并将其放到e
//如果不存在则引发异常BadInput
template<class E,class K>
SkipList<E,K>& SkipList<E,K>::Delete(const K&k,E&e){
if(k>=TailKey)
throw BadInput();//关键值太大

//检查是否存在与k相匹配的元素
SkipNode<E,K>*p=SaveSearch(k);
if(p->data!=k)
throw BadInput();//不存在

//从跳表中删除节点
for (int i=0;i<=Levels&&last[i]->link[i]==p;i++)
last[i]->link=p->link[i];

//修改级数
while(Levels>0&&head->link[Levels]==tail)
Levels--;

e=p->data;
delete p;
return *this;
}

void main(){
SkipList<long,float>mySkip(1000);
mySkip.Insert(100);
mySkip.Insert(123);
mySkip.Insert(12.13);
mySkip.Insert(10.30);
mySkip.Insert(124);
cout<<"CutOff:"<<mySkip.CutOff<<endl;
cout<<"MaxLevel:"<<mySkip.MaxLevel<<endl;
cout<<"Level:"<<mySkip.Level()<<endl;
cout<<"tail:"<<mySkip.tail<<endl;
cout<<"TailKey:"<<mySkip.TailKey<<endl;
cout<<mySkip<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: