跳表(java代码实现)

看《数据结构与算法之美》练手写了一下跳表
一开始自己只看了思路,写了一晚上还是有两个小bug
所以第二次写参考了一下别的博客

跳表的java实现

算是写出了个能用的吧(应该)

import java.util.*;

/**
 * @author 20级三班刘宇阳
 * @create 2022/2/2
 */

/**
 * 跳表类
 * @param <T> 泛型
 */
public class SkipList<T>{
    /**
     * 跳表结点内部类
     */
    private class Node{
        //前后上下
        private Node next,pre,up,down;
        private Integer key;
        private T value;
        public Node(int key,T value){
            this.key = key;
            this.value = value;
        }

        public Node getNext() { return next; }

        public void setNext(Node next) { this.next = next; }

        public Node getPre() { return pre; }

        public void setPre(Node pre) { this.pre = pre; }

        public Node getUp() { return up; }

        public void setUp(Node up) { this.up = up; }

        public Node getDown() { return down; }

        public void setDown(Node down) { this.down = down; }

        public int getKey() { return key; }

        public void setKey(int key) { this.key = key; }

        public T getValue() { return value; }

        public void setValue(T value) { this.value = value; }

        @Override
        public String toString() {
            return "Node{" +
                    "key=" + key +
                    ", value='" + value + '\'' +
                    '}';
        }
    }

    //使tail有哨兵作用
    private static final int MAX_KEY = Integer.MAX_VALUE;
    //使head有哨兵作用
    private static final int MIN_KEY = Integer.MIN_VALUE;
    //掷骰子
    private static final Random random = new Random();
    //当前跳表内索引层的最大值
    private int currentMaxLevel = 1;
    //头尾结点,两个哨兵
    private Node head,tail;
    //当前跳表内存储了多少个元素(不包括索引结点)
    private int size = 0;

    public SkipList(){ clear(); }

    /**
     * 重置当前的状态,也可用于初始化
     */
    public void clear(){
        //重置层数
        setCurrentMaxLevel(1);
        //设置头尾
        setHead(new Node(MIN_KEY,null));
        setTail(new Node(MAX_KEY,null));
        //连接头尾
        horizontalLink(getHead(),getTail());
    }

    //掷骰子,1即可以向上,否则不行
    private boolean canUpgrade(){
        return getRandom().nextInt(2)==1;
    }

    /**
     * 竖直方向连接两个结点(作为内部其他方法的工具方法)
     * @param down 下方结点
     * @param up 上方结点
     */
    private void verticalLink(Node down,Node up){
        down.setUp(up);
        up.setDown(down);
    }


    /**
     * 水平方向连接两个结点(作为内部其他方法的工具方法)
     * @param pre 前面的结点
     * @param next 后面结点
     */
    private void horizontalLink(Node pre,Node next){
        pre.setNext(next);
        next.setPre(pre);
    }

    /**
     * 插入结点操作(作为内部其他方法的工具方法)
     * @param pre 插入位置的前一个结点
     * @param cur 要插入的结点
     */
    private void insertAfter(Node pre,Node cur){
        Node next = pre.getNext();
        horizontalLink(pre,cur);
        horizontalLink(cur,next);
    }

    /**
     * 寻找结点
     * @param key
     * @return 如果存在key,则返回对应node,否则返回小于该key值的最后一个结点
     */
    private Node findNode(int key){
        Node node = getHead();
        while(true){
            while (node.getNext().getKey()<=key&&node.getNext().getKey() != MAX_KEY){
                node = node.getNext();
            }
            if(node.getDown() != null){
                node = node.getDown();
            }else {
                break;
            }
        }
        return node;
    }

    /**
     *  1.先查找到需要插入的地方
     *  2.执行插入
     *  3.判定需不需要进行升层
     * @param key    插入节点的key
     * @param value  插入节点的value
     */
    public void put(int key,T value){
        Node node = findNode(key);
        if(node.getKey() == key){
            node.setValue(value);
        }else{
            //1.创建出节点
            Node cur = new Node(key,value);
            //2.插入节点
            insertAfter(node,cur);
            //用作判定是否超过现有的层数
            int currentLevel = 1;
            //3.判定需不需要进行升层,使用抛硬币的方法,1/2的概率
            boolean canUpGradeFlag=canUpgrade();
            Node pre=node;
            while(canUpGradeFlag){
                //1.currentLevel
                if(currentLevel>=getCurrentMaxLevel()){
                    //2.此时先提高层数
                    setCurrentMaxLevel(getCurrentMaxLevel()+1);
                    //3.创建出两端
                    Node newHead = new Node(MIN_KEY,null);
                    Node newTail = new Node(MAX_KEY,null);
                    //4.水平上的连接
                    horizontalLink(newHead,newTail);
                    //5.上下的承接
                    verticalLink(getHead(),newHead);
                    verticalLink(getTail(),newTail);
                    //6.赋值
                    setHead(newHead);
                    setTail(newTail);
                }
                //7.找到上方该插入位置的前后结点
                while(pre.getUp() == null){
                    pre = pre.getPre();
                }
                //得到上一层要插入位置的前一个结点
                pre = pre.getUp();
                 //8.新建关于当前插入节点的上层节点
                Node up = new Node(key, null);
                //插入节点
                insertAfter(pre,up);
                //层次关系
                verticalLink(cur,up);
                //迭代更新下方结点,方便垂直连接该插入结点的各索引层
                cur = up;
                //更新flag
                canUpGradeFlag = canUpgrade();
                //当前结点的索引层数加一
                currentLevel++;
            }
            //节点数加一
            setSize(getSize()+1);
        }
    }

    /**
     *  1.先查找到需要删除的key
     *  2.如果没有就返回
     *  3.找到后从底向上开始删除
     * @param key 要删除的节点的key
     */
    public boolean remove(int key){
        Node node = findNode(key);
        if(node.getKey()!=key){ return false; }
        else{
            int currentLevel=0;
            while(node != null){
                Node pre = node.getPre();
                Node next = node.getNext();
                //水平方向断开该结点
                horizontalLink(pre,next);
                //当该层除头尾结点外无结点时,说明该层包括以上层都可以舍弃了,进行一个新的更
                //结点的销毁是GC的事,我们只需要断开连接
                if(pre.getNext().getKey() == MAX_KEY && pre.getKey() == MIN_KEY&&getCurrentMaxLevel()>1){
                    setHead(pre.getDown());
                    setTail(next.getDown());
                    getHead().setUp(null);
                    getTail().setUp(null);
                    //记得拿当前的层数更新跳表层数
                    setCurrentMaxLevel(currentLevel);
                    break;
                }
                node = node.getUp();
                currentLevel++;
            }
            //节点数减一
            setSize(getSize()-1);
            return true;
        }
    }

    public T get(int key){
        Node node=findNode(key);
        if(node.getKey()!=key){
            return null;
        }
        return node.getValue();
    }

    /**
     * 范围查询(左闭右闭)
     * @param start 起始key
     * @param end   终止key
     * @return 内容为<key,value>的链表集合
     */
    public List<Map<Integer,T>> getRangeByKey(int start, int end){
        Node node=findNode(start);
        if(node.getKey()!=start){ node=node.getNext(); }
        List<Map<Integer,T>> list=new LinkedList<>();
        while(node.key<=end){
            Map<Integer,T> map=new HashMap<>();
            map.put(node.getKey(),node.getValue());
            list.add(map);
            node=node.getNext();
        }
        return list;
    }

    /**
     * 自己写的很乐色
     * @return
     */
    @Override
    public String toString(){
        StringBuilder sb=new StringBuilder();
        sb.append("SkipList:{\n");
        sb.append("\tlevel:"+this.currentMaxLevel+",\n");
        sb.append("\t{\n");
        Node tempHead=getHead();
        while(tempHead!=null){
            sb.append("\t\t"+tempHead.getKey()+"\t");
            Node tempNode=tempHead.getNext();
            while(tempNode.getKey()!=getTail().getKey()){
                sb.append(tempNode.getKey()+"\t");
                tempNode=tempNode.getNext();
            }
            sb.append(tempNode.key+"\n");
            tempHead=tempHead.getDown();
        }
        sb.append("\t}\n");
        sb.append("}\n");
        return sb.toString();
    }

    public int getCurrentMaxLevel() { return currentMaxLevel; }

    private void setCurrentMaxLevel(int currentMaxLevel) { this.currentMaxLevel = currentMaxLevel; }

    private Node getHead() { return head; }

    private void setHead(Node head) { this.head = head; }

    private Node getTail() { return tail; }

    private void setTail(Node tail) { this.tail = tail; }

    private Random getRandom() { return random; }

    private int getSize() { return size; }

    private void setSize(int size) { this.size = size; }
}


class Demo{
    public static void main(String[] args) {
        SkipList<Integer> skipList=new SkipList<>();
        skipList.put(1,1);
        skipList.put(2,2);
        skipList.put(2,3);
        System.out.println(skipList);
        skipList.remove(2);
        System.out.println(skipList);
        skipList.put(3,3);
        skipList.put(0,0);
        skipList.put(2,2);
        System.out.println(skipList.getRangeByKey(0,5));
    }
}

写了两晚上算是整出来了,好爽
当个ylg推荐一下最近喜欢的说唱捏
丁真进军说唱圈,《Zood》空降B榜
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: package mainimport ( "fmt" )// 节点 type node struct { key int value string left *node right *node }// 跳表 type skipList struct { head *node length int }func main() { sl := &skipList{ head: &node{ key: 0, value: "", left: nil, right: nil, }, length: 0, } // 插入 sl.insert(1, "a") sl.insert(2, "b") sl.insert(3, "c") sl.insert(4, "d") sl.insert(5, "e") fmt.Println(sl) // 查找 fmt.Println(sl.find(4)) // 删除 sl.delete(4) fmt.Println(sl) }// 插入 func (sl *skipList) insert(key int, value string) { // 创建新节点 newNode := &node{ key: key, value: value, left: nil, right: nil, } // 定义当前节点为头结点 cur := sl.head // 寻找位置插入 for cur.right != nil { if cur.right.key > key { break } cur = cur.right } // 插入 newNode.right = cur.right cur.right = newNode newNode.left = cur // 增加长度 sl.length++ }// 查找 func (sl *skipList) find(key int) string { cur := sl.head for cur.right != nil { if cur.right.key > key { break } cur = cur.right } if cur.key == key { return cur.value } return "" }// 删除 func (sl *skipList) delete(key int) { cur := sl.head for cur.right != nil { if cur.right.key > key { break } cur = cur.right } if cur.right != nil && cur.right.key == key { cur.right = cur.right.right if cur.right != nil { cur.right.left = cur } sl.length-- } } ### 回答2: 跳表是一种快速查找的数据结构,类似于有序链表加上多级索引的结构。下面是用Go语言实现跳表代码: ```go package main import ( "fmt" "math" ) type SkipListNode struct { value int next []*SkipListNode } type SkipList struct { head *SkipListNode level int length int } func NewSkipListNode(value, level int) *SkipListNode { return &SkipListNode{ value: value, next: make([]*SkipListNode, level), } } func NewSkipList() *SkipList { // 创建头节点,值为负无穷 head := NewSkipListNode(math.MinInt32, 32) return &SkipList{ head: head, level: 0, length: 0, } } func (list *SkipList) Insert(value int) { update := make([]*SkipListNode, list.level+1) node := list.head // 查找插入位置 for i := list.level; i >= 0; i-- { for node.next[i] != nil && node.next[i].value < value { node = node.next[i] } update[i] = node } // 随机生成索引层数,使其符合跳表的概率分布 level := 0 for (level < 32-1) && (level < list.level+1) && (rand.Int()%2 == 0) { level++ } // 创建新节点 insertNode := NewSkipListNode(value, level+1) // 更新索引 for i := 0; i <= level; i++ { insertNode.next[i] = update[i].next[i] update[i].next[i] = insertNode } // 更新跳表的层数 if level > list.level { list.level = level } list.length++ } func (list *SkipList) Search(target int) bool { node := list.head // 从最高层开始搜索 for i := list.level; i >= 0; i-- { for node.next[i] != nil && node.next[i].value <= target { if node.next[i].value == target { return true } node = node.next[i] } } return false } func main() { list := NewSkipList() list.Insert(3) list.Insert(5) list.Insert(8) list.Insert(10) list.Insert(12) fmt.Println(list.Search(8)) // true fmt.Println(list.Search(6)) // false } ``` 以上是一个简单的跳表实现,包括插入和搜索两个基本操作。通过随机生成索引层数,可以实现快速的查找。 ### 回答3: 下面是使用Go语言实现跳表代码段示例: ```go package main import ( "fmt" "math" "math/rand" ) type Node struct { value int next []*Node } type SkipList struct { head *Node level int } func newNode(value, level int) *Node { return &Node{ value: value, next: make([]*Node, level), } } func newSkipList() *SkipList { return &SkipList{ head: newNode(math.MinInt32, 1), level: 1, } } func (skiplist *SkipList) search(target int) bool { curr := skiplist.head for i := skiplist.level - 1; i >= 0; i-- { for curr.next[i] != nil && curr.next[i].value < target { curr = curr.next[i] } if curr.next[i] != nil && curr.next[i].value == target { return true } } return false } func (skiplist *SkipList) insert(value int) { level := skiplist.randomLevel() newNode := newNode(value, level) update := make([]*Node, level) curr := skiplist.head for i := level - 1; i >= 0; i-- { for curr.next[i] != nil && curr.next[i].value < value { curr = curr.next[i] } update[i] = curr } for i := 0; i < level; i++ { newNode.next[i] = update[i].next[i] update[i].next[i] = newNode } if level > skiplist.level { skiplist.level = level } } func (skiplist *SkipList) erase(value int) { update := make([]*Node, skiplist.level) curr := skiplist.head for i := skiplist.level - 1; i >= 0; i-- { for curr.next[i] != nil && curr.next[i].value < value { curr = curr.next[i] } update[i] = curr } if curr.next[0] != nil && curr.next[0].value == value { for i := skiplist.level - 1; i >= 0; i-- { if update[i].next[i] != nil && update[i].next[i].value == value { update[i].next[i] = update[i].next[i].next[i] } } } } func (skiplist *SkipList) randomLevel() int { level := 1 for rand.Float32() < 0.5 && level < 32 { level++ } return level } func main() { skiplist := newSkipList() skiplist.insert(3) skiplist.insert(6) skiplist.insert(9) skiplist.insert(2) skiplist.insert(5) skiplist.insert(8) fmt.Println(skiplist.search(6)) // 输出: true fmt.Println(skiplist.search(12)) // 输出: false skiplist.erase(6) fmt.Println(skiplist.search(6)) // 输出: false } ``` 此代码实现了一个基本的跳表数据结构,其中SkipList是一个包含了跳表头结点和层数的结构体。可以通过insert方法向跳表中插入元素,通过search方法在跳表中搜索元素,通过erase方法删除跳表中的某个元素。运行main函数可以看到跳表的基本操作结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值