@@ -71,214 +71,131 @@ public class Lc1206DesignSkiplist {
71
71
72
72
public static void main (String [] args ) {
73
73
Skiplist skiplist = new Lc1206DesignSkiplist ().new Skiplist ();
74
+
75
+ // Skiplist skiplist = new Skiplist();
76
+ skiplist .add (30 );
77
+ skiplist .add (40 );
78
+ skiplist .add (50 );
79
+ skiplist .add (60 );
80
+ skiplist .add (70 );
81
+ skiplist .add (90 );
82
+
83
+ System .out .println (skiplist .search (30 )); // true
84
+ System .out .println (skiplist .search (45 )); // false
85
+ skiplist .add (45 );
86
+ System .out .println (skiplist .search (45 )); // true
87
+ skiplist .erase (45 );
88
+ System .out .println (skiplist .search (45 )); // false
89
+
74
90
}
75
91
76
92
//leetcode submit region begin(Prohibit modification and deletion)
77
- class Skiplist {
78
93
79
- final int HEAD_VALUE = -1 ; // 链表头节点的值
80
- final Node HEAD = new Node (HEAD_VALUE );
94
+ class Skiplist {
81
95
82
- Node head ; // 最左上角的头节点,所有操作在开始位置
83
- int levels ; // 当前层级,即 head 节点所在的最高层数
84
- int length ; // 链表长度
96
+ static final int MAX_LEVEL = 16 ; // 定义跳表的最大层数
97
+ private final Node head = new Node (-1 , MAX_LEVEL ); // 初始化头节点,值为-1,层数为最大层数
98
+ private int level = 0 ; // 当前跳表的层数
99
+ private final Random random = new Random (); // 随机数生成器
85
100
86
- public Skiplist () {
87
- head = HEAD ;
88
- levels = 1 ;
89
- length = 1 ;
90
- }
101
+ // Node类表示跳表中的节点
102
+ class Node {
103
+ int value ; // 节点的值
104
+ Node [] forward ; // 前进指针数组,不同层级的前进指针
91
105
92
- public Node get (int target ) {
93
- return get (target , head );
106
+ Node (int value , int level ) {
107
+ this .value = value ; // 初始化节点值
108
+ this .forward = new Node [level + 1 ]; // 初始化前进指针数组
109
+ }
94
110
}
95
111
96
- public Node get (int target , Node from ) {
97
- Node n = from ;
98
- while (n != null ) {
99
- // 1.在同一层级上向右查找,直到链接结尾,或者找到
100
- while (n .right != null && n .right .val < target ) {
101
- n = n .right ;
102
- }
103
- // 2.若找到,返回true
104
- Node right = n .right ; // 要查找的节点
105
- if (right != null && right .val == target ) {
106
- return n ; // 返回要查找的节点的前一个
107
- }
108
- // 3.若右侧数据较大,向下一层
109
- n = n .down ;
112
+ // 生成节点的随机层数
113
+ private int randomLevel () {
114
+ int lvl = 0 ;
115
+ // 当随机数小于0.5且层数小于最大层数时,增加层数
116
+ while (random .nextFloat () < 0.5f && lvl < MAX_LEVEL ) {
117
+ lvl ++;
110
118
}
111
- return null ;
119
+ return lvl ; // 返回生成的层数
112
120
}
113
121
114
- /**
115
- * <pre>
116
- * 从 head 开始,从左到右、从上到下依次查找
117
- * 1.小于,往右
118
- * 2.相同,则返回
119
- * 3.链表结尾,或大于,往下
120
- *
121
- * </pre>
122
- *
123
- * @param target
124
- * @return
125
- */
122
+ // 在跳表中查找目标值
126
123
public boolean search (int target ) {
127
- // Node n = head;
128
- // while (n != null) {
129
- // // 1.在同一层级向右查找,直到链表的结尾
130
- // while (n.right != null && n.right.val < target) {
131
- // n = n.right; // 向右
132
- // }
133
- // // 2.若找到,返回true
134
- // Node right = n.right; // 要查找的节点
135
- // if(right != null && right.val == target) {
136
- // return true;
137
- // }
138
- //
139
- // // 3.若右侧数据较大,向下一层
140
- // n = n.down; // 往下
141
- // }
142
- //
143
- // return false;
144
- Node node = get (target );
145
- return node != null ;
124
+ Node current = head ; // 从头节点开始
125
+ // 从最高层逐层向下查找
126
+ for (int i = level ; i >= 0 ; i --) {
127
+ // 向前移动直到找到大于或等于目标值的节点
128
+ while (current .forward [i ] != null && current .forward [i ].value < target ) {
129
+ current = current .forward [i ];
130
+ }
131
+ }
132
+ current = current .forward [0 ]; // 移动到最底层
133
+ // 检查当前节点的值是否等于目标值
134
+ return current != null && current .value == target ;
146
135
}
147
136
148
- /**
149
- * <pre>
150
- * 插入节点,将节点插入原链表中正确的排序位置
151
- * 1.定位插入位置:原链表中 >= num 的最小节点前
152
- * 2.插入新节点
153
- * 3.根据扔硬币决定(是否)生成索引
154
- * </pre>
155
- *
156
- * @param num
157
- */
137
+ // 向跳表中插入一个值
158
138
public void add (int num ) {
159
- // 1.定位插入位置:原链表中 >= num 的最小节点前
160
- Node node = head ;
161
- Node [] nodes = new Node [levels ]; // 层级
162
- int i = 0 ; // 操作上述数组
163
- while (node != null ) { // node == null, 到达原链表(第一层)
164
- while (node .right != null && node .right .val < num ) {
165
- node = node .right ; // 向右走
139
+ Node [] update = new Node [MAX_LEVEL + 1 ]; // 用于存储需要更新的节点
140
+ Node current = head ; // 从头节点开始
141
+
142
+ // 从最高层逐层向下查找
143
+ for (int i = level ; i >= 0 ; i --) {
144
+ // 向前移动直到找到大于或等于插入值的节点
145
+ while (current .forward [i ] != null && current .forward [i ].value < num ) {
146
+ current = current .forward [i ];
166
147
}
167
-
168
- nodes [i ++] = node ;
169
-
170
- // 到达原链表(第一层)
171
- // if(node.down == null) {
172
- // break;
173
- // }
174
-
175
- // 继续查找下一层的位置
176
- node = node .down ;
148
+ update [i ] = current ; // 存储需要更新的节点
177
149
}
178
150
179
- // 2.插入新节点
180
- node = nodes [--i ]; // nodes 中最后一个元素
181
-
182
- Node newNode = new Node (num , node .right , null );
183
- node .right = newNode ;
184
- length ++;
185
-
186
- // 3.根据扔硬币决定(是否)生成索引
187
- addIndicesByCoinFlip (newNode , nodes , i );
188
- }
189
-
190
- /**
191
- * 抛硬币
192
- *
193
- * @param target
194
- * @param nodes
195
- * @param indices 可以创建的层数
196
- */
197
- private void addIndicesByCoinFlip (Node target , Node [] nodes , int indices ) {
198
- Node downNode = target ;
199
- // 1.抛硬币,在现有层级范围内建立索引
200
- Random random = new Random ();
201
- int coins = random .nextInt (2 ); // 0 or 1, 50%概率
202
- while (coins == 1 && levels < length >> 6 ) { // 除以2的2次方
203
- if (indices > 0 ) {
204
- Node prev = nodes [--indices ]; // 数组的倒数第二个元素,level 2,(循环下一次为 level 3)
205
- Node newIndex = new Node (target .val , prev .right , downNode ); // newIndex指向当前节点
206
- prev .right = newIndex ; //
207
- //indices--;
208
- downNode = newIndex ; // 保存新的向下节点
209
- coins = random .nextInt (2 ); // 0 or 1, 50%概率
210
- } else {
211
- // 2.抛硬币,决定是否建立一层超出跳表层数的索引层
212
- // 新建索引节点和头节点
213
- Node newIndex = new Node (target .val , null , downNode ); // 新层级,右边为null,下为上一次的down节点
214
- Node newHead = new Node (HEAD_VALUE , newIndex , head ); // 头节点
215
- head = newHead ; // head 指针上移
216
- levels ++; // 跳表层数加 1
151
+ int lvl = randomLevel (); // 生成新节点的随机层数
152
+ if (lvl > level ) {
153
+ // 如果新节点的层数大于当前层数,更新头节点的前进指针
154
+ for (int i = level + 1 ; i <= lvl ; i ++) {
155
+ update [i ] = head ;
217
156
}
157
+ level = lvl ; // 更新当前层数
218
158
}
219
- }
220
159
221
- /**
222
- * <pre>
223
- * 遍历跳表,查找与给定值相同的节点,删除每一层
224
- * 1.获取该指定数据节点的前一个节点
225
- * 2.与当前层链表断开
226
- * 3.下移,删除每一层
227
- * </pre>
228
- *
229
- * @param num
230
- * @return
231
- */
232
- public boolean erase (int num ) {
233
- boolean exist = false ;
234
- // Node n = head;
235
- // while (n != null) {
236
- // // 1.获取该指定数据节点的前一个节点
237
- // while (n.right != null && n.right.val < num) {
238
- // n = n.right; // 向右
239
- // }
240
- // // 2.与当前层链表断开
241
- // Node right = n.right; // 要删除的节点
242
- // if(right != null && right.val == num) {
243
- // n.right = right.right; // 前一节点 指向待删除节点的后一节点
244
- // right.right = null; // help GC
245
- // exist = true;
246
- // }
247
- //
248
- // // 3.下移,删除每一层
249
- // // 删除下一层
250
- // n = n.down;
251
- // }
252
- Node node = get (num , head );
253
- while (node != null ) {
254
- Node right = node .right ; // 要删除的节点
255
- node .right = right .right ;
256
- right .right = null ; // help GC
257
- exist = true ;
258
-
259
- node = get (num , node .down );
160
+ Node newNode = new Node (num , lvl ); // 创建新节点
161
+ for (int i = 0 ; i <= lvl ; i ++) {
162
+ newNode .forward [i ] = update [i ].forward [i ]; // 设置新节点的前进指针
163
+ update [i ].forward [i ] = newNode ; // 更新前一个节点的前进指针
260
164
}
261
- if (exist ) {
262
- length --; // 链表长度减 1
263
- }
264
-
265
- return exist ;
266
165
}
267
166
268
- class Node {
269
-
270
- int val ;
271
- Node right , down ;
272
-
273
- Node (int val ) {
274
- this (val , null , null );
167
+ // 从跳表中删除一个值
168
+ public boolean erase (int num ) {
169
+ Node [] update = new Node [MAX_LEVEL + 1 ]; // 用于存储需要更新的节点
170
+ Node current = head ; // 从头节点开始
171
+
172
+ // 从最高层逐层向下查找
173
+ for (int i = level ; i >= 0 ; i --) {
174
+ // 向前移动直到找到大于或等于删除值的节点
175
+ while (current .forward [i ] != null && current .forward [i ].value < num ) {
176
+ current = current .forward [i ];
177
+ }
178
+ update [i ] = current ; // 存储需要更新的节点
275
179
}
276
180
277
- Node (int val , Node right , Node down ) {
278
- this .val = val ;
279
- this .right = right ;
280
- this .down = down ;
181
+ current = current .forward [0 ]; // 移动到最底层
182
+ // 检查当前节点的值是否等于删除值
183
+ if (current != null && current .value == num ) {
184
+ // 更新前进指针,跳过当前节点
185
+ for (int i = 0 ; i <= level ; i ++) {
186
+ if (update [i ].forward [i ] != current ) {
187
+ break ;
188
+ }
189
+ update [i ].forward [i ] = current .forward [i ];
190
+ }
191
+
192
+ // 如果最高层的节点为空,降低当前层数
193
+ while (level > 0 && head .forward [level ] == null ) {
194
+ level --;
195
+ }
196
+ return true ; // 返回true表示删除成功
281
197
}
198
+ return false ; // 返回false表示删除失败
282
199
}
283
200
}
284
201
0 commit comments