UNPKG

6.43 kBPlain TextView Raw
1import { SkipListNode } from "./SkipListNode";
2
3/**
4 * 跳跃表
5 */
6export class SkipList<T>{
7 private level = 0;
8 private count = 0;
9 private head: SkipListNode<T>;
10 constructor(private compareKey?: keyof T){
11 this.head = new SkipListNode();
12 }
13
14 /**
15 * 层级
16 */
17 public get Level(){
18 return this.level;
19 }
20
21 /**
22 * 节点数
23 */
24 public get Count(){
25 return this.count;
26 }
27
28 /**
29 * 头节点
30 */
31 public get Head(){
32 return this.head;
33 }
34
35 /**
36 * 是否为空
37 */
38 public isEmpty(){
39 return this.count === 0;
40 }
41
42 /**
43 * 随机生成节点层级
44 * 以2的指数级随机
45 * @private
46 * @returns number
47 */
48 private randomLevel(){
49 let k = 0;
50 let random = parseInt((Math.random() * 10).toString(), 10);
51 while (random % 2 === 0){
52 k++;
53 random = parseInt((Math.random() * 10).toString(), 10);
54 }
55 return k > this.level ? this.level : k;
56 }
57
58 /**
59 * 查找节点
60 * @param item 如果存在compareKey,item为compareKey的值,否则item为T类型值
61 * @returns SkipListNode<T>
62 */
63 public findNode(item: any): SkipListNode<T>{
64 let result: SkipListNode<T> = null;
65 let temp = this.head;
66 // 从顶层开始向下遍历
67 for (let i = this.level - 1; i >= 0; i--){
68 // 从第i层当前节点向后遍历
69 while (temp.getNext(i) && this.compare(temp.getNext(i).getItem() ,
70 this.compareKey ? {[this.compareKey]: item} as any : item)){
71 temp = temp.getNext(i);
72 }
73 }
74 if (!temp.getNext(0)){
75 return result;
76 }
77 let isEqual = false;
78 if (this.compareKey) {
79 isEqual = temp.getNext(0).getItem()[this.compareKey] === item;
80 }else{
81 isEqual = temp.getNext(0).getItem() === item;
82 }
83 if (isEqual){
84 result = temp.getNext(0);
85 }
86 return result;
87 }
88
89 /**
90 * 插入节点 不允许插入相同权重节点
91 * @param item item 如果存在compareKey,item为compareKey的值,否则item为T类型值
92 * @returns this
93 */
94 public insert(item: T){
95 /**
96 * 1、获取随机高度(NOTE:如果高度增加,整体跳跃表level增加1)
97 * 2、循环最高层级,找到对应的当前节点大于的节点
98 * 3、链接当前层节点,重复2->3步骤
99 */
100
101 const updateNodes = this.findUpdateNodes(item);
102 if (updateNodes[0] && updateNodes[0].getNext(0) && updateNodes[0].getNext(0).getItem() === item){
103 return this;
104 }
105 const level = this.randomLevel();
106 if (level === this.level){
107 updateNodes[level] = this.head;
108 this.level++;
109 }
110 this.insertNode(new SkipListNode(item), updateNodes, level);
111 this.count++;
112 return this;
113 }
114
115 /**
116 * 删除
117 * @param item item 如果存在compareKey,item为compareKey的值,否则item为T类型值
118 */
119 public remove(item: any){
120 const node = this.findNode(item);
121 if (node){
122 // 链接删除的前节点和后节点
123 const height = node.getHeight();
124 for (let i = 0; i < height; i++){
125 const prev = node.getPrev(i);
126 const next = node.getNext(i);
127 prev.setNext(i, next);
128 if (next){
129 next.setPrev(i, prev);
130 }
131 }
132 // 删除顶层,降级
133 while (this.level && !this.head.getNext(this.level - 1)){
134 this.head.deleteLastLevel();
135 this.level--;
136 }
137 this.count--;
138 }
139 return this;
140 }
141
142 /**
143 * 获取跳表数据表 根据层级展示为二维数组
144 * @returns [][]
145 */
146 public getSkipTables(){
147 const table = [];
148 for (let index = 0; index < this.level; index++) {
149 const levelTables: Array<SkipListNode<T>> = [];
150 let temp = this.head;
151 // tslint:disable-next-line:no-conditional-assignment
152 while (temp = temp.getNext(index)){
153 levelTables.push(temp);
154 }
155 table[index] = levelTables;
156 }
157 return table;
158 }
159
160 public toString(){
161 const tables = this.getSkipTables();
162 return tables.reverse().reduce((ori: Array<string>, item) => {
163 ori.push(item.map(node => node.getItem().toString()).toString());
164 return ori;
165 }, []).join("\n");
166 }
167
168 private compare(a: T, b: T){
169 if (this.compareKey){
170 return a[this.compareKey] < b[this.compareKey];
171 }
172 return a < b;
173 }
174
175 /**
176 * 根据插入的节点查找需要更新的节点
177 * @param item 插入的节点
178 * @returns SkipListNode<T>[]
179 */
180 private findUpdateNodes(item: T){
181 const updateNodes: Array<SkipListNode<T>> = [];
182 // 从顶层向下查找,直到找到大于item的节点
183 for (let i = this.level - 1; i >= 0; i--){
184 let tempNode: SkipListNode<T> = this.head.getNext(i);
185 let prevNode: SkipListNode<T> = null;
186 while (tempNode && this.compare(tempNode.getItem() , item)){
187 prevNode = tempNode;
188 tempNode = tempNode.getNext(i);
189 }
190 // NOTE:未找到直接插入尾部
191 if (tempNode){
192 updateNodes[i] = tempNode.getPrev(i);
193 }else{
194 updateNodes[i] = prevNode;
195 }
196 }
197 return updateNodes;
198 }
199
200 /**
201 * 在需要更新的节点尾部插入节点
202 * @param node 被插入的节点
203 * @param updateNodes 需要更新的节点数组
204 * @param level 层级
205 */
206 private insertNode(node: SkipListNode<T>, updateNodes: Array<SkipListNode<T>>, level: number){
207 // 从当前层级向下更新被插入的节点
208 for (let i = level; i >= 0; i--){
209 const nextTemp = updateNodes[i].getNext(i);
210 if (nextTemp){
211 nextTemp.setPrev(i, node);
212 node.setNext(i, nextTemp);
213 }
214 updateNodes[i].setNext(i, node);
215 node.setPrev(i, updateNodes[i]);
216 }
217 }
218}