1. 程式人生 > 遊戲 >國產懸疑《三伏》試玩版今日15點上線 流程1小時

國產懸疑《三伏》試玩版今日15點上線 流程1小時

跳錶

跳錶 (Skip List) 是增加了額外的前向指標的連結串列。

  • 跳錶隨機地決定連結串列地哪些節點需要增加前向指標、需要增加多少個指標。
  • 目的:提高有序連結串列地查詢效率、支援範圍查詢

跳錶的結構

跳錶的查詢路徑:

  • ListNode 的實現:
template<class K, class E>
struct ListNode
{
	typedef pair<const K, E> pairType;
	pairType value;
	ListNode<K, E>** next; // 指標陣列,存放一系列前向指標

	ListNode(const pairType& thePair, int size) : value(thePair)
	{
		next = new ListNode<K, E>*[size];
	}
};
  • SkipList 的類定義:
template<class K, class E, class Compare=less<K>>
class SkipList
{
public:
	SkipList(int maxSize, float prob);
	SkipList(int maxSize, float prob, const Compare& x) : cmp(x) { SkipList(maxSize, prob); }
	~SkipList();

	ListNode<K, E>* insert(const pair<const K, E>& thePair);
	void erase(const K& theKey);
	int size() const { return dSize; }
	pair<const K, E>* find(const K& theKey);
	E& operator[](const K& theKey);
	void display() const // 按照key的順序輸出
	{
		for (auto cur = head->next[0]; cur != tail; cur = cur->next[0])
			cout << cur->value.first << ' ' << cur->value.second << endl;
	}

private:
	ListNode<K, E>* search(const K theKey) const; // 查詢第一個不滿足條件的節點
	int getLevel() const;
	int maxLevel;	// 最大層數
	int level;	// 當前層數
	float cutOff;	// 在計算插入新節點的層數時,迴圈中如果 rand() > curOff 那麼新增一層
	int dSize;	// 當前元素個數
	ListNode<K, E>* head;	// 頭節點
	ListNode<K, E>* tail;	// 尾節點
	ListNode<K, E>** last;	// 查詢路徑上,每一層路徑節點的前一個點
	Compare cmp;
};
  • 建構函式
template<class K, class E, class Compare>
SkipList<K, E, Compare>::SkipList(int maxSize, float prob)
{
	cutOff = RAND_MAX * prob; // 將概率投射到RAND值域上,否則每次rand()都需要對1取模
	level = dSize = 0;
	maxLevel = (int)ceil(logf((float)maxSize) / logf(1 / prob)) - 1;
	srand((unsigned int)time(nullptr));	// 設定隨機數種子

	pair<K, E> thePair;
	head = new ListNode<K, E>(thePair, maxLevel + 1);
	tail = new ListNode<K, E>(thePair, 0);
	last = new ListNode<K, E>*[maxLevel + 1];

	for (int i = 0; i <= maxLevel; ++i)
		head->next[i] = tail;
}
  • 解構函式
template<class K, class E, class Compare>
SkipList<K, E, Compare>::~SkipList()
{
	auto cur = head;
	while (cur != tail)
	{
		auto pre = cur;
		cur = cur->next[0];
		delete pre;
	}
	delete tail;
}
  • search 私有函式,作為工具方法使用,時間複雜度為 \(O(log_{\frac{1}{prob}}n)\),最壞為 \(O(n)\)
template<class K, class E, class Compare>
ListNode<K, E>* SkipList<K, E, Compare>::search(const K theKey) const
{
	ListNode<K, E>* pre = head;
	for (int i = level; i >= 0; --i)
	{
		while (pre->next[i] != tail && cmp(pre->next[i]->value.first, theKey))
			pre = pre->next[i];
		last[i] = pre;	// 記錄下路徑上每一層的前一個節點
	}
	return pre->next[0]; // 返回第一個不滿足比較條件的值
}
  • getLeve 私有函式,作為工具方法使用,保證設定層數為 \(i\) 的概率為 \(prob^i\)
template<class K, class E, class Compare>
int SkipList<K, E, Compare>::getLevel() const
{
	int res = 0;
	// 通過隨機函式和cutOff來設定概率
	while (rand() <= cutOff && res < maxLevel)
		res++;
	return res;
}
  • insert 公有方法,如果節點已存在則修改,否則插入新節點並返回新節點,時間複雜度和search一樣。
template<class K, class E, class Compare>
ListNode<K, E>* SkipList<K, E, Compare>::insert(const pair<const K, E>& thePair)
{
	auto var = search(thePair.first);
	// 如果元素存在則修改它的值
	if (var->value.first == thePair.first && var != head && var != tail)
	{
		var->value.second = thePair.second;
		return var;
	}

	// 否則建立一個新節點
	int theLevel = getLevel();
	if (theLevel > level)
	{
		theLevel = ++level;
		last[theLevel] = tail;
	}

	auto newNode = new ListNode<K, E>(thePair, theLevel + 1);
	for (int i = 0; i <= theLevel; ++i)
	{
		newNode->next[i] = last[i]->next[i];
		last[i]->next[i] = newNode;
	}
	dSize++;
	return newNode;
}
  • erase函式,刪除給定key的節點,時間複雜度和 search 相同
template<class K, class E, class Compare>
void SkipList<K, E, Compare>::erase(const K& theKey)
{
	auto var = search(theKey);
	if (var->value.first != theKey) return;

	for (int i = 0; i <= level && last[i]->next[i] == var; ++i)
		last[i]->next[i] = var->next[i];

	while (level && head->next[level] == tail)
		--level;
	delete var;
	dSize--;
}
  • find 函式,提供給使用者查詢相關值,時間複雜度和 search 相同
template<class K, class E, class Compare>
pair<const K, E>* SkipList<K, E, Compare>::find(const K& theKey)
{
	auto var = search(theKey);
	if (var->value.first == theKey && var != head && var != tail)
		return &var->value;
	return nullptr;
}
  • 過載 [] ,提供的操作類似於 map
template<class K, class E, class Compare>
E& SkipList<K, E, Compare>::operator[](const K& theKey)
{
	auto var = search(theKey);
	if (var->value.first == theKey && var != head && var != tail)
		return var->value.second;

	pair<K, E> thePair;
	thePair.first = theKey;
	return insert(thePair)->value.second;
}