首先贴出参考的博客:
https://blog.csdn.net/moakun/article/details/79997037
根据这篇博客的代码自己实现了一个,添加了删除模块。
如果有理论不懂的可以看上面的博客也可以看下面的视频:
https://www.bilibili.com/video/BV1z7411f7mE?from=search&seid=17814720194061062383
下面是我的代码,代码中有详细的注释,我就不在赘述:
import java.util.Random;
/**
* 〈一句话功能简述〉<br>
* 〈〉
*
* @author Administrator
* @create 2020/04/13
* @since 1.0.0
*/
public class SkipListTest {
//跳表的层数,默认为1
private int skiplevel = 1;
//最大值,为尾部的key
private int maxint = Integer.MAX_VALUE;
//最小值,为头部的key
private int minint = Integer.MIN_VALUE;
//跳表的头结点和尾节点
private SkipNode head = null,tail = null;
//随机对象,用于随机的判断当前的节点需不需要升层
private Random random = null;
//随机值判断的标志
private double isup = 0.5;
//节点数
private int nodes = 0;
public SkipListTest(){
clear();
}
/**
* 重置当前的状态
*/
public void clear(){
//重置层数
setSkiplevel(1);
//设置随机对象
setRandom(new Random());
//设置头
setHead(new SkipNode(getMinint(),null));
//设置尾
setTail(new SkipNode(getMaxint(),null));
//连接头尾
UpLink(getHead(),getTail());
}
/**
* 从中间断开
* node1-right-*-left-node3
* node1-right-*-left-node2-right-*-left-node3
* @param node1 已存在的节点
* @param node2 已存在节点后面要插入的节点
*/
public void LeftAndRight(SkipNode node1,SkipNode node2){
SkipNode node3 = node1.getRight();
node2.setLeft(node1);
node2.setRight(node3);
node1.setRight(node2);
node3.setLeft(node2);
}
/**
* node1-right-*-left-node-right-*-left-node2
* node1-right-*-left-node2
* @param Node 需要删除的节点
*/
public void NoLeftAndRight(SkipNode Node){
SkipNode leftsn = Node.getLeft();
SkipNode rightsn = Node.getRight();
leftsn.setRight(rightsn);
rightsn.setLeft(leftsn);
System.out.println(Node.toString()+" 已删除");
//如果删除了这个元素后本层只剩下了头和尾并且当前的层数是大于1的,那么将本层也删掉
if(leftsn.getRight().getKey() == getMaxint() && leftsn.getKey() == minint&&getSkiplevel()>1){
System.out.println("此层需要被删除");
//断开连接
leftsn.setRight(null);
rightsn.setLeft(null);
//重新对head和tail赋值
setHead(leftsn.getDown());
setTail(rightsn.getDown());
//取消对上层的引用
getHead().setUp(null);
getTail().setUp(null);
//层数减一
setSkiplevel(getSkiplevel()-1);
}
}
/**
* node2
* |
* down
* |
* *
* |
* up
* |
* node1
* @param node1 当前存在的节点
* @param node2 将要作为当前节点的上面节点的节点
*/
public void UpAndDown(SkipNode node1,SkipNode node2){
node1.setUp(node2);
node2.setDown(node1);
}
/**
* 专门连接两端的函数,即head --left --*--right --tail
* node1-right-*-left-node2
* @param node1 前一个节点
* @param node2 后一个节点
*/
public void UpLink(SkipNode node1,SkipNode node2){
node1.setRight(node2);
node2.setLeft(node1);
}
/**
* head ---------------------tail
* | |
* head --------node1--------tail
* | | |
* head --node2-node1--node3-tail
* | | | | |
* head-n4-node2-node1-node3-tail
* @param key 需要匹配的key
* @return
*/
public SkipNode FindSkipNode(int key){
SkipNode sn = getHead();
System.out.println("************查找,当前查找的key为 "+key);
while(true){
while (sn.getRight().getKey() != getMaxint()&&sn.getRight().getKey()<=key){
sn = sn.getRight();
System.out.println("向右走"+sn.toString());
}
//向下走
if(sn.getDown() != null){
sn = sn.getDown();
System.out.println("向下走"+sn.toString());
}else break; //要么找到了,要么表示没有数据
}
return sn;
}
/**
* 1.先查找到需要插入的地方
* 2.执行插入
* 3.判定需不需要进行升层
* @param key 插入节点的key
* @param value 插入节点的value
*/
public void AddSkipNode(int key,String value){
SkipNode sn = FindSkipNode(key);
if(sn.getKey() == key){
sn.setValue(value);
return;
}else{
//1.创建出节点
SkipNode skipNode = new SkipNode(key,value);
//2.插入节点
LeftAndRight(sn,skipNode);
//用作判定是否超过现有的层数
int currentlevel = 1;
//3.判定需不需要进行升层,使用抛硬币的方法,1/2的概率
double v = getRandom().nextDouble();
System.out.println(" 当前的节点 "+skipNode.toString());
while(v<=getIsup()){
System.out.println("需要升层");
//1.首先判断currentlevel是否超过了现有的层数
if(currentlevel>=getSkiplevel()){
System.out.println("需要建立一个新的层次");
//2.此时先提高层数
setSkiplevel(getSkiplevel()+1);
//3.创建出两端的副本
SkipNode snhead = new SkipNode(getMinint(),null);
SkipNode sntail = new SkipNode(getMaxint(),null);
//4.水平上的连接
UpLink(snhead,sntail);
//5.上下的承接
UpAndDown(getHead(),snhead);
UpAndDown(getTail(),sntail);
//6.赋值
setHead(snhead);
setTail(sntail);
}
//7.找到祖静的可以到上一层的节点
//如果本节点就是那么直接跳过
while(sn.getUp() == null){
sn = sn.getLeft();
System.out.println("向左走,找到最靠近的多层节点 "+sn.toString());
}
//得到上一层
sn = sn.getUp();
System.out.println("找到上层节点,开始构建层次,当前的层次为 "+currentlevel);
//8.新建关于当前插入节点的上层节点
SkipNode skipNodeUP = new SkipNode(key, null);
//插入节点
LeftAndRight(sn,skipNodeUP);
//层次关系
UpAndDown(skipNode,skipNodeUP);
//赋值
skipNode = skipNodeUP;
v = getRandom().nextDouble();
//加层
currentlevel++;
System.out.println("构建完成,当前的节点的层次为 "+currentlevel);
}
if (currentlevel == 0)
System.out.println("当前节点不需要构建层次");
//节点数加一
setNodes(getNodes()+1);
}
}
/**
* 1.先查找到需要删除的key
* 2.如果没有就返回
* 3.找到后从底向上开始删除
* @param key 要删除的节点的key
*/
public boolean DeleteSkipNode(int key){
SkipNode sn = FindSkipNode(key);
if(sn.getKey()!=key)
return false;
else{
while(sn != null){
NoLeftAndRight(sn);
sn = sn.getUp();
System.out.println("开始删除上层节点");
}
//节点数减一
setNodes(getNodes()-1);
return true;
}
}
public int getSkiplevel() {
return skiplevel;
}
public void setSkiplevel(int skiplevel) {
this.skiplevel = skiplevel;
}
public int getMaxint() {
return maxint;
}
public void setMaxint(int maxint) {
this.maxint = maxint;
}
public int getMinint() {
return minint;
}
public void setMinint(int minint) {
this.minint = minint;
}
public SkipNode getHead() {
return head;
}
public void setHead(SkipNode head) {
this.head = head;
}
public SkipNode getTail() {
return tail;
}
public void setTail(SkipNode tail) {
this.tail = tail;
}
public Random getRandom() {
return random;
}
public void setRandom(Random random) {
this.random = random;
}
public double getIsup() {
return isup;
}
public void setIsup(double isup) {
this.isup = isup;
}
public int getNodes() {
return nodes;
}
public void setNodes(int nodes) {
this.nodes = nodes;
}
}
class SkipNode{
//左节点
private SkipNode left = null;
//右结点
private SkipNode right = null;
//上节点
private SkipNode up = null;
//下节点
private SkipNode down = null;
//key值
private int key = 0;
//value值
private String value = null;
public SkipNode(int key,String value){
this.key = key;
this.value = value;
}
public SkipNode getLeft() {
return left;
}
public void setLeft(SkipNode left) {
this.left = left;
}
public SkipNode getRight() {
return right;
}
public void setRight(SkipNode right) {
this.right = right;
}
public SkipNode getUp() {
return up;
}
public void setUp(SkipNode up) {
this.up = up;
}
public SkipNode getDown() {
return down;
}
public void setDown(SkipNode down) {
this.down = down;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "SkipNode{" +
"value=" + value +
", key='" + key + '\'' +
'}';
}
}
class runstart{
public static void main(String[] args) {
SkipListTest list=new SkipListTest();
System.out.println(list);
list.AddSkipNode(2, "yan");
list.AddSkipNode(1, "co");
list.AddSkipNode(3, "feng");
list.AddSkipNode(1, "cao");//测试同一个key值
list.AddSkipNode(4, "曹");
list.AddSkipNode(6, "丰");
list.AddSkipNode(5, "艳");
System.out.println(list);
StringBuilder stringBuilder = new StringBuilder();
System.out.println("当前的跳表的层数为 "+list.getSkiplevel());
System.out.println("当前跳表的元素个数为 "+list.getNodes());
boolean b = list.DeleteSkipNode(1);
if(b){
SkipNode head = list.getHead();
while (head.getDown()!=null)
head = head.getDown();
if(head.getRight().getKey()!=list.getTail().getKey()){
head = head.getRight();
}
System.out.println("当前的跳表的层数为 "+list.getSkiplevel());
System.out.println("当前跳表的元素个数为 "+list.getNodes());
System.out.println("删除成功");
stringBuilder.delete(0,stringBuilder.length());
while(head.getRight().getKey()!=list.getTail().getKey()){
stringBuilder.append(head.toString());
stringBuilder.append("\n");
head = head.getRight();
}
System.out.println(stringBuilder.toString());
}
}
}
效果:
笔试.SkipListTest@74a14482
************查找,当前查找的key为 2
当前的节点 SkipNode{value=yan, key=‘2’}
需要升层
需要建立一个新的层次
找到上层节点,开始构建层次,当前的层次为 1
构建完成,当前的节点的层次为 2
需要升层
需要建立一个新的层次
找到上层节点,开始构建层次,当前的层次为 2
构建完成,当前的节点的层次为 3
************查找,当前查找的key为 1
向下走SkipNode{value=null, key=’-2147483648’}
向下走SkipNode{value=null, key=’-2147483648’}
当前的节点 SkipNode{value=co, key=‘1’}
需要升层
找到上层节点,开始构建层次,当前的层次为 1
构建完成,当前的节点的层次为 2
需要升层
找到上层节点,开始构建层次,当前的层次为 2
构建完成,当前的节点的层次为 3
************查找,当前查找的key为 3
向右走SkipNode{value=null, key=‘1’}
向右走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=yan, key=‘2’}
当前的节点 SkipNode{value=feng, key=‘3’}
************查找,当前查找的key为 1
向右走SkipNode{value=null, key=‘1’}
向下走SkipNode{value=null, key=‘1’}
向下走SkipNode{value=co, key=‘1’}
************查找,当前查找的key为 4
向右走SkipNode{value=null, key=‘1’}
向右走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=yan, key=‘2’}
向右走SkipNode{value=feng, key=‘3’}
当前的节点 SkipNode{value=曹, key=‘4’}
************查找,当前查找的key为 6
向右走SkipNode{value=null, key=‘1’}
向右走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=yan, key=‘2’}
向右走SkipNode{value=feng, key=‘3’}
向右走SkipNode{value=曹, key=‘4’}
当前的节点 SkipNode{value=丰, key=‘6’}
需要升层
向左走,找到最靠近的多层节点 SkipNode{value=feng, key=‘3’}
向左走,找到最靠近的多层节点 SkipNode{value=yan, key=‘2’}
找到上层节点,开始构建层次,当前的层次为 1
构建完成,当前的节点的层次为 2
需要升层
找到上层节点,开始构建层次,当前的层次为 2
构建完成,当前的节点的层次为 3
************查找,当前查找的key为 5
向右走SkipNode{value=null, key=‘1’}
向右走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=null, key=‘2’}
向下走SkipNode{value=yan, key=‘2’}
向右走SkipNode{value=feng, key=‘3’}
向右走SkipNode{value=曹, key=‘4’}
当前的节点 SkipNode{value=艳, key=‘5’}
需要升层
向左走,找到最靠近的多层节点 SkipNode{value=feng, key=‘3’}
向左走,找到最靠近的多层节点 SkipNode{value=yan, key=‘2’}
找到上层节点,开始构建层次,当前的层次为 1
构建完成,当前的节点的层次为 2
笔试.SkipListTest@74a14482
当前的跳表的层数为 3
当前跳表的元素个数为 6
************查找,当前查找的key为 1
向右走SkipNode{value=null, key=‘1’}
向下走SkipNode{value=null, key=‘1’}
向下走SkipNode{value=cao, key=‘1’}
SkipNode{value=cao, key=‘1’} 已删除
开始删除上层节点
SkipNode{value=null, key=‘1’} 已删除
开始删除上层节点
SkipNode{value=null, key=‘1’} 已删除
开始删除上层节点
当前的跳表的层数为 3
当前跳表的元素个数为 5
删除成功
SkipNode{value=yan, key=‘2’}
SkipNode{value=feng, key=‘3’}
SkipNode{value=曹, key=‘4’}
SkipNode{value=艳, key=‘5’}