@data-structure/skip-list Home Manual Reference Source

src/SkipList.js

  1. import assert from 'assert';
  2. import Node from './Node.js';
  3. import keys from './keys.js';
  4. import iter from './iter.js';
  5. import downMost from './downMost.js';
  6. import searchTopMost from './searchTopMost.js';
  7. import bottomMostPredecessor from './bottomMostPredecessor.js';
  8. import deleteFromTopMost from './deleteFromTopMost.js';
  9. import insertFromBottomMostPredecessor from './insertFromBottomMostPredecessor.js';
  10. import makeQuasiRandom from './makeQuasiRandom.js';
  11. import makeBottomLevel from './makeBottomLevel.js';
  12.  
  13. /**
  14. * @param {Number} p Promotion probability in (0,1).
  15. * @param {Function} compare
  16. * @param {Node} head
  17. */
  18. export default function SkipList(p, compare, head = new Node()) {
  19. this.head = head; // Sentinel node
  20. this.p = p;
  21. this.compare = compare;
  22. }
  23.  
  24. SkipList.prototype.add = function (key) {
  25. const node = bottomMostPredecessor(this.compare, this.head, key);
  26. const pred = insertFromBottomMostPredecessor(this.p, node, key);
  27. if (pred.left === null && pred.up === null) this.head = pred;
  28. };
  29.  
  30. SkipList.prototype.get = function (key) {
  31. const node = searchTopMost(this.compare, this.head, key);
  32. return node === null ? null : node.key;
  33. };
  34.  
  35. SkipList.prototype.has = function (key) {
  36. return searchTopMost(this.compare, this.head, key) !== null;
  37. };
  38.  
  39. SkipList.prototype.remove = function (key) {
  40. const node = searchTopMost(this.compare, this.head, key);
  41. if (node === null) return false;
  42.  
  43. deleteFromTopMost(node);
  44. return true;
  45. };
  46.  
  47. SkipList.prototype._predecessor = function (key) {
  48. return bottomMostPredecessor(this.compare, this.head, key);
  49. };
  50.  
  51. SkipList.prototype.levelOne = function () {
  52. return downMost(this.head);
  53. };
  54.  
  55. SkipList.prototype.levels = function () {
  56. assert(this.head !== null);
  57. let k = 0;
  58. let current = this.head;
  59. do {
  60. ++k;
  61. current = current.down;
  62. } while (current !== null);
  63.  
  64. return k;
  65. };
  66.  
  67. SkipList.prototype.keys = function () {
  68. const level = this.levelOne();
  69. return keys(level);
  70. };
  71.  
  72. SkipList.prototype.values = function () {
  73. return this.keys();
  74. };
  75.  
  76. SkipList.prototype[Symbol.iterator] = function () {
  77. return this.keys();
  78. };
  79.  
  80. SkipList.prototype.range = function* (left, right) {
  81. const pred = this._predecessor(left);
  82. for (const node of iter(pred)) {
  83. if (this.compare(node.key, right) >= 0) break;
  84. yield node.key;
  85. }
  86. };
  87.  
  88. SkipList.from = (compare, iterable, p = 1 / 2) => {
  89. if (p === 1 / 2) {
  90. const bottomLevelHead = makeBottomLevel(compare, iterable);
  91. const head = makeQuasiRandom(p, bottomLevelHead);
  92. return new SkipList(p, compare, head);
  93. }
  94.  
  95. const list = new SkipList(p, compare);
  96. for (const key of iterable) list.add(key);
  97. return list;
  98. };