UNPKG

4.3 kBJavaScriptView Raw
1import { SkipListNode } from "./SkipListNode";
2export class SkipList {
3 constructor(compareKey) {
4 this.compareKey = compareKey;
5 this.level = 0;
6 this.count = 0;
7 this.head = new SkipListNode();
8 }
9 get Level() {
10 return this.level;
11 }
12 get Count() {
13 return this.count;
14 }
15 get Head() {
16 return this.head;
17 }
18 isEmpty() {
19 return this.count === 0;
20 }
21 randomLevel() {
22 let k = 0;
23 let random = parseInt((Math.random() * 10).toString(), 10);
24 while (random % 2 === 0) {
25 k++;
26 random = parseInt((Math.random() * 10).toString(), 10);
27 }
28 return k > this.level ? this.level : k;
29 }
30 findNode(item) {
31 let result = null;
32 let temp = this.head;
33 for (let i = this.level - 1; i >= 0; i--) {
34 while (temp.getNext(i) && this.compare(temp.getNext(i).getItem(), this.compareKey ? { [this.compareKey]: item } : item)) {
35 temp = temp.getNext(i);
36 }
37 }
38 if (!temp.getNext(0)) {
39 return result;
40 }
41 let isEqual = false;
42 if (this.compareKey) {
43 isEqual = temp.getNext(0).getItem()[this.compareKey] === item;
44 }
45 else {
46 isEqual = temp.getNext(0).getItem() === item;
47 }
48 if (isEqual) {
49 result = temp.getNext(0);
50 }
51 return result;
52 }
53 insert(item) {
54 const updateNodes = this.findUpdateNodes(item);
55 if (updateNodes[0] && updateNodes[0].getNext(0) && updateNodes[0].getNext(0).getItem() === item) {
56 return this;
57 }
58 const level = this.randomLevel();
59 if (level === this.level) {
60 updateNodes[level] = this.head;
61 this.level++;
62 }
63 this.insertNode(new SkipListNode(item), updateNodes, level);
64 this.count++;
65 return this;
66 }
67 remove(item) {
68 const node = this.findNode(item);
69 if (node) {
70 const height = node.getHeight();
71 for (let i = 0; i < height; i++) {
72 const prev = node.getPrev(i);
73 const next = node.getNext(i);
74 prev.setNext(i, next);
75 if (next) {
76 next.setPrev(i, prev);
77 }
78 }
79 while (this.level && !this.head.getNext(this.level - 1)) {
80 this.head.deleteLastLevel();
81 this.level--;
82 }
83 this.count--;
84 }
85 return this;
86 }
87 getSkipTables() {
88 const table = [];
89 for (let index = 0; index < this.level; index++) {
90 const levelTables = [];
91 let temp = this.head;
92 while (temp = temp.getNext(index)) {
93 levelTables.push(temp);
94 }
95 table[index] = levelTables;
96 }
97 return table;
98 }
99 toString() {
100 const tables = this.getSkipTables();
101 return tables.reverse().reduce((ori, item) => {
102 ori.push(item.map(node => node.getItem().toString()).toString());
103 return ori;
104 }, []).join("\n");
105 }
106 compare(a, b) {
107 if (this.compareKey) {
108 return a[this.compareKey] < b[this.compareKey];
109 }
110 return a < b;
111 }
112 findUpdateNodes(item) {
113 const updateNodes = [];
114 for (let i = this.level - 1; i >= 0; i--) {
115 let tempNode = this.head.getNext(i);
116 let prevNode = null;
117 while (tempNode && this.compare(tempNode.getItem(), item)) {
118 prevNode = tempNode;
119 tempNode = tempNode.getNext(i);
120 }
121 if (tempNode) {
122 updateNodes[i] = tempNode.getPrev(i);
123 }
124 else {
125 updateNodes[i] = prevNode;
126 }
127 }
128 return updateNodes;
129 }
130 insertNode(node, updateNodes, level) {
131 for (let i = level; i >= 0; i--) {
132 const nextTemp = updateNodes[i].getNext(i);
133 if (nextTemp) {
134 nextTemp.setPrev(i, node);
135 node.setNext(i, nextTemp);
136 }
137 updateNodes[i].setNext(i, node);
138 node.setPrev(i, updateNodes[i]);
139 }
140 }
141}