前言
今天依旧是记录算法分析作业的一天:)
用C++,实现跳跃表的查找增加和删除
是在《数据结构与算法分析(C++版)》(第三版)这本书后附加的代码的基础上改的。
跳跃表具体内容我也不多说了,可以参考Redis之跳跃表实现 和『数据结构』跳跃表 这两篇文章的图文描述。
我就谈谈具体实现代码:
头文件代码
SkipList.h
#include <random>
using namespace std;
#define MAXLEVEL 9
int randomLevel(void) { //随机分配级数
int level = 0;
while (rand()%2 == 0) level++;
return level;
}
//结点
template <typename Key, typename E>
class SkipNode {
public:
int myLevel;
Key k; // 成员对象
E it; //值
SkipNode** forward; // 前进指针,指向表尾方向
//两个构造函数
SkipNode() {
myLevel = MAXLEVEL;
forward = new SkipNode * [MAXLEVEL + 1];
for (int i = 0; i <= MAXLEVEL; i++)
forward[i] = NULL;
}
SkipNode(Key key, E r, int level) {
myLevel = level;
k = key;
it = r;
forward = new SkipNode * [level + 1];
for (int i = 0; i <= level; i++)
forward[i] = NULL;
}
~SkipNode() { delete[] forward; }
};
//跳跃表
template <typename Key, typename E>
class SkipList {
private:
SkipNode<Key,E>* head;
//unordered_map<Key, E>* head; //相当于实现一个哈希表,方便查找
int level; // 表中层数最大的节点的层数
int reccount; // 表中节点的数量
void AdjustHead(int& level) {
level = MAXLEVEL;
}
public:
SkipList() { //构造函数
head = new SkipNode<Key, E>;
level = MAXLEVEL;
reccount = 0;
}
E find(const Key& k) const { //按照序号找某个结点
SkipNode<Key, E>* x = head; // 定义一个指针
for (int i = level; i >= 0; i--)
while ((x->forward[i] != NULL) &&
(k > x->forward[i]->k))
x = x->forward[i];
x = x->forward[0]; // 如果存在,移至根节点
if ((x != NULL) && (k == x->k)) return x->it; //找到了,返回该序号结点对应的值
return NULL;
}
void insert(const Key& k, const E& it) {
int i;
SkipNode<Key, E>* x = head; // Start at header node
int newLevel = randomLevel(); // 给新节点定义层数
if (newLevel > level) { // New node is deepest in list
AdjustHead(newLevel); // Add null pointers to header
level = newLevel;
}
SkipNode<Key, E>* update[MAXLEVEL + 1]; // Track level ends
for (i = level; i >= 0; i--) { // 在所有级数上进行适当的链接
while ((x->forward[i] != NULL) && (x->forward[i]->k < k))
x = x->forward[i];
update[i] = x; // x为要插入的前一个值的位置
}
x = new SkipNode<Key, E>(k, it, newLevel); // New node
for (i = 0; i <= newLevel; i++) { // 插入
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
reccount++;
}
bool remove(const Key& k)
{
//cout << "Remove not implemented\n"; return false;
int i;
SkipNode<Key, E>* x = head;
SkipNode<Key, E>* update[MAXLEVEL + 1];
int flag = 0; //为0,表示不是最后一位
for (i = level; i >= 0; i--) { // 查找所有级数
while ((x->forward[i] != NULL) && (x->forward[i]->k < k))
x = x->forward[i];
update[i] = x; // x为要插入的前一个值的位置
if (x->forward[i] == NULL) {//如果x是最后一位
flag = 1;
if (x->k != k) //没有这个数
return false;
}
}
for (i = 0; i <= level; i++) {
if (flag == 1) {
update[i]->forward[i] = NULL;
}
else {
update[i]->forward[i] = update[i]->forward[i]->forward[i];
}
}
reccount--;
return true;
}
int size() { return reccount; }
void print() const {
cout << "Print a skiplist with " << reccount << " nodes\n";
for (SkipNode<Key, E>* temp = head; temp != NULL;
temp = temp->forward[0]) {
if (temp->it != NULL)
cout << "temp->k is " << temp->k << "\n";
else cout << "temp->k is NULL\n";
for (int i = 0; i <= temp->myLevel; i++)
if (temp->forward[i] == NULL)
cout << " point to NULL\n";
else
cout << " point to " << temp->forward[i]->it << "\n";
}
cout << endl;
}
};
源文件代码
//用例测试
skipMain.cpp
#include<iostream>
#include<stdlib.h>
#include "skiplist.h"
using namespace std;
int main()
{
SkipList<int, int*> sl;
int* it;
cout << "Size: " << sl.size() << "\n";
sl.insert(100, new int(100));
cout << "Size: " << sl.size() << "\n";
sl.print();
if ((sl.remove(15)) != false)
cout << "Removed 15 successed " << endl;
else cout << "No key 15\n";
sl.insert(15, new int(15));
cout << "Size: " << sl.size() << "\n";
sl.print();
if ((it = sl.find(20)) != NULL)
cout << "Found " << it << endl;
else cout << "No key 20\n";
if ((it = sl.find(15)) != NULL)
cout << "Found 15: " << it << endl<<endl;
else cout << "No key 15\n";
sl.print();
if ((sl.remove(20)) != false)
cout << "Removed 20 successed " << endl;
else cout << "No key 20\n";
cout << "Now, insert 20\n";
sl.insert(20, new int(20));
sl.print();
//测试
sl.insert(700, new int(700));
sl.insert(350, new int(350));
sl.insert(201, new int(201));
sl.insert(170, new int(170));
sl.insert(151, new int(151));
sl.insert(190, new int(190));
sl.insert(1000, new int(1000));
sl.insert(900, new int(900));
sl.insert(950, new int(950));
sl.insert(10, new int(10));
sl.print();
if ((it = sl.find(1000)) != NULL)
cout << "Found " << it << endl;
else cout << "No key 1000\n";
if ((it = sl.find(999)) != NULL)
cout << "Found " << it << endl;
else cout << "No key 999\n";
//测试
cout << "Finally, test iterator\n";
sl.insert(3500, new int(3500));
sl.insert(2010, new int(2010));
sl.insert(1700, new int(1700));
sl.insert(1510, new int(1510));
sl.insert(1900, new int(1900));
sl.insert(10000, new int(10000));
sl.insert(9000, new int(9000));
sl.insert(9500, new int(9500));
sl.insert(100, new int(100));
sl.print();
return 0;
}
总结
并没有用到什么技巧和复杂的结构,主要是理解实现的过程就行(奈何我逻辑不行,在网上看了好多讲解的文章
本文介绍了使用C++实现跳跃表的查找、插入和删除操作,详细展示了源代码,包括随机分配节点级数、节点结构以及跳跃表类的实现。通过案例测试验证了代码的正确性。
&spm=1001.2101.3001.5002&articleId=117854949&d=1&t=3&u=499b6b6a5cb946af8844e0886094b9c6)
907

被折叠的 条评论
为什么被折叠?



