SkipList
一种让排序链表的查找的复杂度能降低到O(logn)级别的数据结构
相当于给排序链表加了索引使其能用二分来查找
// 每一层都是一个 sorted linkedlist
// 上面一层的元素是下层元素的一半, 均匀分布
1---------------------->9 // cache1
1---------->5---------->9 // cache2
1---->3---->5---->7---->9 // cache3
1->2->3->4->5->6->7->8->9->10
-
insert
:O(logn) avg,O(n) worst case- 首先从最上层开始向右查找,找到最大的一个小于要查找元素的节点
- 将之保存下来,记录各层这样的节点到一个栈中,直到最下层
- 从最下层开始,建立新的node,开始新node的下指针为空,保存新的下指针为本node
- 算概率(1/2 - > 1/4 -> 1/8 …),为true并且栈中还有元素则继续上层添加
- 如果栈pop完,但是概率还是为true,则再新添加一层
-
search
:O(logn) avg,O(n) worst case- 首先从最上层开始向右查找,找到最大的一个小于要查找元素的节点
- 如果右边的节点就是要查找的元素,直接返回true
- 如果不是就往下层找,下层是空则退出循环返回false
-
delete
:O(logn) avg,O(n) worst case- 首先从最上层开始向右查找,找到最大的一个小于要查找元素的节点
- 如果右边的节点就是要删除的元素,则直接用
node.right = node.right.right
将之删除 - 到下一层将之删除,直到最后一层
Python实现
class Skiplist:
def __init__(self):
self.head = Node() # dummy head
def search(self, target: int) -> bool:
node = self.head
while node:
while node.right and node.right.val < target:
node = node.right
if node.right and node.right.val == target:
return True
node = node.down # 这一层没有,往下一层
return False
def add(self, num: int) -> None:
nodes = []
node = self.head
while node:
# Move to the right in the current level
while node.right and node.right.val < num:
node = node.right
nodes.append(node)
# Move to the next level
node = node.down
insert = True
down = None
while insert and nodes:
node = nodes.pop()
node.right = Node(num, node.right, down)
down = node.right
insert = (random.getrandbits(1) == 0)
# Create a new level with a dummy head
# right = None
# down = current head
if insert:
self.head = Node(-1, None, self.head)
def erase(self, num: int) -> bool:
node = self.head
found = False
while node:
# Move to the right in the current level
while node.right and node.right.val < num:
node = node.right
# Find the target node
if node.right and node.right.val == num:
# Delete by skipping
node.right = node.right.right
found = True
# Move to the next level
node = node.down
return found
class Node:
def __init__(self, val=-1, right=None, down=None):
self.val = val
self.right = right
self.down = down
# Your Skiplist object will be instantiated and called as such:
# obj = Skiplist()
# param_1 = obj.search(target)
# obj.add(num)
# param_3 = obj.erase(num)
Java实现
class Skiplist {
class Node {
int val;
Node right;
Node down;
Node(){
this(-1, null, null);
}
Node(int val, Node right, Node down) {
this.val = val;
this.right = right;
this.down = down;
}
}
Node head;
public Skiplist() {
this.head = new Node();
}
public boolean search(int target) {
Node node = head;
while(node != null) {
while(node.right != null && node.right.val < target)
node = node.right;
if(node.right != null && node.right.val == target)
return true;
node = node.down;
}
return false;
}
public void add(int num) {
Node node = head;
LinkedList<Node> nodes = new LinkedList<>();
while(node != null) {
while(node.right != null && node.right.val < num) {
node = node.right;
}
nodes.add(node);
node = node.down;
}
// 向上回溯,根据概率判断是否新增节点
boolean isInsert = true; // 最下面一层 100% 要新增
double c = 1.0;
Node down = null; // 记录一下下面一层的down指针
while (!nodes.isEmpty() && isInsert) {
Node cur = nodes.removeLast();
cur.right = new Node(num, cur.right, down);
down = cur.right;
isInsert = count(c++);
}
if(isInsert)
this.head = new Node(-1, null, head);
}
public boolean erase(int num) {
Node node = head;
boolean res = false;
while(node != null) {
while(node.right != null && node.right.val < num) {
node = node.right;
}
if(node.right != null && node.right.val == num) {
res = true;
node.right = node.right.right;
}
node = node.down;
}
return res;
}
// 计算概率
static boolean count(double i) {
double x = new Random().nextDouble();
double y = 1 / Math.pow(2, i);
return x <= y;
}
}