力扣题解(设计跳表)

1206.设计跳表

已解答

不使用任何库函数,设计一个 跳表 。

跳表 是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。

例如,一个跳表包含 [30, 40, 50, 60, 70, 90] ,然后增加 8045 到跳表中,以下图的方式操作:

跳表中有很多层,每一层是一个短的链表。在第一层的作用下,增加、删除和搜索操作的时间复杂度不超过 O(n)。跳表的每一个操作的平均时间复杂度是 O(log(n)),空间复杂度是 O(n)

了解更多 : 跳表 - OI Wiki

在本题中,你的设计应该要包含这些函数:

  • bool search(int target) : 返回target是否存在于跳表中。
  • void add(int num): 插入一个元素到跳表。
  • bool erase(int num): 在跳表中删除一个值,如果 num 不存在,直接返回false. 如果存在多个 num ,删除其中任意一个即可。

注意,跳表中可能存在多个相同的值,你的代码需要处理这种情况。

本题主要难点在于理解调表的构造和查找元素的做法。首先,调表的优势在于可以一下子跳过很多元素,所以叫跳表,而能一下跳过很多元素的原因是跳表中存在多层的元素,如果高层可以通过,则高层之间的底层可以忽略,实现了跳过多个元素。

越往上层数越高。

此时从-3所在节点开始走,若比10大,则可以跳过和低层的2,6比较,实现了跳跃。

跳表实现最复杂的地方是找数值是num的节点对应的所有前一个节点(即每层的前一个节点),实现方法是从最高层开始查找,当节点的值大于num或者节点是不存在时,则本层的前一个前一个节点找到,在去低一层找,之所以可以去低一层找,是因为低一层中存放的节点值一定是在高一层的节点的值中间,而与num的大小不能确定,因此需要去进一步查找。

	vector<node*>findprevnode(int num)
	{
		int level = _root->_next.size();
		vector<node*>pre(level);
		level--;
		node* cur = _root;
		while (level >= 0)
		{
			if (cur->_next[level] && cur->_next[level]->_val < num)
			{
				cur = cur->_next[level];
			}
			else if (cur->_next[level] == nullptr || cur->_next[level]->_val >= num)
			{
				pre[level--] = cur;
			}
		}
		return  pre;
	}

对于插入和删除,搜索,都是复用了这个函数,找到对应前一个节点位置,然后进行插入,删除操作即可。对于搜索,只需要从返回的数组的下标为0的节点判断即可,因为该节点所指的下一个节点一定是数组所有节点所指的下一个节点的最小值,如果这个节点存放的值都不对,则必定找不到所需的节点。

class Skiplist {
public:

	struct skiplistnode
	{
		int _val;
		vector<skiplistnode*>_next;

		skiplistnode()
			:_val(-1)
		{

		}

		skiplistnode(int num, int n)
		{
			_val = num;
			_next.resize(n, nullptr);
		}
	};

	typedef skiplistnode node;
	node* _root;

	Skiplist() {
		srand((unsigned)time(nullptr));
		_root = new node();
	}




	vector<node*>findprevnode(int num)
	{
		int level = _root->_next.size();
		vector<node*>pre(level);
		level--;
		node* cur = _root;
		while (level >= 0)
		{
			if (cur->_next[level] && cur->_next[level]->_val < num)
			{
				cur = cur->_next[level];
			}
			else if (cur->_next[level] == nullptr || cur->_next[level]->_val >= num)
			{
				pre[level--] = cur;
			}
		}
		return  pre;
	}

    
	bool search(int target) {
       vector<node*>prevnode = findprevnode(target);
		if (prevnode[0]->_next[0] == nullptr || prevnode[0]->_next[0]->_val != target)
		{
			return false;
		}
        else
          {
            return true;
          }
	}



	int creatrand()
	{

		int level = 1;
		double p = 0.5;
		
		int it = rand();
		int itt = RAND_MAX * p;
	//	cout << it << " " << itt << endl;
		while (level <= 32 && rand() < RAND_MAX * p)
		{   
			level++;
		}
		return level;


	}
	void add(int num) {
		vector<node*>prevnode = findprevnode(num);
		int n = creatrand();
		if (n > _root->_next.size())
		{
			_root->_next.resize(n);
			prevnode.resize(n,_root);
		}
		node* cur = new node(num, n);

		for (int i = 0; i < n; i++)
		{
			cur->_next[i] = prevnode[i]->_next[i];
			prevnode[i]->_next[i] = cur;
		}

	}

	bool erase(int num) {
		vector<node*>prevnode = findprevnode(num);
		if (prevnode[0]->_next[0] == nullptr || prevnode[0]->_next[0]->_val != num)
		{
			return false;
		}
		else
		{
			node* cur = prevnode[0]->_next[0];
			for (int i = 0; i < cur->_next.size(); i++)
			{
				prevnode[i]->_next[i] = cur->_next[i];
			}
			delete cur;
			return true;
		}
	}
};

相关推荐

  1. 707.设计LeetCode)

    2024-07-11 09:22:02       58 阅读
  2. 设计707

    2024-07-11 09:22:02       33 阅读
  3. [题解]

    2024-07-11 09:22:02       37 阅读
  4. 206】反转链 C++题解(链+头插法)

    2024-07-11 09:22:02       55 阅读
  5. 1-100题解

    2024-07-11 09:22:02       42 阅读
  6. 题解(摆动序列)

    2024-07-11 09:22:02       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 09:22:02       101 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 09:22:02       108 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 09:22:02       91 阅读
  4. Python语言-面向对象

    2024-07-11 09:22:02       98 阅读

热门阅读

  1. pc安装python opencv

    2024-07-11 09:22:02       22 阅读
  2. Linux关于数据库,群集,缓存加速等精捡面试题

    2024-07-11 09:22:02       21 阅读
  3. 【AI应用探讨】—多智能体系统(MAS)应用场景

    2024-07-11 09:22:02       29 阅读
  4. 探索GraphQL的迷宫:Postman中测试指南

    2024-07-11 09:22:02       29 阅读
  5. 包管理器-npm、yarn、cnpm、pnpm的比较

    2024-07-11 09:22:02       27 阅读
  6. Android Studio gradle下载失败?!

    2024-07-11 09:22:02       30 阅读
  7. UWB系列教程(一)UWB简介

    2024-07-11 09:22:02       26 阅读