首页 > 编程语言 >Java开发者的Python快速进修指南:实战之简易跳表

Java开发者的Python快速进修指南:实战之简易跳表

时间:2023-11-28 13:44:06浏览次数:36  
标签:node Java temp Python value next 跳表 节点

前言

之前我已经将Python的基本语法与Java进行了比较,相信大家对Python也有了一定的了解。我不会选择去写一些无用的业务逻辑来加强对Python的理解。相反,我更喜欢通过编写一些数据结构和算法来加深自己对Python编程的理解。学习任何语言都一样。

通过编写数据结构和算法,不仅可以加强我自己的思维能力,还能提高对Python编程语言的熟练程度。在这个过程中,我会不断地优化我的代码,以提高算法的效率和性能。我相信通过这种方式,我能够更好地掌握Python编程,并且在解决实际问题时能够更加灵活地运用Python的特性和语法。

跳表

今天我们来使用Python实现一个简易版本的跳表。所谓跳表就是一种跳跃式的数据结构。

假设你是一位图书馆管理员,你需要在图书馆的书架上找到一本特定的书。如果图书馆只是一个普通的书架,你需要逐本书进行查找,这样会花费很多时间和精力。

然而,如果图书馆采用了跳表这种数据结构,书架上的书被分成了几个层次,每一层都有一个索引,上面标注了每本书的位置信息。当你需要找到一本书时,你可以先查看最高层的索引,快速定位到可能包含该书的区域,然后再在该区域内根据索引逐步查找,直到找到目标书籍。

这样,跳表的索引层就相当于图书馆的书籍分类系统,它提供了一个快速查找的方法。通过索引层,你可以迅速定位到书籍所在的区域,减少了查找的次数和时间。

跳表主要的思想是利用索引的概念。因此,每个节点除了保存下一个链表节点的地址之外,还需要额外存储索引地址,用于指示下一步要跳转的地址。它在有序链表的基础上增加了多层索引,以提高查找效率。

而且这适合于读多写少的场景。在实现过程中,无论是在插入数据完毕后重新建立索引,还是在插入数据的同时重新建立索引,都会导致之前建立的索引丢弃,浪费了大量时间。而且,如果考虑多线程的情况,情况会更糟糕。写这种东西时,通常先实现一个简单版,然后根据各个环节进行优化,逐步改进算法。因此,我们今天先实现一个简单版的跳表。

具体实现

我们先来实现一个简单版的跳表,不动态规定步长。我们可以先定义一个固定的步长,比如2。

为了实现跳表,我们需要定义一个节点的数据结构。这个节点包含以下信息:当前节点的值(value),指向前一个节点的指针(before_node),指向后一个节点的指针(next_node),以及指向索引节点的指针(index_node)。

class SkipNode:

    def __init__(self,value,before_node=None,next_node=None,index_node=None):
        self.value = value
        self.before_node = before_node
        self.next_node = next_node
        self.index_node = index_node
        
head = SkipNode(-1)
tail = SkipNode(-1)

为了方便操作,我先生成了两个特殊节点,一个是头节点,另一个是尾节点。头节点作为跳表的起始点,尾节点作为跳表的结束点。

数据插入

在跳表中插入节点时,我们按照从小到大的升序进行排序。插入节点时,无需维护索引节点。一旦完成插入操作,我们需要重新规划索引节点,以确保跳表的性能优化。

def insert_node(node):
    if head.next_node is None:
        head.next_node = node
        node.next_node = tail
        node.before_node = head
        tail.before_node = node
        return
    temp = head.next_node
    # 当遍历到尾节点时,需要直接插入
    while temp.next_node is not None or temp == tail:
        if temp.value > node.value or temp == tail:
            before = temp.before_node
            before.next_node = node
            temp.before_node = node
            node.before_node = before
            node.next_node = temp
            break
        temp = temp.next_node
    re_index()

重建索引

为了重新规划索引,我们可以先将之前已经规划好的索引全部删除。然后,我们可以使用步长为2的方式重新规划索引。

def re_index():
    step = 2
    # 用来建立索引的节点
    index_temp = head.next_node
    # 用来遍历的节点
    temp = head.next_node
    while temp.next_node is not None:
        temp.index_node = None
        if step == 0:
            step = 2
            index_temp.index_node = temp
            index_temp = temp
        temp = temp.next_node
        step -= 1

查询节点

查询:从头节点开始查询,根据节点的值与目标值进行比较。如果节点的值小于目标值,则向右移动到下一个节点或者索引节点继续比较。如果节点的值等于目标值,则找到了目标节点,返回结果。如果节点的值大于目标值,则则说明目标节点不存在。

def search_node(value):
    temp = head.next_node
    step = 0
    while temp.next_node is not None:
        step += 1
        if value == temp.value:
            print(f"该值已找到,经历了{step}次查询")
            return
        elif value < temp.value:
            print(f"该值在列表不存在,经历了{step}次查询")
            return
        if temp.index_node is not None and value > temp.index_node.value:
            temp = temp.index_node
        else:
            temp = temp.next_node
    print(f"该值在列表不存在,经历了{step}次查询")

遍历

为了方便查看,我特意编写了一个用于遍历和查看当前数据的功能,以便更清楚地了解数据的结构和内容。

def print_node():
    my_list = []
    temp = head.next_node
    while temp.next_node is not None:
        if temp.index_node is not None:
            my_dict = {"current_value": temp.value, "index_value": temp.index_node.value}
        else:
            my_dict = {"current_value": temp.value, "index_value": None}  # 设置一个默认值为None
        my_list.append(my_dict)
        temp = temp.next_node
    for item in my_list:
        print(item)

查看结果

所有代码已经准备完毕,现在我们可以在另一个文件中运行并查看跳表的内容和数据。让我们快速进行操作一下。

import skipList
import random


for i in range(0,10):
    random_number = random.randint(1, 100)
    temp = skipList.SkipNode(random_number)
    skipList.insert_node(temp)

skipList.print_node()

skipList.search_node(89)

以下是程序的运行结果。为了方便查看,我特意打印了索引节点的值,以告诉你要跳到哪一个节点。

image

总结

通过实现一个简易版本的跳表,可以加深了对Python编程的理解。跳表是一种跳跃式的数据结构,通过索引层提供快速查找的能力,提高了查找的效率。在实现跳表的过程中,会更加熟悉了Python的语法和特性,并且可以更加灵活地运用它来解决实际问题。

标签:node,Java,temp,Python,value,next,跳表,节点
From: https://www.cnblogs.com/guoxiaoyu/p/17856392.html

相关文章

  • python正则表达式
    一、问题:对返回的非json结果如何拿到里面想要的那部分内容 二、回答可以通过正则表达式获取:findall.*匹配0~n个内容.+起码匹配1个()分组如对xml结果的数据进行处理,代码如下所示:1deftestPostXml():2'''3xml数据4:return:5'''......
  • python正则贪婪匹配
    一、问题:我想对a234ba444bab这个字符串,提取出来234和444两组数据,要怎么匹配 二、回答采用re.findall('a(.+?)b','a234ba444bab')说明:这里.+代表起码匹配一个,如果用.*的话可能匹配出来空即0~n个这里?代表最小匹配即非贪婪匹配,上面的意思是当看到b就结束,不加?则看到b不会立马结......
  • python如何获取工程的根目录以及文件路径?
    一、问题:python如何获取工程的根目录以及文件路径? 二、回答1.思路为在工程根目录下新建一个py文件,这样获取到的路径就是工程的根路径2.基于此即可封装获取文件路径的方法代码如下所示:1importos23defgetFileDir(*args):4'''5获取工程中文件路径,......
  • 【Python】注解的使用
    注解是给人看的,编译器并不会检查类型。如果不写注解,编辑器不会有代码补全功能,因为它不知道你是什么类型。有了注解之后,编辑器就知道你是什么类型,就会进行代码提示。1、函数注解语法如下:deffunc_name(arg1:Type,arg2:Type)->ReturnType:pass2、变量注解语法如下:va......
  • python Matplotlib库:根据excel生成各种柱状图
    我将向大家介绍如何使用Python和一些常见的库来根据Excel数据生成十种不同类型的图表。通过多维度的可视化,我们可以更全面地了解数据中的模式、趋势和关系。无论您是数据分析师、市场营销人员还是研究人员,这些图表将帮助您挖掘数据中更多的信息。1.准备工作 首先,我们需要安装一些......
  • python中全局变量和局部变量作用域理解
    一:描述python中全局变量和局部变量作用域理解 二:回答1. 局部变量不能修改全局变量局部变量只作用于方法内,无法修改全局变量1#全局变量city2city="上海"34defmod_city():5#局部变量city6city="深圳"7print(city)89......
  • python中面向对象有什么特点
    一:问题python中面向对象有什么特点? 二:回答python同其他面向对象语言一样,有3个特征:封装、继承、重写 简单理解就是:封装:把一系列属性和操作封装到一个方法里面,这样想要实现某种效果,只需要简单的调个方法名字就行了,不需要在写一遍所有的操作内容继承:简单理解就是拼爹,父辈拥......
  • python面向对象方法与属性
    一:描述python中面向对象方法与属性:①静态变量:实例变量、类变量②静态方法:@staticmethod,相当于被放到类里的函数③私有属性和方法:以两个下划线开头,如__secret()④魔术方法:以两个下划线开头且以两个下划线结尾,如__secret__()⑤受保护的属性和方法:以一个下划线开头,如_secret()⑥特殊......
  • python对象嵌套
    一、描述python对象嵌套,即包含的关系。python实现:班级(名字,多个学生)、学生(学号,姓名) 二、详细说明要想实现班级里含有多个学生的这种关系,可以在班级类里嵌套学生类,将学生类信息以列表的形式存储保存即可1classStudent:2def__init__(self,s_no,s_name):3......
  • python虚拟环境
    一:问题我下了别人的工程,工程环境是用全局的python环境好,还是弄一个虚拟环境好一点,为什么? 二:回答用虚拟环境好,因为能够实现环境分离,你能在虚拟环境中安装项目特定的依赖项,而不会影响全局Python环境。从而实现不同项目维护不同的依赖关系,而不必担心版本冲突或相互影响。具体操......