Skip to content

Commit 6710844

Browse files
committed
新增跳表C++版本.翻译来源JAVA版本
1 parent 5c178ac commit 6710844

File tree

1 file changed

+363
-0
lines changed

1 file changed

+363
-0
lines changed

c-cpp/17_skiplist/SkipList.cpp

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <iostream>
4+
#include <string>
5+
#include <cstring>
6+
#include <random>
7+
#include <ctime>
8+
using namespace std;
9+
10+
/**
11+
* 跳表的一种实现方法。
12+
* 跳表中存储的是正整数,并且存储的是不重复的。
13+
*
14+
* 跳表的C++版本.
15+
* 翻译JAVA版本 原作者 Author:ZHENG
16+
*
17+
* Author:puhuaqiang
18+
*
19+
* 跳表结构:
20+
*
21+
* 第K级 1 9
22+
* 第K-1级 1 5 9
23+
* 第K-2级 1 3 5 7 9
24+
* ... ....
25+
* 第0级(原始链表) 1 2 3 4 5 6 7 8 9
26+
*/
27+
28+
const int MAX_LEVEL = 16;
29+
30+
/**
31+
* @brief 节点
32+
*/
33+
class CNode
34+
{
35+
public:
36+
CNode();
37+
~CNode();
38+
39+
std::string toString();
40+
/**
41+
* @brief 获取索引链表
42+
*/
43+
CNode** GetIdxList();
44+
45+
/**
46+
* @brief 设置数据
47+
*/
48+
void SetData(int v);
49+
/**
50+
* @brief 获取数据
51+
*/
52+
int GetData();
53+
/**
54+
* @brief 设置最大索引级别
55+
*/
56+
void SetLevel(int l);
57+
private:
58+
/**当前节点的值*/
59+
int m_data;
60+
/**
61+
* 当前节点的每个等级的下一个节点.
62+
* 第2级 N1 N2
63+
* 第1级 N1 N2
64+
* 如果N1是本节点,则 m_lpForwards[x] 保存的是N2
65+
*
66+
* [0] 就是原始链表.
67+
*/
68+
CNode* m_lpForwards[MAX_LEVEL];
69+
/**当前节点的所在的最大索引级别*/
70+
int m_iMaxLevel;
71+
};
72+
73+
/**
74+
* @brief 跳表
75+
*/
76+
class CSkipList
77+
{
78+
public:
79+
CSkipList();
80+
~CSkipList();
81+
/**
82+
* @brief 查找指定的值的节点
83+
* @param v 正整数
84+
*/
85+
CNode* Find(int v);
86+
/**
87+
* @brief 插入指定的值
88+
* @param v 正整数
89+
*/
90+
void Insert(int v);
91+
/**
92+
* @brief 删除指定的值的节点
93+
* @param v 正整数
94+
*/
95+
int Delete(int v);
96+
void PrintAll();
97+
/**
98+
* @brief 打印跳表结构
99+
* @param l 等于-1时打印所有级别的结构 >=0时打印指定级别的结构
100+
*/
101+
void PrintAll(int l);
102+
/**
103+
* @brief 插入节点时,得到插入K级的随机函数
104+
* @return K
105+
*/
106+
int RandomLevel();
107+
108+
private:
109+
int levelCount;
110+
/**
111+
* 链表
112+
* 带头/哨所(节点)
113+
*/
114+
CNode* m_lpHead;
115+
};
116+
117+
int main()
118+
{
119+
CSkipList skipList;
120+
/// 插入原始值
121+
for(int i=1; i< 50; i++){
122+
if((i%3) == 0){
123+
skipList.Insert(i);
124+
}
125+
}
126+
for(int i=1; i< 50; i++){
127+
if((i%3) == 1){
128+
skipList.Insert(i);
129+
}
130+
}
131+
skipList.PrintAll();
132+
std::cout<<std::endl;
133+
/// 打印所有等级结构
134+
skipList.PrintAll(-1);
135+
/// 查找
136+
std::cout<<std::endl;
137+
CNode* lpNode = skipList.Find(27);
138+
if(NULL != lpNode){
139+
std::cout<<"查找值为27的节点,找到该节点,节点值:"<<lpNode->GetData()<<std::endl;
140+
}else{
141+
std::cout<<"查找值为27的节点,未找到该节点"<<std::endl;
142+
}
143+
/// 删除
144+
std::cout<<std::endl;
145+
int ret = skipList.Delete(46);
146+
if(0 == ret){
147+
std::cout<<"查找值为46的节点,找到该节点,并删除成功"<<std::endl;
148+
}else{
149+
std::cout<<"查找值为46的节点,找到该节点,删除失败"<<std::endl;
150+
}
151+
std::cout<<std::endl;
152+
//打印所有等级结构
153+
skipList.PrintAll(-1);
154+
std::cin.ignore();
155+
return 0;
156+
}
157+
158+
CNode::CNode()
159+
{
160+
m_data = -1;
161+
m_iMaxLevel = 0;
162+
for(int i=0; i<MAX_LEVEL; i++){
163+
m_lpForwards[i] = NULL;
164+
}
165+
}
166+
CNode::~CNode()
167+
{
168+
169+
}
170+
CNode** CNode::GetIdxList()
171+
{
172+
return m_lpForwards;
173+
}
174+
175+
void CNode::SetData(int v)
176+
{
177+
m_data = v;
178+
}
179+
int CNode::GetData()
180+
{
181+
return m_data;
182+
}
183+
void CNode::SetLevel(int l)
184+
{
185+
m_iMaxLevel = l;
186+
}
187+
std::string CNode::toString()
188+
{
189+
char tmp[32];
190+
std::string ret;
191+
192+
ret.append("{ data: ");
193+
sprintf(tmp, "%d", m_data);
194+
ret.append(tmp);
195+
ret.append("; levels: ");
196+
sprintf(tmp, "%d", m_iMaxLevel);
197+
ret.append(tmp);
198+
ret.append(" }");
199+
return ret;
200+
}
201+
202+
CSkipList::CSkipList()
203+
{
204+
levelCount = 1;
205+
m_lpHead = new CNode();
206+
}
207+
CSkipList::~CSkipList()
208+
{
209+
210+
}
211+
CNode* CSkipList::Find(int v)
212+
{
213+
CNode* lpNode = m_lpHead;
214+
/**
215+
* 从 最大级索引链表开始查找.
216+
* K -> k-1 -> k-2 ...->0
217+
*/
218+
for(int i=levelCount-1; i>=0; --i){
219+
/**
220+
* 查找小于v的节点(lpNode).
221+
*/
222+
while((NULL != lpNode->GetIdxList()[i]) && (lpNode->GetIdxList()[i]->GetData() < v)){
223+
lpNode = lpNode->GetIdxList()[i];
224+
}
225+
}
226+
/**
227+
* lpNode 是小于v的节点, lpNode的下一个节点就等于或大于v的节点
228+
*/
229+
if((NULL != lpNode->GetIdxList()[0]) && (lpNode->GetIdxList()[0]->GetData() == v)){
230+
return lpNode->GetIdxList()[0];
231+
}
232+
return NULL;
233+
}
234+
void CSkipList::Insert(int v)
235+
{
236+
/// 新节点
237+
CNode* lpNewNode = new CNode();
238+
if(NULL == lpNewNode){
239+
return;
240+
}
241+
242+
/**
243+
* 新节点最大分布在的索引链表的上限
244+
* 如果返回 3,则 新的节点会在索引1、2、3上的链表都存在
245+
*/
246+
int level = RandomLevel();
247+
lpNewNode->SetData(v);
248+
lpNewNode->SetLevel(level);
249+
250+
/**
251+
* 临时索引链表
252+
* 主要是得到新的节点在每个索引链表上的位置
253+
*/
254+
CNode *lpUpdateNode[level];
255+
for(int i=0; i<level; i++){
256+
/// 每个索引链表的头节点
257+
lpUpdateNode[i] =m_lpHead;
258+
}
259+
CNode* lpFind = m_lpHead;
260+
for(int i= level-1; i >= 0; --i){
261+
/**
262+
* 查找位置
263+
* eg. 第1级 1 7 10
264+
* 如果插入的是 6
265+
* lpFind->GetIdxList()[i]->GetData() : 表示节点lpFind在第1级索引的下一个节点的数据
266+
* 当 "lpFind->GetIdxList()[i]->GetData() < v"不成立的时候,
267+
* 新节点就要插入到 lpFind节点的后面, lpFind->GetIdxList()[i] 节点的前面
268+
* 即在这里 lpFind就是1 lpFind->GetIdxList()[i] 就是7
269+
*/
270+
while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){
271+
lpFind = lpFind->GetIdxList()[i];
272+
}
273+
/// lpFind 是新节点在 第i级索引链表的后一个节点
274+
lpUpdateNode[i] = lpFind;
275+
}
276+
277+
for(int i=0; i<level; ++i){
278+
/**
279+
* 重新设置链表指针位置
280+
* eg 第1级索引 1 7 10
281+
* 插入6.
282+
* lpUpdateNode[i] 节点是1; lpUpdateNode[i]->GetIdxList()[i]节点是7
283+
*
284+
* 这2句代码就是 把6放在 1和7之间
285+
*/
286+
lpNewNode->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i];
287+
lpUpdateNode[i]->GetIdxList()[i] = lpNewNode;
288+
}
289+
if(levelCount < level){
290+
levelCount = level;
291+
}
292+
}
293+
int CSkipList::Delete(int v)
294+
{
295+
int ret = -1;
296+
CNode *lpUpdateNode[levelCount];
297+
CNode *lpFind = m_lpHead;
298+
for(int i=levelCount-1; i>= 0; --i){
299+
/**
300+
* 查找小于v的节点(lpFind).
301+
*/
302+
while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){
303+
lpFind = lpFind->GetIdxList()[i];
304+
}
305+
lpUpdateNode[i] = lpFind;
306+
}
307+
/**
308+
* lpFind 是小于v的节点, lpFind的下一个节点就等于或大于v的节点
309+
*/
310+
if((NULL != lpFind->GetIdxList()[0]) && (lpFind->GetIdxList()[0]->GetData() == v)){
311+
for(int i=levelCount-1; i>=0; --i){
312+
if((NULL != lpUpdateNode[i]->GetIdxList()[i]) && (v == lpUpdateNode[i]->GetIdxList()[i]->GetData())){
313+
lpUpdateNode[i]->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i]->GetIdxList()[i];
314+
ret = 0;
315+
}
316+
}
317+
}
318+
return ret;
319+
}
320+
void CSkipList::PrintAll()
321+
{
322+
CNode* lpNode = m_lpHead;
323+
while(NULL != lpNode->GetIdxList()[0]){
324+
std::cout<<lpNode->GetIdxList()[0]->toString().data()<<std::endl;
325+
lpNode = lpNode->GetIdxList()[0];
326+
}
327+
}
328+
void CSkipList::PrintAll(int l)
329+
{
330+
for(int i=MAX_LEVEL-1; i>=0;--i){
331+
CNode* lpNode = m_lpHead;
332+
std::cout<<""<<i<<"级:"<<std::endl;
333+
if((l < 0) || ((l >= 0) && (l == i))){
334+
while(NULL != lpNode->GetIdxList()[i]){
335+
std::cout<<lpNode->GetIdxList()[i]->GetData()<<" ";
336+
lpNode = lpNode->GetIdxList()[i];
337+
}
338+
std::cout<<std::endl;
339+
if(l >= 0){
340+
break;
341+
}
342+
}
343+
}
344+
}
345+
int GetRandom()
346+
{
347+
static int _count = 1;
348+
std::default_random_engine generator(time(0) + _count);
349+
std::uniform_int_distribution<int> distribution(1,99999/*0x7FFFFFFF*/);
350+
int dice_roll = distribution(generator);
351+
_count += 100;
352+
return dice_roll;
353+
}
354+
int CSkipList::RandomLevel()
355+
{
356+
int level = 1;
357+
for(int i=1; i<MAX_LEVEL; ++i){
358+
if(1 == (GetRandom()%3)){
359+
level++;
360+
}
361+
}
362+
return level;
363+
}

0 commit comments

Comments
 (0)