跳跃表--加速链表访问

1. 动态的数据结构

        之前一次去实习笔试的时候,有一题笔试题是这样的,设计一个队列,使得它在高强度的插入和删除下仍然具有较好的访问速度。当时想,数组虽然好,访问的时候是O(1)但是一旦涉及到删除和添加元素的时候,性能就下来了。

        由此想到STL中的vector,往里面添加元素是是添加在末尾,一旦超过了其内存大小,在分配一块更大的内存(原来的两倍)然后将旧元素拷贝到新的内存空间去,这样虽然在拷贝的时候时间代价很高,但是平均下来,每个元素的访问代价还是O(1)。比如现在vector里面有4个元素,当我们增加第5个元素的时候,如果忽略分配内存用时,复制4个元素用时4个单位,之前对这4个元素存的时候如果向他们收取2个代价,一个用于存储,两个用于将来的拷贝移动,那么平摊下来,每个元素的存取代价始终未常数,这就是平摊分析。

        既然数组适合存放静态数据,那么就用链表吧,当时我就把一个普通的链表写上去了。结果显然达不到要求,后来在学习的时候发现,其实红黑树挺适合解决这个问题的,但是红黑树的维护比较复杂,比如插入元素后的旋转,写的不多还真比较难调出来。

于是乎总结了一下一些动态的数据结构

  • 1.红黑树
  • 2.B树
  • 3.平衡搜索树
  • 4.跳跃表

这几种在数据改变时候都能保证良好的搜索速度,但是如果考虑实现难度的话,跳跃表是最简单的


2. 跳跃表原理

跳跃表是怎么来的呢?

一般的链表查找一个元素的时候就是挨个查找,那么怎么加速它的查找呢?

另外新建一个链表,其中包含原链表中的一些元素,先到这个链表里面查大概的位置,然后再到原链表里面去查具体的位置。怎么样更快呢?

再多建一条链表,在之前链表的基础之上在随机选择某些元素。

循环就得到了跳跃表的思想了

        当向链表中插入元素的时候,以1/2的概率把它插入到上面一条链表里去,这样当元素即使很多的时候,也能保证上一条链表是下一条长度的一半,每加一条链表,访问速度就提高一倍,这样理论上每个元素的访问速度就达到了logN了。


3. 实际性能

OK,说了这么多它的好,看看他的实际性能,以插入10W随机数为例

template <class T>
void Linklist<T>::SL_Insert(T val)
{
	Node<T> *p,*q,*up,*up_next,*newNode,*oldNode;
	int rad;
	p=head;
	q=p->next;
	while(1)
	{
		while(q!=NULL&&q->var<val)
		{
			p=q;
			q=q->next;
		}
		if(p->down==NULL)
			break;
		stk->PushIn(p);
		p=p->down;
		q=p->next;
	}
	oldNode=new Node<int>(val);
	p->next=oldNode;
	oldNode->next=q;

	while(1)
	{
		rad=rand()%8;
		if(rad>3)
		{
			if(!stk->isEmpty())
			{
				up=stk->Pop();
				up_next=up->next;
				newNode=new Node<int>(val);
				up->next=newNode;
				newNode->next=up_next;
				newNode->down=oldNode;	
			}
			else
			{
				newNode=new Node<int>(0);
				newNode->down=head;
				head=newNode;
				newNode=new Node<int>(val);
				head->next=newNode;
				newNode->down=oldNode;
			}
			oldNode=newNode;
		}
		else
			break;
	}
	stk->clear();
}

1.普通的插入方法耗时199400ms



2.跳跃表耗时328ms,加速是很明显的。



4. 时间复杂度和空间复杂度分析

普通的链表在查找的时候耗时O(N),总体耗时O(N^2),空间复杂度O(N)

跳跃表查找耗时OlogN),总体耗时O(N*logN),空间复杂度由等比数列求和得到O(2*N)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值