【高阶数据结构】跳表

SkipList是由William Pugh发明的:

William Pugh一开始的思路:

  • 每隔一个节点就提高一层;

查找的效率为O(log(N))

但是他有一个非常大的问题:就是如果删除一个元素那么原先的结构就被打乱,需要从新调整;时间复杂度:O(N); 

SkipList设计

William Pugh进一步优化:将每一个节点的层数进行随机,不采用隔一个节点就上升一层

节点代码:节点的数值、一个指针数组(指向下一个节点)

template<class T>
struct SkipNode
{
	SkipNode(T val, size_t n):_val(val)
	{
		_v.resize(n, nullptr);
	}
	//成员变量
	T _val;
	vector<SkipNode<T>*> _v;
};

查找一个值:

  • 下一个元素为空或者比要找的元素大向下,保存当前指针,下一个元素为空或者比要找的元素小向右
  • 返回值为pair<vector<Node*>, bool>,vector<Node*>是后续插入元素的前一个,bool决定是否存在
	//应该返回查找链
	pair<vector<Node*>, bool> FindPervNode(T val)
	{
		vector<Node*> findList(_head->_v.size(), nullptr);//查找链

		int level = _head->_v.size() - 1;
		Node* cur = _head;
		//下标为-1,说明没有元素;
		while (level >= 0)
		{
			//下一个元素为空或者比要找的元素大 , 向下
			if (cur->_v[level] == nullptr || cur->_val > val)
			{
				//前一个添加查找链
				findList[level] = cur;
				level--;
			}
			//下一个元素比要找的元素小,向右
			else if(cur->_val < val)
			{
				cur = cur->_v[level];
			}
			//等于,return false
			else
				return make_pair(findList, true);
		}
		return make_pair(findList, false);
	}

如何插入:

  • 使用查找判断是否已存在,并且找插入位置的前一个的查找链
  • 插入元素的next等于前一个的next;前一个的next等于插入元素;

	//应该返回查找链
	pair<vector<Node*>, bool> FindPervNode(T val)
	{
		vector<Node*> findList(_head->_v.size(), nullptr);//查找链

		int level = _head->_v.size() - 1;
		Node* cur = _head;
		//下标为-1,说明没有元素;
		while (level >= 0)
		{
			//下一个元素为空或者比要找的元素大 , 向下
			if (cur->_v[level] == nullptr || cur->_val > val)
			{
				//前一个添加查找链
				findList[level] = cur;
				level--;
			}
			//下一个元素比要找的元素小,向右
			else if(cur->_val < val)
			{
				cur = cur->_v[level];
			}
			//等于,return false
			else
				return make_pair(findList, true);
		}
		return make_pair(findList, false);
	}

删除:

  • 每个元素至少有一层,遍历最底层;保存前一个
  • 使用前一个的next等于删除元素的next;
  • delete删除元素; 
bool Erase(T val)
	{
		//查找是否存在
		pair<vector<Node*>, bool> fpn = FindPervNode(val);

		if (fpn.second == false)
			return false;

		vector<Node*> findList = fpn.first;
		Node* prev = findList[0], * cur = prev->_v[0];
		//前一个节指向  删除节点的后一个节点
		for (int i = 0; i < cur->_v.size(); i++)
		{
			prev->_v[i] = cur->_v[i];
		}
		delete cur;

		// 如果删除最高层节点,把头节点的层数也降一下
		int i = _head->_v.size() - 1;
		while (i >= 0)
		{
			if (_head->_v[i] == nullptr)
				--i;
			else
				break;
		}
		_head->_v.resize(i + 1);
		return true;
	}

完整代码:

#pragma once
#include<iostream>
#include<vector>

using namespace std;

template<class T>
struct SkipNode
{
	SkipNode(T val, size_t n):_val(val)
	{
		_v.resize(n, nullptr);
	}
	//成员变量
	T _val;
	vector<SkipNode<T>*> _v;
};

template<class T>
class SkipList {
	typedef SkipNode<T> Node;
public:
	//应该返回查找链
	pair<vector<Node*>, bool> FindPervNode(T val)
	{
		vector<Node*> findList(_head->_v.size(), nullptr);//查找链

		int level = _head->_v.size() - 1;
		Node* cur = _head;
		//下标为-1,说明没有元素;
		while (level >= 0)
		{
			//下一个元素为空或者比要找的元素大 , 向下
			if (cur->_v[level] == nullptr || cur->_val > val)
			{
				//前一个添加查找链
				findList[level] = cur;
				level--;
			}
			//下一个元素比要找的元素小,向右
			else if(cur->_val < val)
			{
				cur = cur->_v[level];
			}
			//等于,return false
			else
				return make_pair(findList, true);
		}
		return make_pair(findList, false);
	}
	int Random()
	{
		int level = 1;
		while (rand() <= _proba * RAND_MAX && level < _maxLevel)
			level++;
		return level;
	}
	bool Insert(T val)
	{
		//查找是否存在
		pair<vector<Node*>, bool> fpn = FindPervNode(val);
		 
		if (fpn.second == true)
			return false;

		vector<Node*> findList= fpn.first;
		//获取随机层数和新节点
		int probaLevel = Random();
		Node* newNode = new Node(val,probaLevel);
		//头的个数小于新节点的个数,扩容
		if (_head->_v.size() < probaLevel)
		{
			_head->_v.resize(probaLevel, nullptr);
			findList.resize(probaLevel, _head);
		}
		
		//新节点指向findlist的下一个,findlist指向新节点
		for (int i = 0; i < probaLevel; i++)
		{
			newNode->_v[i] = findList[i]->_v[i];
			findList[i]->_v[i] = newNode;
		}
	}
	bool Erase(T val)
	{
		//查找是否存在
		pair<vector<Node*>, bool> fpn = FindPervNode(val);

		if (fpn.second == false)
			return false;

		vector<Node*> findList = fpn.first;
		Node* prev = findList[0], * cur = prev->_v[0];
		//前一个节指向  删除节点的后一个节点
		for (int i = 0; i < cur->_v.size(); i++)
		{
			prev->_v[i] = cur->_v[i];
		}
		delete cur;

		// 如果删除最高层节点,把头节点的层数也降一下
		int i = _head->_v.size() - 1;
		while (i >= 0)
		{
			if (_head->_v[i] == nullptr)
				--i;
			else
				break;
		}
		_head->_v.resize(i + 1);
		return true;
	}
	void Print()
	{

		Node* cur = _head;
		while (cur)
		{
			printf("%2d\n", cur->_val);
			// 打印每个每个cur节点
			for (auto e : cur->_v)
			{
				printf("%2s", "↓");
			}
			printf("\n");

			cur = cur->_v[0];
		}
	}
public:
	SkipList()
	{
		srand( (unsigned int) time(nullptr) );
		_head = new Node(T(), 1);
		_proba = 0.5;
		_maxLevel = 32;
	}
	~SkipList()
	{
		if (_head)
		{
			//删除所有节点
		}
	}

private:
	//头节点
	Node* _head;
	//每多一层的概率
	float _proba;
	//最大层数
	size_t _maxLevel;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值