跳表(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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值