数据结构与算法之链表-python实现(简单好用)

【Python爬虫(2)】从0到1:Python爬虫必备的数据结构与算法基础 数据结构和算法基础在 Python 爬虫开发中扮演着举足轻重的角色。列表、元组、字典等基础数据结构为数据的存储和操作提供了基本手段,栈、队列、链表等进阶数据结构则能帮助我们解决更复杂的问题,提高爬虫的效率和性能。冒泡排序、选择排序、插入排序等简单排序算法,不仅是算法学习的基础,在实际的数据处理中也有其应用场景。通过对这些数据结构和算法的学习,我们能够更好地理解爬虫程序的运行机制,优化爬虫的实现。 阅读详情

前言

链表:一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接

链表的数据结构:
在这里插入图片描述
而对于其中每一个节点:
在这里插入图片描述
每一个节点有两个域,左边叫值域,用于存放用户数据,右边叫指针域,一般是存储着到下一个节点的指针

head节点:
头节点,特殊的一个节点,永远指向第一个节点
tail节点:
尾节点,也是特殊的一个节点,永远指向最后一个节点。tail.next = None

而由abcd四个节点组成了一个链表,每一个节点都有data和next,尾节点的next指向None

链表中的元素都会有两个属性,一个是元素的值,另一个是指针,指针标记了下一个元素的地址,每一个数据都会保存下一个数据的内存的地址,通过此地址可以找到下一个数据,任意位置插入和删除元素效率较高,时间复杂度为O(1)

需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度为O(N)

优点:

  1. 任意位置插入和删除元素速度快,时间复杂度为O(1)
  2. 内存利用率高,不会浪费内存

缺点:
随机访问效率低 时间复杂度为O(N)

python的单链表实现

单链表也就是刚才所讲的链表结构,也是最基础的链表

class Node():
    def __init__(self, value):
    	# 该节点的值
        self._value = value
        # 指向下一个节点
        self._next = None

class LinkedList():
    def __init__(self, head=None):
    	# 头节点
        self._head = head

    # 检查该链表是否为空,为空则返回 True,否则返回 False
    def isEmpty(self):
        return self._head == None

    # 返回链表节点的数量
    def length(self):
        if self.isEmpty():
            return 0
        else:
            cur = self._head
            count = 1
            while cur._next != None:
                count += 1
                cur = cur._next
            return count

    # 遍历所有节点
    def travel(self):
        if self.isEmpty():
            print("The linkedlist is empty!")
        else:
            cur = self._head
            values = []
            while cur != None:
                values.append(cur._value)
                cur = cur._next
            print(values)

    # 头部添加节点
    def add(self, value):
        node = Node(value)
        node._next = self._head
        self._head = node

    # 尾部添加节点
    def append(self, value):
        node = Node(value)
        if self.isEmpty():
            self._head = node
        else:
            cur = self._head
            while cur._next != None:
                cur = cur._next
            cur._next = node

    # 插入节点
    def insert(self, pos, value):
        if pos <= 0:
            self.add(value)
        elif pos > (self.length()-1):
            self.append(value)
        else:
            node = Node(value)
            cur = self._head
            index = 0
            while index < (pos-1):
                index += 1
                cur = cur._next
            node._next = cur._next
            cur._next = node

    # 删除等于某个值的全部节点
    def remove(self, value):
        pre = None
        cur = self._head
        while cur != None:
            if cur._value == value:
                if pre == None:
                    self._head = self._head._next
                    cur = self._head
                    continue
                else:
                    pre._next = cur._next
                    cur = cur._next
                    continue
            pre, cur = cur, cur._next

    # 删除某个索引对应的节点
    def delete(self, index):
        if index < 0 or index > (self.length()-1):
            print("The input index is out of range!")
        elif index == 0:
            self._head = self._head._next
        else:
            count = 1
            pre, cur = self._head, self._head._next
            while count<index:
                count += 1
                pre, cur = cur, cur._next
            pre._next = cur._next

    # 根据值返回节点的索引
    def searchbyvalue(self, value):
        count = 0
        cur = self._head
        index = []
        while cur != None:
            if cur._value == value:
                index.append(count)
            count += 1
            cur = cur._next
        if not index:
            return False
        else:
            return index

    # 根据索引返回节点的值
    def searchbyindex(self, index):
        count = 0
        cur = self._head
        if index < 0 or index > (self.length()-1):
            print("The input index is out of range")
        else:
            while count < index:
                count += 1
                cur = cur._next
            return cur._value
双向链表

在这里插入图片描述
双向链表双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。 所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点

python的双向链表实现

class Node(object):
    """双向链表的结点"""

    def __init__(self, item):
        # item存放数据元素
        self.item = item
        # next 指向下一个节点的标识
        self.next = None
        # prev 指向上一结点
        self.prev = None

class BilateralLinkList(object):
    """双向链表"""

    def __init__(self):
        self._head = None
	
	# 判断链表是否为空
    def is_empty(self):
        return self._head is None
        
	# 链表长度
    def length(self):
        # 初始指针指向head
        cur = self._head
        count = 0
        # 指针指向None 表示到达尾部
        while cur is not None:
            count += 1
            # 指针下移
            cur = cur.next
        return count

	# 遍历链表
    def items(self):
        # 获取head指针
        cur = self._head
        # 循环遍历
        while cur is not None:
            # 返回生成器
            yield cur.item
            # 指针下移
            cur = cur.next

	# 向链表头部添加元素
    def add(self, item):
        node = Node(item)
        if self.is_empty():
            # 头部结点指针修改为新结点
            self._head = node
        else:
            # 新结点指针指向原头部结点
            node.next = self._head
            # 原头部 prev 指向 新结点
            self._head.prev = node
            # head 指向新结点
            self._head = node

	# 尾部添加元素
    def append(self, item):
        node = Node(item)
        if self.is_empty():  # 链表无元素
            # 头部结点指针修改为新结点
            self._head = node
        else:  # 链表有元素
            # 移动到尾部
            cur = self._head
            while cur.next is not None:
                cur = cur.next
            # 新结点上一级指针指向旧尾部
            node.prev = cur
            # 旧尾部指向新结点
            cur.next = node
            
	# 指定位置插入元素
    def insert(self, index, item):
        if index <= 0:
            self.add(item)
        elif index > self.length() - 1:
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            for i in range(index):
                cur = cur.next
            # 新结点的向下指针指向当前结点
            node.next = cur
            # 新结点的向上指针指向当前结点的上一结点
            node.prev = cur.prev
            # 当前上一结点的向下指针指向node
            cur.prev.next = node
            # 当前结点的向上指针指向新结点
            cur.prev = node
	
	# 删除结点
    def remove(self, item):
        if self.is_empty():
            return
        cur = self._head
        # 删除元素在第一个结点
        if cur.item == item:
            # 只有一个元素
            if cur.next is None:
                self._head = None
                return True
            else:
                # head 指向下一结点
                self._head = cur.next
                # 下一结点的向上指针指向None
                cur.next.prev = None
                return True
        # 移动指针查找元素
        while cur.next is not None:
            if cur.item == item:
                # 上一结点向下指针指向下一结点
                cur.prev.next = cur.next
                # 下一结点向上指针指向上一结点
                cur.next.prev = cur.prev
                return True
            cur = cur.next
        # 删除元素在最后一个
        if cur.item == item:
            # 上一结点向下指针指向None
            cur.prev.next = None
            return True
	
	# 查找元素是否存在
    def find(self, item):
        return item in self.items()
循环链表

在单链表基础上,将头尾链接,组成循环

python的循环链表实现


class Node(object):
    """节点"""
    def __init__(self, item):
        self.item = item
        self.next = None
 
 
class SinCycLinkedlist(object):
    """单向循环链表"""
    def __init__(self):
        self.__head = None
 
  	# 判断链表是否为空
    def is_empty(self):
        return self.__head == None
 
  	# 返回链表的长度
    def length(self):
        # 如果链表为空,返回长度0
        if self.is_empty():
            return 0
        count = 1
        cur = self.__head
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count
 
  	# 遍历链表
    def travel(self):
        if self.is_empty():
            return
        cur = self.__head
        print cur.item,
        while cur.next != self.__head:
            cur = cur.next
            print cur.item,
        print ""
 
  	# 头部添加节点
    def add(self, item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = self.__head
        else:
            #添加的节点指向_head
            node.next = self.__head
            # 移到链表尾部,将尾部节点的next指向node
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            cur.next = node
            #_head指向添加node的
            self.__head = node
 
  	# 尾部添加节点
    def append(self, item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = self.__head
        else:
            # 移到链表尾部
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            # 将尾节点指向node
            cur.next = node
            # 将node指向头节点_head
            node.next = self.__head
 
  	# 在指定位置添加节点
    def insert(self, pos, item):
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self.__head
            count = 0
            # 移动到指定位置的前一个位置
            while count < (pos-1):
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node
 
  	# 删除一个节点
    def remove(self, item):
        # 若链表为空,则直接返回
        if self.is_empty():
            return
        # 将cur指向头节点
        cur = self.__head
        pre = None
        while cur.next != self.__head:
            if cur.item == item:
                # 先判断此结点是否是头节点
                if cur == self.__head:
                    # 头节点的情况
                    # 找尾节点
                    rear = self.__head
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:
                    # 中间节点
                    pre.next = cur.next
                return
            else:
                pre = cur
                cur = cur.next
        # 退出循环,cur指向尾节点
        if cur.item == item:
            if cur == self.__head:
                # 链表只有一个节点
                self.__head = None
            else:
                # pre.next = cur.next
                pre.next = self.__head
 
 	# 查找节点是否存在
    def search(self, item):
        if self.is_empty():
            return False
        cur = self.__head
        if cur.item == item:
            return True
        while cur.next != self.__head:
            cur = cur.next
            if cur.item == item:
                return True
        return False
双向循环链表

顾名思义,双向循环链表就是将双向链表的头尾相连,构成循环

python的双向循环链表实现

# 1.节点构造
class Node(object):
    def __init__(self, elem):
        self.elem = elem  
        self.next = None  
        self.prev = None  

class DoubleCircleLinkedList(object):
    # 2.成员构造
    def __init__(self, node=None):
        self._head = node
        
    # 3.返回大小
    def length(self):
        if self.is_empty():
            return 0
        else:
            cur = self._head.next
            n = 1
            while cur != self._head:
                cur = cur.next
                n += 1
            return n

    # 4.判空
    def is_empty(self):
        return self._head is None

    # 5.增
    def addFirst(self, elem):
        node = Node(elem)
        if self.is_empty():  # 链表为空
            node.next = node
            node.prev = node
            self._head = node
        else:
            node.next = self._head
            node.prev = self._head.prev
            self._head.prev.next = node
            self._head.prev = node
            self._head = node

    def addLast(self, elem):
        if self.is_empty():
            self.addFirst(elem)
        else:
            node = Node(elem)
            cur = self._head.next
            while cur.next != self._head:
                cur = cur.next
            cur.next = node
            node.prev = cur
            node.next = self._head
            self._head.prev = node

    def add(self, pos, elem):
        if pos <= 0:
            self.addFirst(elem)
        elif pos >= self.length():
            self.addLast(elem)
        else:
            cur = self._head.next
            n = 1
            while cur.next != self._head:
                if n == pos:
                    break
                cur = cur.next
                n += 1
            node = Node(elem)
            node.prev = cur.prev
            cur.prev.next = node
            node.next = cur
            cur.prev = node
            
    # 6.删
    def remove(self, elem):
        if self.is_empty():
            return
        else:
            if self._head.elem == elem:
                if self.length == 1:
                    self._head = Node
                else:
                    self._head.prev.next = self._head.next
                    self._head.next.prev = self._head.prev
                    self._head = self._head.next
            cur = self._head.next
            while cur != self._head:
                if cur.elem == elem:
                    cur.prev.next = cur.next
                    cur.next.prev = cur.prev
                cur = cur.next
                
    # 7.查
    def travel(self):
        cur = self._head
        while cur.next != self._head:
            print(cur.elem, end=' ')
            cur = cur.next
        print(cur.elem)
        
    def search(self, elem):
        if self.is_empty():
            return False
        else:
            cur = self._head.next
            if self._head.elem == elem:
                return True
            else:
                while cur != self._head:
                    if cur.elem == elem:
                        return True
                    else:
                        cur = cur.next
                return False
静态链表

使用静态链表存储数据,需要预先申请足够大的一整块内存空间,也就是说,静态链表存储数据元素的个数从其创建的那一刻就已经确定,后期无法更改。

不仅如此,静态链表是在固定大小的存储空间内随机存储各个数据元素,这就造成了静态链表中需要使用另一条链表(通常称为"备用链表")来记录空间存储空间的位置,以便后期分配给新添加元素使用。

这意味着,如果你选择使用静态链表存储数据,你需要通过操控两条链表,一条是存储数据,另一条是记录空闲空间的位置。

而使用动态链表存储数据,不需要预先申请内存空间,而是在需要的时候才向内存申请。也就是说,动态链表存储数据元素的个数是不限的,想存多少就存多少。

同时,使用动态链表的整个过程,你也只需操控一条存储数据的链表。当表中添加或删除数据元素时,你只需要通过 malloc 或 free 函数来申请或释放空间即可,实现起来比较简单。

python的静态链表实现

class Node:
    def __init__(self, next, val=None):
        self.val = val  # 值
        self.next = next  # 游标。最后一个元素的游标必须是 0


class SLinkList:
    # 分配线性表长度、定义线性表
    def __init__(self, size=7):
        self.size = size
        self.link = [Node((i + 1) % self.size) for i in range(self.size)]

    # 线性表清空
    def clearSLL(self):
        self.__init__()

    # 线性表是否为空
    def isEmpty(self):
        return False if self.link[self.size - 1].next else True

    # 查找空位置
    def findEmpty(self):
        ind = self.size
        for i in range(1, self.size - 1):
            if self.link[i].val is None:
                ind = i
                break
        return ind

    # 指定位置插入元素
    def insert(self, ind, ele):
        sua = -1
        # 前一个元素
        pre = self.size - 1
        # 插入元素的位置(第一个空位置)
        insertLoc = self.link[0].next
        # 条件判断
        if ind < 1 or ind >= pre or insertLoc >= self.size:
            return 0
        # 第一个元素的索引
        for i in range(1, self.size - 1):
            index = self.link[pre].next
            if i == ind:
                self.link[pre].next = insertLoc
                # 元素插入
                self.link[insertLoc].val = ele
                self.link[insertLoc].next = index
                # 首位元素
                self.link[0].next = self.findEmpty()
                sua = 1
                break
            if self.link[index].val is None:
                break
            pre = index
        return sua

    # 查找线性表某位置的元素
    def getByIndex(self, ind):
        if ind < 1 or ind >= self.size - 1:
            return -1

        index = self.link[self.size - 1].next
        if index == 0:
            return -1
        for i in range(1, ind):
            index = self.link[index].next

        return self.link[index].val

    # 查找线性表的元素所在位置
    def locateElement(self, ele):
        index = self.link[self.size - 1].next
        ind = -1
        if index == 0:
            return ind
        for i in range(1, self.size - 1):
            if self.link[index].val == ele:
                ind = i
                break
            if self.link[index].val is None:
                break
            index = self.link[index].next
        return ind

    # 删除线性表指定位置的元素
    def deleteElement(self, ind):
        sua = -1
        # 前一个索引
        pre = self.size - 1
        for i in range(1, self.size - 1):
            index = self.link[pre].next
            # 当前位置是个空位置
            if self.link[index].val is None:
                break
            # 已经遍历到第i个位置
            if i == ind:
                self.link[pre].next = self.link[index].next
                self.link[index].val = None
                # 删除元素的游标指向备用链表
                self.link[index].next = self.link[0].next
                # 首位元素
                self.link[0].next = index
                sua = 1
                break
            pre = index
        return sua

    # 按照线性表排序线性表遍历
    def travelLink(self):
        print("*" * 50)
        index = self.link[self.size - 1].next
        while self.link[index].val:
            print(
                f"value = {self.link[index].val} next = {self.link[index].next}"
            )
            index = self.link[index].next
        print("*" * 50)

    # 按照索引遍历
    def traversingByIndex(self):
        print("*" * 50)
        for i in range(self.size):
            print(
                f"index = {i}, value = {self.link[i].val} next = {self.link[i].next}"
            )
        print("*" * 50)
AI量化交易工作台Vibe-Trading:用自然语言驱动策略回测与多智能体研究 量化交易通过数学模型和计算机程序执行投资决策,其核心在于将市场规律转化为可验证的策略。传统量化开发涉及数据获取、策略编写、回测验证等复杂工程,对非编程背景的从业者构成较高门槛。随着大语言模型技术的发展,自然语言交互正成为降低技术使用难度的关键。Vibe-Trading项目正是这一趋势的实践,它将金融工程任务封装为可调用的工具与技能,允许用户通过自然语言指令直接驱动策略回测、因子研究和投资组合分析。其技术价值在于构建了一个模块化的AI Agent框架,通过ReAct推理框架协调多个专项技能,并创新性地引入多智 阅读详情

相关推荐

mysql 计算不同胜率的活跃玩家的次日,3日,7日留存率

它根据每天的日期(logymd)和最高段位(max_rank)、胜率段落(win_rate_segment)进行分组,并计算总玩家人数(total_players)、第二天的留存人数(next_day_players)、第三天的留存人数(day3_players)和第七天的留存人数(day7_players)。注意:不是新手留存,是段位活跃玩家留存;最终的结果则是将留存数据进行展示,按照日期(date)、最高段位(rank_level)、胜率段落(win_rate_segment)进行排序。

weixin_42698221的博客 1836

Demo2Reward:用人类演示动态优化VLM奖励模型提示

多模态大模型(VLM)的奖励建模正面临核心瓶颈——静态提示导致语义鸿沟与泛化失效。其本质是将人类判断标准固化为不可更新的文本模板,使奖励信号脱离真实任务意图。Demo2Reward提出范式级改进:以结构化人类演示为元信号,驱动提示权重连续优化,实现从‘结果打分’到‘过程理解’的跃迁。该方法不修改VLM主干,却显著提升RLHF收敛效率与OOD鲁棒性,在医疗、工业质检等场景验证了跨任务迁移与热修复能力。它重新定义了提示工程的技术价值:不是前端微调,而是奖励系统的认知校准基础设施。

weixin_34302798的博客 408

RV1126 ISP开发实战:从Tuner调试到IQ文件解析

本文详细介绍了RV1126 ISP开发的完整流程,从Tuner调试到IQ文件解析,涵盖了环境搭建、工具使用、参数配置及性能优化等关键环节。通过实战案例和避坑指南,帮助开发者快速掌握Rockchip芯片的ISP开发技巧,提升图像处理质量。

weixin_29195615的博客 572

STM32F401RET6寄存器手册阅读标记

对于时钟树配置,可参考STM32CubeMX中的时钟树配置,STM32CubeMX将基础配置图像化,较为简单。RCC_CR寄存器的HSIRDY位为只读位,当读取值为1时,表示HSI振荡器准备就绪,当HSION位被设置时,HSIRDY会自动设置为低电平。//问题标记:USART配置寄存器信息是如何与USART1/2/3建立联系的(为什么不是三个分别配置)查阅寄存器手册可知,需要配置时钟的模块有:USART1,IO port A。(2)TX配置方法(寄存器手册512页)(4)配置寄存器(寄存器手册548页)

m0_72615170的博客 1468

DO-178C详解:机载软件开发、验证与适航标准指南

DO-178C将软件划分为五个等级(A到E),这些等级是基于失效状态对航空器安全的影响而定。

qq_41854911的博客 2849

在RV1126上实现人脸识别----MobileFaceNet转成rknn模型

目录 1.模型下载 2 转成rknn模型并推理 3 查看网络模型 1.模型下载 首先下载MobileFaceNet的模型,github下载地址为:https://github.com/sirius-ai/MobileFaceNet_TF/tree/master/arch/pretrained_model/ 2 转成rknn模型并推理 import numpy as np import cv2 from rknn.api import RKNN if __name__ == '__..

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 3526

把静态前端托管进 SAP BTP:HTML5 Application Deployer 与企业级内容部署全攻略

本文介绍了在SAP BTP Cloud Foundry环境中使用HTML5 Application Repository托管前端静态资源的工程化实践。通过HTML5 Application Deployer工具,结合MTA描述、路由配置和服务实例,实现前后端解耦和标准化部署。文章详细阐述了目录结构、关键配置文件、MTA编排以及构建部署流程,并针对大体积前端资源提供了GACD和异步上传两种解决方案。最后说明了如何与AppRouter协同工作,使部署内容可供终端用户访问。这套方法使前端更新无需重启后端,支持团队

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 155

LabVIEW实现HTTP通信

本节简要介绍HTTP通信的基础知识,并以工业物联网平台TLINK中云端设备的数据发布设计为例,阐述互联网环境下HTTP客户端应用程序设计的基本方法。重点讲解工业物联网平台TLINK中HTTP设备的创建、通信数据帧的构造与测试。

不脱发的程序猿 1545

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: python第三方库-urllib(简单好用)
下一篇: 全部博文链接汇总(不断更新)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值