skiplist.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //stl之外的东西
  2. #ifndef _SKIPLISTS_H_
  3. #define _SKIPLISTS_H_
  4. #include<ostream>
  5. #include<cstdlib>
  6. #include<type_traits>
  7. #include<shared_mutex>
  8. #include<mutex>
  9. #include<cstring>
  10. #include<random>
  11. #include<chrono>
  12. #include<optional>
  13. #include"../nanxing_memory.h"
  14. namespace nanxing
  15. {
  16. template<typename K,typename V=int>
  17. struct SkiplistNode
  18. {
  19. private:
  20. K key;
  21. V Value;
  22. public:
  23. using deep_point=SkiplistNode**;
  24. explicit SkiplistNode(){}
  25. SkiplistNode(K _k,V _v,int _deep):key(_k),Value(_v),deep_level(_deep) //这里有个问题,即V只能是一个可复制或者可移动的类型
  26. {
  27. forward= new SkiplistNode*[deep_level+1]; //构造一个存储对应的数据的指针(分配空间就好了没必要调用构造函数)
  28. std::memset(forward,0,sizeof(SkiplistNode*)*(deep_level+1)); //全部初始化为0
  29. }
  30. ~SkiplistNode()
  31. {
  32. delete[] forward;
  33. }
  34. [[nodiscard]]
  35. V get_value()const{return Value;};
  36. [[nodiscard]] //没事不要乱取值,否则会影响性能,返回值不用取来干嘛
  37. K get_key()const{return key;}
  38. void set_value(V _v){Value=_v;}
  39. [[nodiscard]]
  40. V reset_value(V _v){Value=_v;}
  41. deep_point forward; //指向下一层数据的指针数组的指针
  42. int deep_level;
  43. };
  44. template<typename K,typename V,typename alloc=nanxing::allocator<SkiplistNode<K,V>>> //使用自定义构造器
  45. class Skiplists
  46. {
  47. public:
  48. using Node=SkiplistNode<K,V>;
  49. Skiplists(int _max_level):Creater(),max_level(_max_level){
  50. current_level=0;
  51. Node_count=0;
  52. K key;
  53. V value;
  54. head=(this->Creater.allocate(sizeof(SkiplistNode<K,V>)));
  55. Creater.construct(head,key,value,_max_level);
  56. for(int i=0;i<10000;i++)
  57. {
  58. random_map[i]=get_random();
  59. }
  60. }
  61. [[nodiscard]]
  62. SkiplistNode<K,V>* creat_node(K key,V value,int level) //如果返回值被忽略会发生内存泄露
  63. {
  64. SkiplistNode<K,V>* tmp=static_cast<SkiplistNode<K,V>*>(Creater.allocate(sizeof(SkiplistNode<K,V>(key,value,level)))) ;
  65. Creater.construct(tmp,key,value,level); //进行内存分配
  66. return tmp;
  67. }
  68. int List_size(){return {Node_count};}
  69. [[nodiscard]]
  70. int insert_Node(K key,V value) //插入节点
  71. {
  72. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  73. std::unique_lock<std::shared_mutex>lk{RWmutex}; //这里用的是写锁
  74. #endif
  75. Node* tmp=this->head;
  76. Node* updata[max_level]={0}; //用于记录每一层的路径(首先初始化为全nullptr)
  77. for(int i= current_level;i>=0;i--) //从最顶层开始向下查找
  78. {
  79. while(tmp->forward[i]!=nullptr&&tmp->forward[i]->get_key()<key) //寻找插入点(这里的i代表在同一层)
  80. { //head节点是一个没有值的全空节点,用于标识头部,因此插入的所有节点都在head之后
  81. //因此查找的起始点是head->forward
  82. tmp=tmp->forward[i]; //这里需要参考skiplist的论文
  83. //这里递归向下的愿意是一个在i层出现的节点一定会出现在n层(n<i)
  84. //即只需要从这个节点开始先后查找即可
  85. }
  86. updata[i]=tmp; //用于记录每一层插入的位置
  87. }
  88. tmp=tmp->forward[0]; //查看最底层
  89. if(tmp!=nullptr&&tmp->get_key()==key)
  90. {
  91. return 2; //代表点已经存在
  92. }
  93. else //{tmp==nullptr|| tmp->get_key()!=key}
  94. {
  95. int _node_level=random_map[random_point%10000]; //打表,但是最离谱的是rand()比这边打表还快
  96. random_point++; //这个如果没有就退化为单链表
  97. if(_node_level>current_level)
  98. {
  99. for(int i=_node_level+1;i>=current_level+1;i--)
  100. {
  101. updata[i]=head;
  102. }
  103. current_level=_node_level;
  104. }
  105. Node* _insert=creat_node(key,value,_node_level);
  106. for(int i=0;i<=_node_level;i++)
  107. {
  108. _insert->forward[i]=updata[i]->forward[i];
  109. updata[i]->forward[i]=_insert;
  110. }
  111. Node_count++;
  112. return 1; //插入成功
  113. }
  114. return -1; //插入失败
  115. }
  116. int insert_Node(SkiplistNode<K,V>* _insert)
  117. {
  118. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  119. RWmutex.lock(); //这里用的是写锁
  120. #endif
  121. K key=_insert->get_key();
  122. Node* tmp=this->head;
  123. Node* updata[max_level]={0}; //用于记录每一层的路径(首先初始化为全nullptr)
  124. for(int i= current_level;i>=0;i--) //从最顶层开始向下查找
  125. {
  126. while(tmp->forward[i]!=nullptr&&tmp->forward[i]->get_key()<key) //寻找插入点(这里的i代表在同一层)
  127. {
  128. tmp=tmp->forward[i]; //这里需要参考skiplist的论文
  129. }
  130. updata[i]=tmp; //用于记录每一层插入的位置
  131. }
  132. tmp=tmp->forward[0]; //查看最底层
  133. if(tmp!=nullptr&&tmp->get_key()==key) //这里做一个截断判定,如果是空指针不会判定第二个条件
  134. {
  135. #ifdef _THREAD_
  136. RWmutex.unlock();
  137. #endif
  138. return 2; //代表点已经存在
  139. }
  140. else //{tmp==nullptr|| tmp->get_key()!=key}
  141. {
  142. int _node_level=_insert->deep_level;
  143. if(_node_level>current_level)
  144. {
  145. for(int i=_node_level+1;i>current_level+1;i--)
  146. {
  147. updata[i]=head;
  148. }
  149. }
  150. for(int i=0;i<=_node_level;i++)
  151. {
  152. _insert->forward[i]=updata[i]->forward[i];
  153. updata[i]->forward[i]=_insert;
  154. }
  155. Node_count++;
  156. #ifdef _THREAD_
  157. RWmutex.unlock();
  158. #endif
  159. return 1; //插入成功
  160. }
  161. #ifdef _THREAD_
  162. RWmutex.unlock();
  163. #endif
  164. return -1; //插入失败
  165. #ifdef _THREAD_
  166. RWmutex.unlock();
  167. #endif
  168. }
  169. bool search_Node(K key) //查找值是否存在
  170. {
  171. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  172. RWmutex.lock_shared(); //这里用的是读锁
  173. #endif
  174. using Node=SkiplistNode<K,V>;
  175. Node* tmp=head;
  176. for(int i=current_level;i>=0;i--) //逐层查找
  177. {
  178. while(tmp->forward[i]!=nullptr&&tmp->forward[i]->get_key()<key)
  179. {
  180. tmp=tmp->forward[i];
  181. }
  182. }
  183. tmp=tmp->forward[0];
  184. if(tmp!=nullptr&&tmp->get_key()==key)
  185. {
  186. return true;
  187. }
  188. else
  189. {
  190. return false;
  191. }
  192. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  193. RWmutex.unlock_shared(); //这里用的是读锁
  194. #endif
  195. }
  196. std::optional<V> get_value_from_key(K key) //通过键返回值
  197. {
  198. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  199. RWmutex.lock_shared(); //这里用的是读锁
  200. #endif
  201. using Node=SkiplistNode<K,V>;
  202. std::optional<V> opt;
  203. Node* tmp=head;
  204. for(int i=current_level;i>=0;i--) //逐层查找
  205. {
  206. while(tmp->forward[i]!=nullptr&&tmp->forward[i]->get_key()<key)
  207. {
  208. tmp=tmp->forward[i];
  209. }
  210. }
  211. tmp=tmp->forward[0];
  212. if(tmp!=nullptr&&tmp->get_key()==key)
  213. {
  214. opt=tmp->get_value();
  215. }
  216. else
  217. {
  218. opt = std::nullopt;
  219. }
  220. return opt;
  221. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  222. RWmutex.unlock_shared(); //这里用的是读(共享)锁
  223. #endif
  224. }
  225. int delete_Node(K key)
  226. {
  227. #ifdef _THREAD_ //考虑到很多时候是用单线程异步所以用锁反而会拖累速度,所以条件编译单线程不加锁
  228. RWmutex.lock(); //这里用的是写锁
  229. #endif
  230. using Node=SkiplistNode<K,V>;
  231. Node* updata[current_level]={nullptr}; //由于是删除,用current_level就好了
  232. Node* tmp=head;
  233. for(int i=current_level;i>=0;i++)
  234. {
  235. while(tmp->forward[i]!=nullptr&&tmp->forward[i]->get_key()<key)
  236. {
  237. tmp=tmp->forward[i];
  238. }
  239. updata[i]=tmp;
  240. }
  241. tmp=tmp->forward[0];
  242. if(tmp!=nullptr&&tmp->get_key()==key) //判断第一层的这个点是否为需要删除的点
  243. {
  244. Node* deletes=tmp;
  245. for(int i=0;i<current_level;i++) //从下往上修改对应的指针
  246. {
  247. if(updata[i]->forward[i]!=key) //到某一层这个指针指向的不是需要删除的节点的时候停止(跳表中任意的节点只会出现在第0-k层)
  248. {
  249. break;
  250. }
  251. updata->forward[i]=tmp->forward[i];
  252. }
  253. Creater.destory(deletes); //调用析构函数
  254. Creater.deallocate(deletes); //释放空间
  255. return 1; //删除成功
  256. }
  257. else
  258. {
  259. return 0; //没有需要删除的节点
  260. }
  261. return -1; //删除失败
  262. #ifdef _THREAD_
  263. RWmutex.unlock();
  264. #endif
  265. }
  266. void Print_basic()
  267. {
  268. using Node=SkiplistNode<K,V>;
  269. Node* tmp=head;
  270. if(tmp->forward[0]!=nullptr)
  271. {
  272. tmp =tmp ->forward[0];
  273. std::cout<<"("<<tmp->get_key()<<","<<tmp->get_value()<<")";
  274. }
  275. while(tmp->forward[0]!=nullptr)
  276. {
  277. tmp=tmp->forward[0];
  278. std::cout<<"->"<<"("<<tmp->get_key()<<","<<tmp->get_value()<<")";
  279. }
  280. std::cout<<std::endl;
  281. }
  282. private:
  283. int get_random() //生成随机数,用于创建对应的数据的层数
  284. {
  285. // 通过<chrono>库获取当前的高精度时间点
  286. auto now = std::chrono::system_clock::now();
  287. // 将时间点转换为自纪元(通常是1970年1月1日)以来的纳秒数
  288. auto duration_since_epoch = now.time_since_epoch();
  289. // 将纳秒数转换为无符号长整型,用作随机数生成的种子
  290. unsigned long seed = std::chrono::duration_cast<std::chrono::nanoseconds>(duration_since_epoch).count();
  291. // 创建一个随机数引擎,这里使用的是Mersenne Twister引擎
  292. std::mt19937 rng(seed);
  293. // 定义一个均匀分布的整数范围
  294. std::uniform_int_distribution<int> dist(0, max_level);
  295. //生成一个随机数
  296. return dist(rng);
  297. //return (rand()%max_level);
  298. }
  299. private:
  300. int max_level;
  301. int current_level; //当前的深度
  302. #ifdef _THREAD_ //不是多线程没有必要
  303. std::shared_mutex RWmutex; //读写锁
  304. #endif
  305. alloc Creater; //构造器实例
  306. SkiplistNode<K,V>* head; //跳表的起点
  307. int Node_count; //总结点数
  308. int random_map[10000]={0}; //随机数表
  309. int random_point=0; //指示当前访问的随机数的位置
  310. };
  311. }
  312. #endif