跳表(skip list)的c++实现

首先声明,是转摘别人的代码,本人稍作更改。在microsoft visual studio comunity 2017环境下测试通过。要理解跳表是如何实现的,看懂这个图很重要(摘自维基百科)

 

跳表数据结构

A schematic picture of the skip list data structure. Each box with an arrow represents a pointer and a row is a linked list giving a sparse subsequence; the numbered boxes (in yellow) at the bottom represent the ordered data sequence. Searching proceeds downwards from the sparsest subsequence at the top until consecutive elements bracketing the search element are found

我翻译一下:跳表数据结构的示意图。每个带箭头的箱子代表一个指针,每一行是是一个链表,每个链表给出一个稀疏子序列;底部的编号的箱子(黄色)表示有序的数据列。搜索过程由顶部的最稀疏的子序列开始,方向朝下,直到包围搜索元素的两个连续元素被发现。

由此可见:元素类型包含一个数据值(黄色箱子)和一个指针向量(用next表示),指针指向某个元素。因为向量的成员也叫元素,为了区别,下面我把链表的元素简称为元素,把指针向量的元素称为指针。所有元素的指针是紧密排列的,这表明指针的个数(next.size())就是该元素出现在子序列中的次数。每个指针都水平向右指向,这表明子序列由相同下标的指针指向的元素组成,并且指针的下标编号和子序列的编号(从0开始编号,0号表示最底层,这一层包含所有元素)是相同的,因此我们可以很方便的通过指针向量的下标操作来访问每一层子序列的元素。每个元素的指针个数由随机数产生,最大max_height,拥有最大指针个数的元素决定了链表的高度。从图形我们也可以很直观的看出每一层子序列是一个单向有序链表,而且越高的子序列越稀疏。

搜索过程结束的条件是:直到p和p->next[0](p->key< x <=p->next[0]->key)这两个元素被发现。p表示搜索经历的元素,x表示搜索元素值,next[0]表示最底层子序列上p指向的下一个元素,如果x==p-next[0]->key,则p->next[0]就是要找的元素,否则数据列不存在x。

看懂了这个图,基本上就能理解如何用c++来实现跳表了。

// exercise18.11.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"


// Chapter 18 exercise 11: implement a skip list. Following Ottmann & Widmayer,
// "Algorithmen and Datenstrukturen" (3rd Edition), 1997, Chapter 1.7.1

#include "d:/download/stroustrup-ppp-master/lib_files/std_lib_facilities.h"

struct element {
	element(int k, int height) : key(k), next(height) { }    //height:元素的层高
	int key;
	vector<element*> next;
};

class skip_list {
public:
	skip_list();
	element* find(int x);
	void insert(int x);
	void remove(int x);
	void print();
	void debug_print();
	void desc_print();
	int get_height() { return height; }
private:
	const int max_height = 4;
	const int infty = numeric_limits<int>::max();
	element head;
	element tail;
	int height;                        //有效层高,从0开始编号,所以实际有效层高数是height+1,可能的最大值是max_height-1
	int random_height();
};

// initialise empty list with head element's next pointing to tail element
// on all list levels
skip_list::skip_list()
	:head(0, max_height), tail(infty, 1), height(0)
{
	for (int i = 0; i<head.next.size(); ++i)
		head.next[i] = &tail;
}

// returns pointer to element with key x if x exists in list, 0 otherwise
element* skip_list::find(int x) {
	element* p = &head;

	for (int i = height; i >= 0; --i) {
		while (p->next[i]->key < x) {
			p = p->next[i];
		}
	}

	// now either p == &head and x <= p->next[0]->key
	// or p != &head and p->key < x <= p->next[0]->key
	p = p->next[0];
	if (p->key == x) return p;  // x is at position p in list
	else return 0;              // x is not in list
}

// inserts element with key x into list
void skip_list::insert(int x) {
	vector<element*> update(max_height);
	element* p = &head;

	for (int i = height; i >= 0; --i) {
		while (p->next[i]->key < x) {
			p = p->next[i];
		}
		update[i] = p;
	}
	p = p->next[0];

	if (p->key == x) return;    // key x exists already in list

	int new_height = random_height();
	if (new_height > height) {  // link new element to head, adjust list height
		for (int i = height + 1; i <= new_height; ++i) {
			update[i] = &head;
		}
		height = new_height;
	}

	// create new element with height new_height and key x
	p = new element(x, new_height+1);

	// insert p into level i lists immediately after element update[i]
	for (int i = 0; i <= new_height; ++i) {
		p->next[i] = update[i]->next[i];
		update[i]->next[i] = p;
	}
}

// removes element with key x from list
void skip_list::remove(int x) {
	vector<element*> update(max_height);
	element* p = &head;
	for (int i = height; i >= 0; --i) {
		while (p->next[i]->key < x)
			p = p->next[i];
		update[i] = p;
	}
	p = p->next[0];

	// if found, remove and potentially reduce list height
	if (p->key == x) {
		for (int i = 0; i<p->next.size(); ++i) {
			// remove p from level i list
			update[i]->next[i] = p->next[i];
		}
		while (height >= 1 && head.next[height]->key == infty)
			--height;
		delete p;
	}
}

void skip_list::print() {
	element* p = head.next[0];
	cout << "{";
	while (p->key != infty) {
		cout << ' ' << setw(2) << p->key;
		p = p->next[0];
	}
	cout << " }" << "\n";
}

// print lists at higher levels
void skip_list::debug_print() {
	for (int i = 0; i <= height; ++i) {
		element* p = head.next[0];
		cout << "Lvl " << i+1 << ": {";
		while (p->key != infty) {
			if (p->next.size() > i)
				cout << ' ' << setw(2) << p->key;
			else
				cout << "   ";
			p = p->next[0];
		}
		cout << " }" << "\n";
	}
}

void skip_list::desc_print() {
	for (int i = height; i >= 0; --i) {
		element* p = head.next[0];            //最底层才包含所有元素
		cout << "Lvl " << i+1 << ": {";
		while (p->key != infty) {
			if (p->next.size() > i)
				cout << ' ' << setw(2) << p->key;
			else
				cout << "   ";
			p = p->next[0];
		}
		cout << " }" << "\n";
	}
}

int skip_list::random_height() {
	int rand_height = 0;
	while (randint(10000)<5000 && rand_height<max_height-1)
		++rand_height;
	return rand_height;
}

int main()
try {
	srand(time(0));
	const int test_val = 75;
	while (true) {
		skip_list sl;
		for (int i = 0; i<23; ++i)
			sl.insert(randint(100));
		sl.desc_print();
		cout << "Enter value to remove: ";
		int x;
		cin >> x;
		if (x == -1) return 0;

		element* p = sl.find(x);
		sl.remove(x);
		sl.desc_print();
		cout << "\n";
	}
}
catch (exception& e) {
	cerr << "exception: " << e.what() << endl;
}
catch (...) {
	cerr << "exception\n";
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
跳表Skiplist)是一种基于链表实现的数据结构,用于快速查找和插入有序序列中的元素。它是一种随机化数据结构,可以在O(log n)的时间内完成查找、插入和删除操作。 以下是一个简单的C++实现示例: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int MAX_LEVEL = 16; // 最大层数 class Node { public: int key; Node **forward; Node(int level, int key) { forward = new Node*[level+1]; memset(forward, 0, sizeof(Node*)*(level+1)); this->key = key; } ~Node() { delete[] forward; } }; class SkipList { public: SkipList() { levelCount = 1; head = new Node(MAX_LEVEL, 0); srand(time(0)); } ~SkipList() { delete head; } int randomLevel() { int level = 1; while (rand() % 2 == 1 && level < MAX_LEVEL) level++; return level; } void insert(int key) { Node *update[MAX_LEVEL+1]; memset(update, 0, sizeof(Node*)*(MAX_LEVEL+1)); Node *p = head; for (int i = levelCount; i >= 1; i--) { while (p->forward[i] != nullptr && p->forward[i]->key < key) p = p->forward[i]; update[i] = p; } p = p->forward[1]; if (p != nullptr && p->key == key) return; int level = randomLevel(); if (level > levelCount) { for (int i = levelCount+1; i <= level; i++) update[i] = head; levelCount = level; } p = new Node(level, key); for (int i = 1; i <= level; i++) { p->forward[i] = update[i]->forward[i]; update[i]->forward[i] = p; } } void remove(int key) { Node *update[MAX_LEVEL+1]; memset(update, 0, sizeof(Node*)*(MAX_LEVEL+1)); Node *p = head; for (int i = levelCount; i >= 1; i--) { while (p->forward[i] != nullptr && p->forward[i]->key < key) p = p->forward[i]; update[i] = p; } p = p->forward[1]; if (p == nullptr || p->key != key) return; for (int i = 1; i <= levelCount; i++) { if (update[i]->forward[i] != p) break; update[i]->forward[i] = p->forward[i]; } delete p; while (levelCount > 1 && head->forward[levelCount] == nullptr) levelCount--; } bool search(int key) { Node *p = head; for (int i = levelCount; i >= 1; i--) { while (p->forward[i] != nullptr && p->forward[i]->key < key) p = p->forward[i]; } p = p->forward[1]; if (p != nullptr && p->key == key) return true; return false; } void display() { for (int i = 1; i <= levelCount; i++) { Node *p = head->forward[i]; cout << "Level " << i << ": "; while (p != nullptr) { cout << p->key << " "; p = p->forward[i]; } cout << endl; } } private: Node *head; int levelCount; }; int main() { SkipList skiplist; skiplist.insert(1); skiplist.insert(3); skiplist.insert(2); skiplist.insert(4); skiplist.display(); skiplist.remove(3); skiplist.display(); cout << skiplist.search(2) << endl; cout << skiplist.search(3) << endl; return 0; } ``` 在这个示例中,我们使用了一个类`Node`作为跳表中的节点,`SkipList`类则封装了跳表的插入、删除、搜索和显示等操作。其中,`randomLevel()`函数用于随机生成节点的层数,`insert()`函数用于插入一个节点,`remove()`函数用于删除一个节点,`search()`函数用于查找一个节点,`display()`函数用于显示整个跳表跳表是一种比较高级的数据结构,它可以在很多场景中代替平衡树,以提高数据结构操作的效率。如果你对跳表感兴趣,可以尝试阅读一些更深入的资料来了解更多。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值