热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基础版跳跃表实现(golang)

基础版跳跃表实现(golang)-跳跃表入门跳跃表这个东西,一直在听说,但从未手动实现过,所以理解的也不是很透彻。最近闲来无事,用golang实现了一个基础版本,加深一下理解。跳跃

跳跃表入门

跳跃表这个东西,一直在听说,但从未手动实现过,所以理解的也不是很透彻。最近闲来无事,用golang实现了一个基础版本,加深一下理解。

跳跃表的逻辑结构如下:

这里不解释基础原理了,网上大把的资料,总结几点加深理解:

  • 跳跃表的底层还是链表,而且是有序链表,在构造跳跃表的时候就必须保证数据有序;
  • 跳跃表用的是空间换时间的思想;
  • 有点类似有序数组的二分查找;
  • 跳表的查询,插入和删除操作的期望时间复杂度都为 O(logN);

代码实现

跳跃表的实现并不固定,可以有很多不同的版本,我这里仅实现了一个基础版本,并没有各种优化操作。

基础结构:

// 单个节点
type SkipNode struct {
    Val   int
    Level int
    Nexts []*SkipNode
}

// 跳跃表
type SkipList struct {
    Head *SkipNode
    //Tail     *SkipNode
    MaxLevel int
}

源码:

package main

import (
    "errors"
    "fmt"
    "math/rand"
    "time"
)

// 单个节点
type SkipNode struct {
    Val   int
    Level int
    Nexts []*SkipNode
}

// 跳跃表
type SkipList struct {
    Head *SkipNode
    //Tail     *SkipNode
    MaxLevel int
}

// 初始化
func (obj *SkipList) Init(maxLevel int) {
    obj.MaxLevel = maxLevel
    head := new(SkipNode)
    head.Level = 1
    head.Val = -99999
    head.Nexts = make([]*SkipNode, 1, maxLevel)
    obj.Head = head
}

// 获取新节点的最大层数
func (obj *SkipList) GetNodeLevel() int {
    level := 1
    for rand.Intn(2) == 1 {
        level++
        if obj.MaxLevel <= level {
            break
        }
    }
    return level
}

// 插入节点
func (obj *SkipList) insert(val int) error {
    preNodes := make([]*SkipNode, obj.Head.Level, obj.Head.Level)
    currNode := obj.Head
    // 查找定位位置
    for i := obj.Head.Level - 1; i >= 0; i-- {
        for currNode.Nexts[i] != nil && currNode.Nexts[i].Val = 0; i-- {
        for currNode.Nexts[i] != nil && currNode.Nexts[i].Val = 0; i-- {
        for currNode.Nexts[i] != nil && currNode.Nexts[i].Val = 0; i-- {
        fmt.Printf("    skip list level %d: ", i)
        tmpNode := node.Nexts[i]
        for tmpNode != nil {
            fmt.Printf("%d->", tmpNode.Val)
            tmpNode = tmpNode.Nexts[i]
        }
        fmt.Println("\b\b  ")
    }
}

// 构造
func (obj *SkipList) build() {
    for i := 1; i <70; i += 2 {
        obj.insert(i)
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())

    skipObj := SkipList{}
    skipObj.Init(10)
    skipObj.build()
    skipObj.printf()

    err := skipObj.insert(3)
    if err != nil {
        fmt.Printf("insert 3 failed, %s\n", err.Error())
    }
    res := skipObj.find(37)
    if res == nil {
        fmt.Printf("not found 37\n")
    } else {
        fmt.Printf("found 37, %+v\n", res)
    }

    skipObj.del(37)
    skipObj.del(33)
    skipObj.del(4)
    skipObj.printf()

    res = skipObj.find(37)
    if res == nil {
        fmt.Printf("not found 37\n")
    } else {
        fmt.Printf("found 37, %+v\n", res)
    }
}

运行结果如下:


推荐阅读
  • Go 快速入门指南命令行参数
    命令行参数个数调用os包即可。获取参数个数,遍历参数packagemainimport(fmtos)funcmain(){fmt.Printf(Numberofargsi ... [详细]
  • Go冒泡排序练习
    package main要求:随机生成5个元素的数组,并使用冒泡排序对其排序  从小到大思路分析:随机数用mathrand生成为了更好 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • golang 解析磁力链为 torrent 相关的信息
    其实通过http请求已经获得了种子的信息了,但是传播存储种子好像是违法的,所以就存储些描述信息吧。之前python跑的太慢了。这个go并发不知道写的有没有问题?!packag ... [详细]
  • 看到平台银行对接方案写的demo确实还不错记个笔记互相学习学习packageapiimport(cryptotlsnetnethttpstringssynct ... [详细]
  • 集成第三方库,自检测读取配置文件。文件读取,结构体定义,接口实现,错误返回,库解析,适合新同学练手。思路文件读取获取字节流文件类型分析,确定解析api集成第三方解析api管理器定义 ... [详细]
  • 小编给大家分享一下Golang端口复用测试的实现方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有 ... [详细]
  • 在Kubernetes上部署JupyterHub的步骤和实验依赖
    本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 七、Golang之切片(slice)-由于数组的长度是固定的,所以有很多的局限性,所以今天讲切片,切片是一个拥有相同类型且长度可变的有序集合,切片和数组两种不同的数据类型,它是基于 ... [详细]
author-avatar
跟-着感觉走
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有