返回顶部
首页 > 资讯 > 后端开发 > Python >Python 列表与链表的区别详解
  • 149
分享到

Python 列表与链表的区别详解

2024-04-02 19:04:59 149人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录python 列表和链表的区别列表的实现机制链表链表与列表的差异Python 列表和链表的区别 python 中的 list 并不是我们传统意义上的列表,传统列表——通常也叫作链

Python 列表和链表的区别

python 中的 list 并不是我们传统意义上的列表,传统列表——通常也叫作链表(linked list)是由一系列节点来实现的,其中每个节点都持有一个指向下一节点的引用。


class node:
	def __init__(self, value, next=None):	
		self.value = value		
		self.next = next

接下来,我们就可以将所有的节点构造成一个列表了:


>>> L = Node("a", Node("b", Node("c", Node("d"))))
>>> L.next.next.value
'c'

这是一个所谓的单向链表,双向链表的各节点中还需要持有一个指向前一个节点的引用

但 python 中的 list 则与此有所不同,它不是由若干个独立的节点相互引用而成的,而是一整块单一连续的内存区块,我们通常称之为“数组”(array),这直接导致了它与链表之间的一些重要区别。

例如如果我们要按既定的索引值对某一元素进行直接访问的话,显然使用数组会更有效率。因为,在数组中,我们通常可以直接计算出目标元素在内存中的位置,并对其进行直接访问。而对于链表来说,我们必须从头开始遍历整个链表。

但是具体到 insert 操作上,情况又会有所不同。对于链表而言,只要知道了要在哪里执行 insert 操作,其操作成本是非常低的,无论该列表中有多少元素,其操作时间大致上是相同的。而数组就不一样了,它每次执行 insert 操作都需要移动插入点右边的所有元素,甚至在必要的时候,我们可能还需要将这些列表元素整体搬到一个更大的数组中去。

也正因如此,append 操作通常会采取一种被称为动态数组或‘向量'的指定解决方案,其主要想法是将内存分配的过大一些,并且等到其溢出时,在线性时间内再次重新分配内存。但这样做似乎会使 append 变得跟 insert一样糟糕。其实不然,因为尽管这两种情况都可能会迫使我们去搬动大量的元素,但主要不同点在于,对于 append 操作,发生这样的可能性要小得多。事实上,如果我们能确保每次所搬入的数组都大过原数组一定的比例(例如大20%甚至100%),那么该操作的平均成本(或者说得更确切一些,将这些搬运开销均摊到每次 append 操作中去)通常是常数!

数组数据是连续的,一般需要预先设定数据长度,不能适应数据动态的增减,当数据增加是可能超过预设值,需要要重新分配内存,当数据减少时,预先申请的内存未使用,造成内存浪费。链表的数据因为是随机存储的,所以链表可以动态的分配内存,适应长度的动态变化

1.数组的元素是存放在栈中的,链表的元素在堆中
2.读取操作:数组时间复杂度为O(1),链表为O(n)
3.插入或删除操作:数据时间复杂度为O(n),链表为O(1)

列表
关于列表的存储:

列表开辟的内存空间是一块连续的内存,把这个内存等分成几份(单位是字节),他是连续存储的。
如果一个列表长度已满,再append添加元素的话,会在内存中重新开辟一个2倍的内存空间以存储新元素,原列表内存会被清除。

列表与链表复杂度:


按元素值查找:
     按顺序查找,复杂度是一样的。
     按二分查找,链表没法查找.
按下标查找:
     列表是O( 1 )
     链表是O(n)
在某元素后插入:
     列表是O(n)
     链表是O( 1 )
删除某元素:
     列表是O(n)
     链表是O( 1 )

链表------->列表相对应的数据结构
链表是一种线性数据结构(与树形结构相对),不是进行连续存储的。
链表中每一个元素都是一个对象,每个对象称为一个节点,包含有数据域key和执行下一个节点的指针next。通过各个节点之间的相互连接,最终串联成一个链表。
1、存储的过程中,需要先创建节点,然后进行定义。


# 节点定义:
class  Node( object ):     
   def  __init__( self ,item):
	     self .item  =  item  # 数据域
	     self . next  =  None  # 指针域
 
n1  =  Node( 1 )
n2  =  Node( 2 )
n3  =  Node( 3 )
 
n1. next  =  n2
n2. next  =  n3
# 通过 n1 找到n3的值
print (n1. next . next .item)

只保留头结点,执行第一个位置,剩下的都是next去指定。

2、链表遍历:(头节点的变动)

在这里插入图片描述


# 节点定义:
class  Node( object ):     
   def  __init__( self ,item):
	     self .item  =  item  # 数据域
	     self . next  =  None  # 指针域
 
n1  =  Node( 1 )
n2  =  Node( 2 )
n3  =  Node( 3 )
 
n1. next  =  n2
n2. next  =  n3
# 通过 n1 找到n3的值
print (n1. next . next .item)

3、链表节点的插入和删除操作(非常方便,时间复杂度低)

插入:

在这里插入图片描述


p  =  Node( 5 )  # 要插入的值
curNode  =  Node( 1 )  # 标志位
# 顺序不能乱,否则就找不到原链表中的下一个值
p. next  =  curNode. next  # 指定插入值之后的值为标志位之后的值
curNode. next  =  p   # 然后再把原先的链next指向改成插入的值

删除:

在这里插入图片描述


curNode 代表当前值
p  =  curNode. next  # 表示要删除的数
curNode. next  =  p. next  # 重新指定建立链表
del  p 删除数

4、建立链表(单链表)

在这里插入图片描述

1)头插法:是在head头节点的位置后插入数;得到的链表与原先的列表顺序是相反的。

在这里插入图片描述


def  createLinkListF(li):
  l  =  Node()  # 始终指向头节点
   for  num  in  li:
     s  =  Node(num)
     s. next  =  l. next
     l. next  =  s
   return  l

2)尾插法:在链表的尾巴上插入。相当于是追加,必须时刻记住尾巴在哪儿

在这里插入图片描述


def  createLinkListR(li):
  l  =  Node()
  r  =  l  # r指向尾节点
   for  num  in  li:
     s  =  Node(num):
     r. next  =  s
     r  =  s  # 重新指定尾节点

双链表
双链表中每个节点有两个指针:一个指向后面节点,一个指向前面节点。

在这里插入图片描述

1、节点定义:


class  Node( object ):
   def  __init__( self ,item = None ):
     self .item  =  item    # 记录当前值
     self . next  =  None    # 记录下一个值
     self .prior  =  None   # 记录前置的一个值

2、双链表节点的插入和删除

在这里插入图片描述


curNode  =  Node( 1 )  # 取一数据作为标志位

1)插入:


p  =  Node( 2 )  # 要插入的数
p. next  =  curNode. next  # 指定插入数的next 是 当前数的next
curNode. next .prior  =  p  # 指定插入数的下一个数的 前置数为当前的数值
p.prior  =  curNode  # 插入数的前置数为 标志位
curNode. next  =  p  # 指定,标志位的next数是当前要插入的数

2)删除:


p  =  curNode. next  # 标志位的下一个数,要删除的数
curNode. next  =  p. next  # 将next指向下一个数
p. next .prior  =  curNode # 将要删除数的下一个数的前置数改为标志位
del  p  # 删除当前数

3、建立双链表


尾插法:
def  createLinkListR(li):
  l  =  Node()
  r  =  l
   for  num  in  li:
     s  =  Node(num)
     r. next  =  s
     s.prior  =  r
     r  =  s
   return  l,r
 

单链表逆置

在这里插入图片描述

循环反转单链表。在循环的方法中,使用pre指向前一个节点,cur指向当前节点,每次把cur->next指向pre即可。


# 创建节点 
class  Node( object ):
     
     def  __init__( self ,item = None , next = None ):
         self .item  =  item  # 数据域
         self . next  =  next  # 指针域 
 
# 循环逆置方法
def  revLinkList(link):
     
     if  link  is  None  or  link. next  is  None :
         return  link
         
     pre  =  link  # 记录当前节点的值
     cur  =  link. next  # 记录下一节点的值
     pre. next  =  None  # 先将当前节点的next指向定为None
     
     while  cur:  # 链表中一直有值
         tmp  =  cur. next  # 获取cur的下一个值,临时赋值给tmp
         cur. next  =  pre  # 将cur值指向pre
         pre  =  cur  # 重新指定
         cur  =  tmp
     
     return  pre  # 把当前值返回
 
#应用
link  =  Node( 1 , Node( 2 , Node( 3 , Node( 4 , Node( 5 , Node( 6 , Node( 7 , Node( 8 , Node( 9 )))))))))
r  =  revLinkList(link):   # 链表逆置之后,得到的head值
while  r:
     print ( "{0}---->" . fORMat (r.item))  # 输出逆置后的当前值
     r  =  r. next  # 获取下一个,重新赋给r,然后交给上边输出

列表的实现机制

Python 标准类型 list 就是一种元素个数可变的线性表,可以加入和删除元素,并在各种操作中维持已有元素的顺序(即保序),而且还具有以下行为特征:


基于下标(位置)的高效元素访问和更新,时间复杂度应该是O(1);为满足该特征,应该采用顺序表技术,表中元素保存在一块连续的存储区中。
允许任意加入元素,而且在不断加入元素的过程中,表对象的标识(函数id得到的值)不变。为满足该特征,就必须能更换元素存储区,并且为保证更换存储区时 list 对象的标识 id 不变,只能采用分离式实现技术。

在 Python 的官方实现中,list 就是一种采用分离式技术实现的动态顺序表。这就是为什么用 list.append(x) (或 list.insert(len(list), x),即尾部插入)比在指定位置插入元素效率高的原因。

在 Python 的官方实现中,list 实现采用了如下的策略:在建立空表(或者很小的表)时,系统分配一块能容纳 8 个元素的存储区;在执行插入操作(insert 或 append)时,如果元素存储区满就换一块 4 倍大的存储区。但如果此时的表已经很大(目前的阀值为50000),则改变策略,采用加一倍的方法。引入这种改变策略的方式,是为了避免出现过多空闲的存储位置。

列表的实现可以是数组或者链表。列表是一种顺序表,顺序表一般是数组。列表是一个线性表,它允许用户在任何位置进行插入、删除、访问和替换元素。

列表的实现是基于数组或者基于链表结构,当使用列表迭代器的时候,双向链表结构比单链表结构更快。
Python 中的列表英文名是 list,因此很容易与 C 语言中的链表搞混了,因为在 C 语言中大家经常给链表命名为 list。事实上 CPython,也是我们常见的用 C 语言开发的 Python 解释器,Python 语言底层是 C 语言实现的)中的列表根本不是列表。在 CPython 中列表被实现为长度可变的数组。

从细节上看,Python 中的列表是由其他对象的引用组成的连续数组,指向这个数组的指针及其长度被保存在一个列表头结构中。这就意味着,每次添加或删除一个元素时,由引用组成的数组需要改变大小(重新分配)。幸运的是,Python在创建这些数组时采用了指数分配,所以并不是每次操作都要改变数组的大小。但是,也因为这个原因添加或者取出元素是平摊复杂度较低。不幸的是,在普通链表上“代价很小”的其他一些操作在 Python 中计算复杂度相对较高。

总的来说,Python中的列表是一个动态的顺序表,而顺序表大多是由数组实现的。

链表

链表是由许多相同数据类型的数据项按照特定的顺序排列而成的线性表。链表中的数据项在计算机的内存中的位置是不连续且随机的,然而列表是连续的。链表数据的插入和删除是很方便的,但数据的查找效率较低,不能像列表一样随机读取数据。
链表由一个一个的结点构成,每个结点由数据域和“指针域”组成,数据域存储数字,“指针域”指向下一个结点所在的内存地址。(因为Python 中没有指针这一概念的,这里的指针是一种指向)


class Node(object):
    """节点"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None

链表封装的一系列操作:


class SingleLinkList(object):
    """单链表"""
    def __init__(self, node=None):
        self.__head = node

    def is_empty(self):
        """链表是否为空"""
        return self.__head == None

    def length(self):
        """链表长度"""
        # cur游标,用来移动遍历节点
        cur = self.__head
        # count记录数量
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历整个链表"""
        cur = self.__head
        while cur != None:
            print(cur.elem, end=" ")
            cur = cur.next
        print("")

    def add(self, item):
        """链表头部添加元素,头插法"""
        node = Node(item)
        node.next = self.__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 != None:
                cur = cur.next
            cur.next = node

    def insert(self, pos, item):
        """指定位置添加元素
        :param  pos 从0开始
        """
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            pre = self.__head
            count = 0
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 当循环退出后,pre指向pos-1位置
            node = Node(item)
            node.next = pre.next
            pre.next = node

    def remove(self, item):
        """删除节点"""
        cur = self.__head
        pre = None
        while cur != None:
            if cur.elem == item:
                # 先判断此结点是否是头节点
                # 头节点
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next

    def search(self, item):
        """查找节点是否存在"""
        cur = self.__head
        while cur != None:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        return False

链表与列表的差异

Python 中的 list(列表)并不是传统意义上的列表,传统的意义上的列表就是链表,不同地方在于链表在数据存储方面更加的自由,其带有指示下一个结点未知的指向,可以随意的存储数据。而列表则只能分配在一段连续的存储空间里,且是作为一个整体,这就大大限制了数据的变更操作,但其在进行一些基础简单的操作时,时间复杂度极低。

list(列表):动态的顺序表
链表:存储地址分散的,需要“指针”指向的线性表

链表插入删除效率极高,达到O(1)。对于不需要搜索但变动频繁且无法预知数量上限的数据,比如内存池、操作系统的进程管理、网络通信协议栈的 trunk 管理等。甚至就连很多脚本语言都有内置的链表、字典等基础数据结构支持。

列表是一个线性的集合,它允许用户在任何位置插入、删除、访问和替换元素。
列表实现是基于数组或基于链表结构的。当使用列表迭代器的时候,双链表结构比单链表结构更快。
有序的列表是元素总是按照升序或者降序排列的元素。

实现细节
python中的列表的英文名是list,因此很容易和其它语言(c++, Java等)标准库中常见的链表混淆。事实上CPython的列表根本不是列表(可能换成英文理解起来容易些:python中的list不是list)。在CPython中,列表被实现为长度可变的数组。

可参考《Python高级编程(第2版)》

从细节上看,Python中的列表是由对其它对象的引用组成的连续数组。指向这个数组的指针及其长度被保存在一个列表头结构中。这意味着,每次添加或删除一个元素时,由引用组成的数组需要该标大小(重新分配)。幸运的是,Python在创建这些数组时采用了指数分配,所以并不是每次操作都需要改变数组的大小。但是,也因为这个原因添加或取出元素的平摊复杂度较低。

不幸的是,在普通链表上“代价很小”的其它一些操作在Python中计算复杂度相对过高。

利用 list.insert(i,item) 方法在任意位置插入一个元素——复杂度O(N)
利用 list.pop(i) 或 list.remove(value) 删除一个元素——复杂度O(N)

列表的算法效率
可以采用时间复杂度来衡量:

index() O(1)
append O(1)
pop() O(1)
pop(i) O(n)
insert(i,item) O(n)
del operator O(n)
iteration O(n)
contains(in) O(n)
get slice[x:y] O(k)
del slice O(n)
set slice O(n+k)
reverse O(n)
concatenate O(k)
sort O(nlogn)
multiply O(nk)

O括号里面的值越大代表效率越低

到此这篇关于Python 列表与链表的区别详解的文章就介绍到这了,更多相关Python 列表与链表区别内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python 列表与链表的区别详解

本文链接: https://lsjlt.com/news/135287.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python 列表与链表的区别详解
    目录python 列表和链表的区别列表的实现机制链表链表与列表的差异python 列表和链表的区别 python 中的 list 并不是我们传统意义上的列表,传统列表——通常也叫作链...
    99+
    2024-04-02
  • python列表与列表算法详解
    目录1. 序列类型定义2. 列表的基础知识2.1 列表定义2.2 列表基本操作总结1. 序列类型定义 序列是具有先后关系的一组元素 序列是一维元素向量,元素类型可以不同 ...
    99+
    2024-04-02
  • python列表与列表算法详解(2)
    目录2. 案例【三酷猫冒泡法排序】3. 案例【三酷猫二分法查找】总结1. 案例【三酷猫列表记账】 操作需求: (1)用列表对象记录三酷猫每天钓鱼的种类和数量 (2)统计三酷猫所钓...
    99+
    2024-04-02
  • python元组与列表的区别是什么
    Python中的元组(tuple)和列表(list)是两种不同的数据结构,它们之间的主要区别在于以下几点: 不可变性:元组是不可...
    99+
    2024-03-15
    python
  • C语言链表与单链表详解
    链表是什么及链表的优势 链表是一种介于数组的另外一种数据结构: 我们知道数组可以存放很多的元素,这些元素都是呈线性排列,也就是一个挨着一个连续存放 但是当元素足够多时,还能继续正常的...
    99+
    2024-04-02
  • python元组与列表有什么区别
    元组和列表在Python中都是用来存储多个值的数据类型,但它们有一些关键的区别:1. 可变性:列表是可变的,意味着可以通过索引来修改...
    99+
    2023-10-11
    python
  • NumPy 与 Python 内置列表计算标准差区别详析
    目录1 什么是 Numpy2 NumPy 数组和 Python 内置计算对比3 函数计算时间装饰器4 标准差计算公式5 总结1 什么是 Numpy NumPy,是 Numerical...
    99+
    2024-04-02
  • python:列表详解
    目录列表list1、列表创建2、列表访问1)一维列表的访问2)二维列表的访问3、修改元素5、del命令6、列表运算1)列表相加2)列表相乘7、列表方法1) index(value[,...
    99+
    2024-04-02
  • Python数据结构与算法之链表,无序链表详解
    目录我们首先来构造节点。节点(Node)的类构建完毕后,接下来我们开始构建整个链表(LinkList)的类。那么我们还需要一个方法来判断链表头的指向。接下来我们构建链表节点的添加方法...
    99+
    2024-04-02
  • Python线性表种的单链表详解
    目录1. 线性表简介2. 数组3. 单向链表设计链表的实现链表与顺序表的对比1. 线性表简介 线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列。线性表的特征是在一个序列中...
    99+
    2024-04-02
  • Python中列表和元组的区别
    Python中列表和元组的区别 数据结构定义符号是否可变存储空间能否作为字典的键列表(list)[        ]可变,动态内存较大不能元组(tuple)(        )不可变,静态内存较小能         在Python中...
    99+
    2023-09-07
    python 数据结构
  • Python中列表和元组的使用方法和区别详解
    一、二者区别 列表: 1.可以增加列表内容 append 2.可以统计某个列表段在整个列表中出现的次数 count 3.可以插入一个字符串,并把整个字符串的每个字母拆分当作一个列表段追加到列表当中 ...
    99+
    2022-06-04
    使用方法 详解 区别
  • Mysql临时表及分区表区别详解
    临时表与内存表 内存表,指的是使用Memory引擎的表,建表语法是create table … engine=memory。这种 表的数据都保存在内存里,系统重启的时候会被清空,但是表结构还在。除...
    99+
    2022-05-26
    Mysql 临时表 分区表
  • python之列表详解
    文章目录 一.创建列表1.基于弱数据类型语言的定义2.通过全局函数list()定义3.创建空列表 二.访问列表的值1.通过下标索引2.通过for循环遍历3.通过while循环遍历 ...
    99+
    2023-10-18
    python 开发语言 后端 列表
  • Python中元组,列表,字典的区别
    Python中,有3种内建的数据结构:列表、元组和字典。 1.列表 list是处理一组有序项目的数据结构,即你可以在一个列表中存储一个序列的项目。列表中的项目。列表中的项目应该包括在方括号中,这样...
    99+
    2022-06-04
    中元 字典 区别
  • Python中的列表、元祖、字典的区别
    定义方法列表可以包含不同类型的对象,可以增减元素,可以跟其他的列表结合或者把一个列表拆分,用[]来定义的eg:aList=[123,'abc',4.56,['inner','list'],7-9j]1.list(str):将str转换成li...
    99+
    2023-01-31
    元祖 字典 区别
  • java中的数组(Array)与列表(ArrayList)的区别
    列表(ArrayList)是对数组(Array)的一个加强,分配数组列表和创建数组的方式如下:分配数组列表:new ArrayList(100);创建数组:new Employee[100];在线视频教程推荐:java课程两者之间的区别:一...
    99+
    2016-08-24
    java入门 java 数组 列表 区别 Array ArrayList
  • Python中列表索引A[:2]与A[:,2]的区别说明
    目录列表索引 A[ : 2 ]与A[ : , 2]区别创建一个列表访问列表中的值A[ : 2 ]与A[ : , 2]的区别python中[::]的含义[:-1][::-1][:,]列...
    99+
    2024-04-02
  • hive内部表和外部表的区别详解
    Hive内部表:默认创建的表是内部表。hive完全管理表(元数据和数据)的声明周期,类似于RDBMS的表。当删除表时,他会删除源数据以及表的元数据。 Hive外部表:外部表的数据不是Hive拥有或者管理的,只管理元数据的...
    99+
    2023-04-26
    hive内部表和外部表区别 hive内部表 hive外部表
  • python列表排序用 sort()和sorted()的区别
    目录1. 是否改变原列表2.参数设置:key 和 reverse3.输入数据类型前言: 内容提要:本文比较了 Python 中用于列表排序的两种函数 sort() 和 sorted(...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作