skiplist.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #ifndef NANXING_SKIPLISTS_H_
  2. #define NANXING_SKIPLISTS_H_
  3. #ifdef NANXING_DEBUG_
  4. #include "../tests/print_result.h"
  5. #endif
  6. #include"../basic/nanxing_operator_check.h"
  7. #include<cstdlib>
  8. #include<cstring>
  9. #include<exception>
  10. #include<random>
  11. #include<shared_mutex>
  12. #include <variant>
  13. #include<chrono>
  14. #include<iostream>
  15. namespace nanxing_extend
  16. {
  17. //限定为侵入式链表结构,因为这样方便空间的控制,可以直接在节点类中析构全部的空间
  18. static int count=0;
  19. //错误处理机制
  20. class nextpoint_new:std::exception //skip_node分配空间失败的时候
  21. {
  22. const char* what() const noexcept
  23. {
  24. return "malloc next_node point falure";
  25. }
  26. };
  27. class newNode_error:std::exception //申请新的空间的时候
  28. {
  29. const char* what() const noexcept
  30. {
  31. return "malloc new node error";
  32. }
  33. };
  34. class random_error:std::exception //申请预设随机数空间的时候
  35. {
  36. const char* what() const noexcept
  37. {
  38. return "malloc random space error";
  39. }
  40. };
  41. enum class Skip_result //跳表操作的结果
  42. {
  43. successufl,
  44. #ifdef SKIP_MAX_SIZE
  45. full,
  46. #endif
  47. #ifdef SKIP_MAX_SIZE
  48. too_small,
  49. #endif
  50. falure,
  51. exit,
  52. empty,
  53. };
  54. //注意这里的V只能是非指针类型,即侵入式数据结构因为这样的内存是可控的
  55. template<typename K,typename V>
  56. struct skip_node
  57. {
  58. static_assert(NANXING_BASIC_OPERATOR_(K,compare),"the type of K is error");
  59. static_assert(NANXING_BASIC_OPERATOR_(V,compare),"the type of V is error");
  60. static_assert(NANXING_OPERATOR_FORBIDEN_(V,point),"the type of V cannot be point"); //限定为侵入式数据结构
  61. skip_node<K,V>** next_node;
  62. V value;
  63. K key;
  64. private:
  65. int level;
  66. public:
  67. skip_node(){};
  68. skip_node(K _key,V _value,int _level):key(_key),value(_value),level(_level){};
  69. void init_next(int level)
  70. {
  71. try
  72. {
  73. next_node=::new skip_node<K,V>*[level];
  74. }
  75. catch(std::bad_alloc){ //捕获内存分配错误
  76. throw nextpoint_new(); //重新抛出一个定制的更详细的类型用以明确错误的具体位置
  77. }
  78. std::memset(next_node,0,sizeof(skip_node<K,V>*)*level);
  79. }
  80. K get_key(){ return key; }
  81. ~skip_node()
  82. {
  83. delete[] this->next_node; //将申请的next指针存储空间完全释放
  84. }
  85. };
  86. template<typename K,typename V>
  87. class skipList
  88. {
  89. static_assert(NANXING_BASIC_OPERATOR_(K,compare),"the type of K is error");
  90. static_assert(NANXING_BASIC_OPERATOR_(V,compare),"the type of V is error");
  91. static_assert(NANXING_OPERATOR_FORBIDEN_(V,point),"the type of V cannot be point"); //限定为侵入式数据结构
  92. private:
  93. using Node=skip_node<K,V>;
  94. using ptr=Node*;
  95. using Nptr=Node**;
  96. //由于C++的便利性我们考虑使用带头节点的跳表(C++允许对数据不进行初始化(默认构造函数))
  97. #ifdef NANXING_THREAD_
  98. std::shared_mutex RW_lock; //读写锁
  99. #endif
  100. Nptr head; //头节点
  101. int max_level; //最大高度
  102. int* random_level=nullptr; //如果启用随机数表这个就非空,反之为nullptr
  103. //当不启用随机数表,使用rand()构造随机数,启用的时候用mt19773构造随机数
  104. int current_level; //跳表当前高度
  105. int current_size; //跳表当前尺寸
  106. //这里出于一个考虑,当跳表单纯作为小数据内存数据库,单表大小限制是没有意义的
  107. //但是像level_db这样作为KV数据库的缓存的时候,就需要限制大小进行落盘
  108. #ifdef SKIP_MAX_SIZE
  109. int max_size; //跳表允许的最大尺寸
  110. #endif
  111. public:
  112. #ifndef SKIP_MAX_SIZE
  113. skipList(int _max_level):max_level(_max_level),random_level(nullptr)
  114. {
  115. try
  116. {
  117. Node* middle=::new skip_node<K,V>;
  118. middle->init_next(max_level);
  119. head=::new Node*[max_level];
  120. for(int i=0;i<max_level;i++)
  121. {
  122. head[i]=middle;
  123. }
  124. }
  125. catch(std::bad_alloc)
  126. {
  127. throw newNode_error(); //重新抛出更详细的错误类型
  128. }
  129. if(max_level==0){ //如果将高度设置为0直接调用terminate打断整个程序执行
  130. std::cerr<<"the level of skiplist cannot set zero"<<std::endl;
  131. std::terminate();
  132. }
  133. }
  134. #else
  135. skipList(int _max_level,int _max_size):max_size(_max_size),max_level(_max_level),random_level(nullptr)
  136. {
  137. try
  138. {
  139. Node* middle=::new skip_node;
  140. middle->init_next(max_level);
  141. head=::new (Node*)[max_level];
  142. for(auto& i in head)
  143. {
  144. i=middle;
  145. }
  146. }
  147. catch(std::bad_alloc)
  148. {
  149. throw newNode_error();
  150. }
  151. }
  152. #endif
  153. #ifdef _RANDOM_LIST_
  154. void create_random_list() //直接生成随机数表
  155. {
  156. #ifdef NANXING_THREAD_
  157. std::lock_guard<std::shared_mutex> lock(RW_lock);
  158. #endif
  159. if(random_level!=nullptr)
  160. {
  161. return;
  162. }
  163. try{
  164. random_level=::new int[1024]; //刚好是一页的大小(4KB)
  165. }
  166. catch(std::bad_alloc)
  167. {
  168. throw random_error();
  169. return;
  170. }
  171. std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count());
  172. for(int i=0;i<1024;i++)
  173. {
  174. random_level[i]=(rnd()%max_level)+1;
  175. }
  176. }
  177. #endif
  178. auto insert(K _key,V _value)->std::variant<Skip_result,V> //如果相同的时候我们考虑将value返回,由于限制为侵入式链表因此实际上不会内存泄露
  179. {
  180. #ifdef NANXING_THREAD_
  181. std::lock_guard<std::shared_mutex> lock(RW_lock);
  182. #endif
  183. #ifdef SKIP_MAX_SIZE
  184. if(current_size==max_size)
  185. {
  186. return sk=Skip_result::full;
  187. }
  188. #endif
  189. int rand_level=0;
  190. ptr* updata=new ptr[max_level]; //用于更新的数组
  191. for(int i=0;i<max_level;i++)
  192. {
  193. updata[i]=nullptr;
  194. }
  195. ptr point=head[max_level-1];
  196. ptr new_node;
  197. std::variant<Skip_result,V> sk;
  198. for(int i=max_level-1;i>=0;i--)
  199. {
  200. for(;;)
  201. {
  202. if(point->next_node[i]==nullptr)
  203. {
  204. updata[i]=point;
  205. break;
  206. }
  207. else if(point->next_node[i]->key>=_key)
  208. {
  209. if(point->next_node[i]->key==_key)
  210. {
  211. sk=std::move(point->next_node[i]->value); //这个值已经不需要了,直接移动
  212. point->next_node[i]->value=_value;
  213. return sk;
  214. }
  215. else
  216. {
  217. updata[i]=point;
  218. break;
  219. }
  220. }
  221. else{
  222. point=point->next_node[i]; //更新point指针
  223. }
  224. }
  225. }
  226. [[likely]]
  227. //cppcheck还不能识别C++17引入的属性
  228. if(random_level!=nullptr)
  229. {
  230. rand_level=random_level[current_size%1024];
  231. }
  232. else
  233. {
  234. rand_level=rand()%max_level;
  235. }
  236. ptr tmp=nullptr;
  237. new_node=new skip_node(_key,_value,rand_level);
  238. new_node->init_next(rand_level);
  239. for(int i=0;i<rand_level;i++)
  240. {
  241. tmp=updata[i]->next_node[i];
  242. updata[i]->next_node[i]=new_node;
  243. new_node->next_node[i]=tmp;
  244. }
  245. if(rand_level>current_level)
  246. {
  247. current_level=rand_level;
  248. }
  249. current_size++;
  250. sk=Skip_result::successufl;
  251. return sk;
  252. }
  253. auto Delete_node(K _key) noexcept ->std::variant<Skip_result,V> //由于使用侵入式数据结构,因此当节点空间析构的时候对应的数据也会完全析构
  254. {
  255. std::variant<Skip_result,V> sk;
  256. if(current_size==0)
  257. {
  258. std::cerr<<"The skiplist is empty"<<std::endl;
  259. return sk=Skip_result::empty;
  260. }
  261. else
  262. {
  263. ptr updata[max_level]={nullptr}; //用于更新的数组
  264. ptr point=head[max_level-1];
  265. ptr tmp;
  266. for(int i=max_level-1;i>=0;i--)
  267. {
  268. for(;;)
  269. {
  270. if(point->next_node[i]==nullptr)
  271. {
  272. break;
  273. }
  274. else if(point->next_node[i]->key>=_key)
  275. {
  276. if(point->next_node[i]->key==_key)
  277. {
  278. updata[i]=point;
  279. }
  280. else{
  281. break;
  282. }
  283. }
  284. else{
  285. point=point->next_node[i]; //更新point指针
  286. }
  287. }
  288. }
  289. if(updata[0]!=nullptr)
  290. {
  291. tmp=updata[0]->next_node[0]; //需要被删除的数据结构
  292. int i=0;
  293. while(i<max_level-1&&updata[i]!=0)
  294. {
  295. updata[i]->next_node[i]=tmp->next_node[i];
  296. i++;
  297. }
  298. delete tmp;
  299. sk=Skip_result::successufl;
  300. return sk;
  301. }
  302. }
  303. sk=Skip_result::falure;
  304. return sk;
  305. }
  306. [[nodiscard]]
  307. auto search(K _key) noexcept ->std::variant<Skip_result,V>{ //不涉及任何内存分配相关任务,因此是异常安全的
  308. #ifdef NANXING_THREAD_
  309. std::shared_lock<std::shared_mutex> lock(RW_lock);
  310. #endif
  311. std::variant<Skip_result,V> sk;
  312. ptr tmp=head[current_level-1];
  313. int tmp_level=current_level-1;
  314. for(int i=tmp_level;i>=0;i--)
  315. {
  316. while(tmp->next_node[tmp_level]!=nullptr)
  317. {
  318. if(tmp->next_node[tmp_level]->key>=_key)
  319. {
  320. if(tmp->next_node[tmp_level]->key==_key)
  321. {
  322. return sk=Skip_result::exit;
  323. }
  324. else{
  325. break; //跳出开始下一层循环
  326. }
  327. }
  328. else{
  329. tmp=tmp->next_node[tmp_level];
  330. }
  331. }
  332. }
  333. return sk=Skip_result::falure;
  334. }
  335. #ifdef NANXING_DEBUG_
  336. void Print()noexcept
  337. {
  338. ptr tmp=head[0]->next_node[0];
  339. while(tmp!=nullptr&&tmp->next_node[0]!=nullptr) //这里用了截断的技巧,即第一个条件不成立就不会触发第二个条件运行
  340. {
  341. std::cout<<"("<<tmp->get_key()<<","<<tmp->value<<")"<<"->";
  342. tmp=tmp->next_node[0];
  343. count++;
  344. }
  345. if(tmp!=nullptr)
  346. {
  347. std::cout<<"("<<tmp->get_key()<<","<<tmp->value<<")"<<std::endl;
  348. count++;
  349. }
  350. std::cout<<"count ="<<count<<std::endl;
  351. }
  352. #endif
  353. #ifdef SKIP_MAX_SIZE
  354. [[nodicard]]
  355. inline auto change_size(int _max_size)->std::variant<Skip_result,V> noexcept
  356. {
  357. std::variant<
  358. if(_max_size>this->max_size)
  359. {
  360. this->max_size=_max_size;
  361. tmp=Skip_result::successufl;
  362. return tmp;
  363. }
  364. else
  365. {
  366. tmp=Skip_result::too_samll;
  367. return tmp;
  368. }
  369. }
  370. #endif
  371. #ifdef NANXING_DEBUG_
  372. inline void insert_check()
  373. {
  374. ptr tmp=head[0]->next_node[0];
  375. K tmp_key;
  376. if(tmp==nullptr)
  377. {
  378. std::cerr<<"the skiplist is empty"<<std::endl;
  379. std::terminate();
  380. }
  381. else
  382. {
  383. tmp_key=head[0]->next_node[0]->key;
  384. }
  385. tmp=tmp->next_node[0];
  386. while(tmp->next_node[0]!=nullptr)
  387. {
  388. if(tmp->next_node[0]->key<tmp_key)
  389. {
  390. nanxing_test::inseat_result_to_txt("THE skiplist insert error");
  391. std::terminate();
  392. }
  393. tmp_key=tmp->key;
  394. tmp=tmp->next_node[0];
  395. }
  396. nanxing_test::inseat_result_to_txt<std::string>("skiplists insert successful");
  397. }
  398. #endif
  399. };
  400. }
  401. #endif