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 解析html之BeautifulSoup
Jul 07 Python
Python中的ceil()方法使用教程
May 14 Python
flask使用session保存登录状态及拦截未登录请求代码
Jan 19 Python
Python入门学习指南分享
Apr 11 Python
python复制文件到指定目录的实例
Apr 27 Python
python解释器spython使用及原理解析
Aug 24 Python
Python命令行参数解析工具 docopt 安装和应用过程详解
Sep 26 Python
python给指定csv表格中的联系人群发邮件(带附件的邮件)
Dec 31 Python
python 解压、复制、删除 文件的实例代码
Feb 26 Python
python GUI库图形界面开发之PyQt5单行文本框控件QLineEdit详细使用方法与实例
Feb 27 Python
python实现人机五子棋
Mar 25 Python
详解Pytorch显存动态分配规律探索
Nov 17 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下将图片以二进制存入mysql数据库中并显示的实现代码
2010/05/27 PHP
ThinkPHP5分页paginate代码实例解析
2020/11/10 PHP
不错的asp中显示新闻的功能
2006/10/13 Javascript
javascript 常用方法总结
2009/06/03 Javascript
jquery向上向下取整适合分页查询
2014/09/06 Javascript
仿百度换肤功能的简单实例代码
2016/07/11 Javascript
JavaScript代码里的判断小结
2016/08/22 Javascript
详解vue父子模版嵌套案例
2017/03/04 Javascript
H5上传本地图片并预览功能
2017/05/08 Javascript
vue里的data要用return返回的原因浅析
2019/05/28 Javascript
解决vue组件props传值对象获取不到的问题
2019/06/06 Javascript
node.js使用stream模块实现自定义流示例
2020/02/13 Javascript
Vue Router的手写实现方法实现
2020/03/02 Javascript
vue 实现动态路由的方法
2020/07/06 Javascript
修改NPM全局模式的默认安装路径的方法
2020/12/15 Javascript
Python开发实例分享bt种子爬虫程序和种子解析
2014/05/21 Python
零基础写python爬虫之神器正则表达式
2014/11/06 Python
python 默认参数问题的陷阱
2016/02/29 Python
python numpy之np.random的随机数函数使用介绍
2019/10/06 Python
PyTorch和Keras计算模型参数的例子
2020/01/02 Python
TensorFlow Autodiff自动微分详解
2020/07/06 Python
使用Python将xmind脑图转成excel用例的实现代码(一)
2020/10/12 Python
Python中BeautifulSoup通过查找Id获取元素信息
2020/12/07 Python
基于Python的接口自动化unittest测试框架和ddt数据驱动详解
2021/01/27 Python
x-ua-compatible content=”IE=7, IE=9″意思理解
2013/07/22 HTML / CSS
俄罗斯韩国化妆品网上商店:Cosmasi.ru
2019/10/31 全球购物
中间件分为哪几类
2012/03/14 面试题
质检员的岗位职责
2013/11/15 职场文书
干部培训自我鉴定
2014/01/22 职场文书
上课说话检讨书大全
2014/01/22 职场文书
电子专业自荐信
2014/07/01 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
2014年车间工作总结
2014/11/21 职场文书
琅琊山导游词
2015/02/05 职场文书
ORACLE查看当前账号的相关信息
2021/06/18 Oracle
使用CSS实现黑白格背景效果
2022/06/01 HTML / CSS