Python单链表原理与实现方法详解


Posted in Python onFebruary 22, 2020

本文实例讲述了Python单链表原理与实现方法。分享给大家供大家参考,具体如下:

Python实现单链表

关于链表

  • 链表(Linked List)是由许多相同数据类型的数据项按照特定顺序排列而成的线性表。
  • 链表中个数据项在计算机内存中的位置是不连续且随机的,数组在内存中是连续的。
  • 链表数据的插入和删除很方便,但查找数据效率低下,不能像数组一样随机读取数据。

单链表的实现

  • 一个单向链表的节点由数据字段和指针组成,指针指向下一个元素所在内存地址

  • 定义一个链表节点类,self.value实例属性表示节点数据字段;self.next表示指针;初始化值为None

  • class Node(object):
      def __init__(self, value=None, next=None):
        self.value = value
        self.next = next
  • 在单链表中第一个节点为头(head)指针节点(即头指针指向的节点为单链表第一个节点,后续简称头指针节点),从头指针节点出发可以遍历整个链表,进行元素查找,插入和删除,非常重要。一般不移动head头指针。

  • 单链表中最后一个节点为尾节点,其指针为None,表示结束。

  • 建立单链表我们首先需要创建头指针节点(引入头指针是为了方便操作单链表,对于头指针节点,只有指针域指向链表第一个节点,不含实际值)

  • class linkedList(object):
      def __init__(self):
        self.head = Node()	# 创建头指针结点
        self.length = 0	# 初始链表长度,头指针节点不计入长度
      def __len__(self):	# 重写特殊方法返回self.length
        return self.length
  • 链表初始化之后,开始定义链表方法

  • 链表头部插入节点:

    • 调用Node()传入待插入的值value创建待插入节点

    • 判断当前链表是否为空链表,链表为空:

      • 插入节点既是链表头指针指向的节点也是尾节点(指向None)
    • 链表不为空:

      • 待插入节点指向原头指针节点,头指针重新指向待插入节点
      • 首先需要将原头指针结点,存放到临时变量中(防止head指针变更时,指针断裂导致数据丢失,链表中指针就是连接的纽带,其中某个纽带断裂(即指针指向其他)则后续数据都将丢失)
      • 将头指针指向新插入节点
      • 新插入节点指针指向原头指针节点
      • 长度+1
    • def head_insert(self, value): # 链表头部插入
          node = Node(value)
          if self.head.next == None:
            self.head.next = node
            node.next = None
          else:
            # 插入元素指针域指向原head元素
            tmp_head = self.head.next # 原头指针节点存储到tmp_head
            self.head.next = node # 新head指针指向node
            node.next = tmp_head # 新插入节点指向原头指针节点
          self.length += 1
  • 链表头部删除节点:

    • 依旧是先判断链表是否为空,为空则返回False

    • 链表不为空时:

      • 头指针指针域(指针域存放下一节点的内存地址,即头指针节点)指向头指针,也就是说链表第一个节点变成了头指针head,由于head不计入链表,所以就相当于删除了第一个节点(有点绕)
      • 同时返回删除的值
    • def head_del(self): # 删除头结点,返回头结点的值
          if self.head.next == None:
            return False
          else:
            # 头指针指针域指向自己
            self.head = self.head.next
            self.length -= 1
            return self.head.value
  • 链表尾部添加节点:

    • 创建待插入节点对象

    • 判断链表是否为空,为空则头指针节点就是待插入节点,也是尾节点

    • 链表不为空:

      • 首先通过while循环(循环条件为节点指针是否为None)找到当前链表的最后一个元素
      • 然后将当前最后一个元素指向待插入节点
      • 长度+1
    • def append(self, value):  # 链表尾部添加结点
          # 创建新插入的结点对象
          node = Node(value)
          if self.length == 0:
            self.head.next = node  # 只有一个节点,指针指向自己
          else:
            curnode = self.head.next  # 变量curnode存放指针
            while curnode.next != None:
              curnode = curnode.next
            curnode.next = node # 当为最后一个节点时,指针指向新插入节点
          self.length += 1
  • 指定位置后面插入节点:

    • 这里方法接受两个位置参数,index插入位置和value插入值

    • 依旧创建新节点对象

    • 判断是否为空

    • 在链表不为空的条件下:

      • 首先定义一个变量表示当前节点,以及一个index索引比较数i
      • 使用while循环,索引比较数i != index时,更新当前节点
      • 找到索引位置节点后,首先让插入节点指向索引位置节点的下一个节点
      • 然后让索引位置节点指向插入节点
      • 链表长度+1
    • def insert(self, index, value):
      	node = Node(value)
        if self.length == 0:
          self.head.next = node
        else:
          i = 0
          cur_node = self.head.next
          while i != index:
            cur_node = cur_node.next
            i += 1
          node.next = cur_node.next
          cur_node.next = node
        self.length += 1
  • 给定值删除该值节点:

    • 删除链表中给定的值我们需要遍历整个链表,因此需要创建一个可迭代对象

    • 定义节点迭代方法

    • def iter_node(self):
        cur_node = self.head.next	#当前节点
        while cur_node.next != None:	# 对除最后一个节点进行可迭代化处理
          yield cur_node
          cur_node = curnode.next
        if cur_node.next == None:	# 对尾节点进行可迭代化处理
          yield cur_node
    • 重写特殊方法?iter?,用来声明这个类是一个迭代器

    • def __iter__(self): # 遍历列表节点
        for node in self.iter_node():
           yield node.value
    • 首先定义一个Flag变量(默认为False),用来表示删除状态

    • 依旧判断链表是否为空

    • 链表不为空时:

      • 设置一个前驱节点(当找到需要删除的节点时,先让前驱节点指向删除节点的后继节点)
      • for循环遍历链表
        • 找到符合条件的值就让前驱节点指向,删除节点的后继节点,然后del删除node,Flag更改为True
        • 没找到符合条件的值,就更新前驱节点,继续遍历
    • def delete_node(self, value):
          Flag = False
          if self.length == 0:
            return False
          else:
            previous_node = self.head  # 初始化前置节点为头结点
            for node in self.iter_node():
              if node.value == value:
                previous_node.next = node.next # 前置节点指针指向当前节点的后继节点
                del node
                self.length -= 1
                Flag = True
              else:
                previous_node = node  # 更新前置节点的值
            return Flag
  • 完整代码:

  • # 定义链表节点类
    class Node(object):
      def __init__(self, value=None, next=None):
        self.value = value # 节点元素
        self.next = next  # 指针
    
    
    # 单链表类
    class LinkedList(object):
      def __init__(self):
        self.head = Node() # 创建头结点
        self.length = 0 # 初始化链表长度
    
      def __len__(self):
        return self.length
    
      def __iter__(self): # 遍历列表节点
        for node in self.iter_node():
          yield node.value
    
      def iter_node(self):
        curnode = self.head.next
        while curnode.next != None:
          yield curnode
          curnode = curnode.next
        if curnode.next == None:
          yield curnode
    
      def head_insert(self, value): # 链表头部插入
        node = Node(value)
        if self.head.next == None:
          self.head.next = node
          node.next = None
        else:
          # 插入元素指针域指向原head元素
          tmp_head = self.head.next # 原头指针节点存储到tmp_head
          self.head.next = node # 新head指针指向node
          node.next = tmp_head # 新插入节点指向原头指针节点
        self.length += 1
    
      def head_del(self): # 删除头结点,返回头结点的值
        if self.head.next == None:
          return False
        else:
          # 头指针指针域指向自己
          self.head = self.head.next
          self.length -= 1
          return self.head.value
    
      def append(self, value):  # 链表尾部添加结点
        # 创建新插入的结点对象
        node = Node(value)
        if self.length == 0:
          self.head.next = node  # 只有一个节点,指针指向自己
        else:
          curnode = self.head.next  # 变量curnode存放指针
          while curnode.next != None:
            curnode = curnode.next
          curnode.next = node # 当为最后一个节点时,指针指向新插入节点
        self.length += 1
    	
      # 这里的insert是指定值后面插入不是指定位置
      def insert(self, index, value):
        node = Node(value)
        if self.length == 0:
          self.head.next = node
          self.length += 1
        else:
          for nd in self.iter_node():
            if nd.value == index:  # 如果nd节点值等于index,则插入到nd后
              tmp_node = nd.next # 将nd的指针存放到中间变量
              nd.next = node # nd节点指向插入节点
              node.next = tmp_node  # 插入节点指向原nd.next节点
              self.length += 1
              return True
          return False
    
      def replace(self, old_value, new_value):
        index = 0
        if self.length == 0:
          return False
        else:
          for node in self.iter_node():
            if node == old_value:
              node.value = new_value
              index += 1
        if index != 0:
          return index # 替换节点数量(存在节点值相同情况)
        else:
          return False  # 替换失败,未找到替换值
    
      def delete_node(self, value):
        Flag = False
        if self.length == 0:
          return False
        else:
          previous_node = self.head  # 初始化前置节点为头结点
          for node in self.iter_node():
            if node.value == value:
              previous_node.next = node.next # 前置节点指针指向当前节点的后继节点
              del node
              self.length -= 1
              Flag = True
            else:
              previous_node = node  # 更新前置节点的值
          return Flag
    
    
    
    # 测试
    l = LinkedList()
    l.append(1)
    l.append(2)
    l.append(7)
    l.append(5)
    l.append(6)
    l.append(7)
    l.head_insert(3)
    print("当前链表长度:%s" %l.length)
    #print("删除头结点为:%d"% l.head_del())
    print("当前链表长度:%s" %l.length)
    i = 1
    #l.delete_node(7)
    for node in l:
      print("第%d个链表节点的值: %d"%(i, node))
      i += 1

    运行结果:

  • 当前链表长度:7
    当前链表长度:7
    第1个链表节点的值: 3
    第2个链表节点的值: 1
    第3个链表节点的值: 2
    第4个链表节点的值: 7
    第5个链表节点的值: 5
    第6个链表节点的值: 6
    第7个链表节点的值: 7

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python去除列表中重复元素的方法
Mar 20 Python
Python的Django框架中的Context使用
Jul 15 Python
python读写json文件的简单实现
Apr 11 Python
python利用dir函数查看类中所有成员函数示例代码
Sep 08 Python
详解python使用递归、尾递归、循环三种方式实现斐波那契数列
Jan 16 Python
python样条插值的实现代码
Dec 17 Python
Python闭包思想与用法浅析
Dec 27 Python
Django实现web端tailf日志文件功能及实例详解
Jul 28 Python
python3实现mysql导出excel的方法
Jul 31 Python
pytorch载入预训练模型后,实现训练指定层
Jan 06 Python
解决TensorFlow模型恢复报错的问题
Feb 06 Python
浅谈keras使用中val_acc和acc值不同步的思考
Jun 18 Python
python函数enumerate,operator和Counter使用技巧实例小结
Feb 22 #Python
python通过文本在一个图中画多条线的实例
Feb 21 #Python
python使用html2text库实现从HTML转markdown的方法详解
Feb 21 #Python
python-sys.stdout作为默认函数参数的实现
Feb 21 #Python
pycharm运行程序时看不到任何结果显示的解决
Feb 21 #Python
Python 安装 virturalenv 虚拟环境的教程详解
Feb 21 #Python
python ffmpeg任意提取视频帧的方法
Feb 21 #Python
You might like
PHP 函数执行效率的小比较
2010/10/17 PHP
php数组函数序列 之shuffle()和array_rand() 随机函数使用介绍
2011/10/29 PHP
PHP 图片水印类代码
2012/08/27 PHP
php操作xml
2013/10/27 PHP
PHP中$_FILES的使用方法及注意事项说明
2014/02/14 PHP
php绘图中显示不出图片的原因及解决
2014/03/05 PHP
php设置页面超时时间解决方法
2015/09/22 PHP
php防止表单重复提交实例讲解
2019/02/11 PHP
javascript实现面向对象类的功能书写技巧
2010/03/07 Javascript
扩展easyui.datagrid,添加数据loading遮罩效果代码
2010/11/02 Javascript
javascript 内存回收机制理解
2011/01/17 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
AngularJS基础 ng-include 指令简单示例
2016/08/01 Javascript
jQuery实现的导航下拉菜单效果示例
2016/09/05 Javascript
使用JQuery选择HTML遍历函数的方法
2016/09/17 Javascript
VueJs路由跳转——vue-router的使用详解
2017/01/10 Javascript
JavaScript实现网页头部进度条刷新
2017/04/16 Javascript
原生JS实现旋转轮播图+文字内容切换效果【附源码】
2018/09/29 Javascript
vue实现分页组件
2020/06/16 Javascript
JS实现电话号码的字母组合算法示例
2019/02/26 Javascript
Layui带搜索的下拉框的使用以及动态数据绑定方法
2019/09/28 Javascript
Python中datetime常用时间处理方法
2015/06/15 Python
Django开发中的日志输出的方法
2018/07/02 Python
python 3.6.5 安装配置方法图文教程
2018/09/18 Python
python修改字典键(key)的方法
2019/08/05 Python
pandas条件组合筛选和按范围筛选的示例代码
2019/08/26 Python
FitFlop美国官网:英国符合人体工学的鞋类品牌
2018/10/05 全球购物
青年志愿者事迹材料
2014/02/07 职场文书
幼儿园毕业家长感言
2014/02/10 职场文书
供货协议书
2014/04/22 职场文书
诉前财产保全担保书
2014/05/20 职场文书
2014年银行客户经理工作总结
2014/11/12 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
狼牙山五壮士观后感
2015/06/09 职场文书
Android中View.post和Handler.post的关系
2022/06/05 Java/Android
win10如何快速切换窗口 win10切换窗口快捷键分享
2022/07/23 数码科技