欢迎这位怪蜀黍来到《数据结构之(5)python实现单链表 - 大码王 - 博客园》

关闭页面特效

介绍

 

 

 

 

为什么需要链表?

对于上部分顺序表的学习,我们了解到在构建顺序表时需要预先知道数据大小来申请连续的存储空间,而在进行扩充的时候又需要进行数据的搬迁,所以使用起来并不是很灵活。

那我们就想,能不能存在一种数据结构是的在数据扩充的时候,在原有的数据完全不变化,扩充一个数据就增加一个,我们需要这样的一个数据结构,那么这样的数据结构怎么存储呢?

比如构造了一组数据Li=[200],然后申请了一个存储空间将200存储下来,然后补充了一个数据400,Li=[200,400],这时候又申请了一个空间用来储存400,现在我们要做的是不利用顺序表的方式进行存储,把他们顺序链接在一起,并且也不考虑我们最终扩充多少的数据,即扩充一个数据就申请一个单元来储存它,比如在扩充一个数据600,数据结构Li=[200,400,600],那么就在申请一个空间来储存600。如下表所示,我们怎么吧这种离散的空间关联在一起呢?
在这里插入图片描述
上表的结构已经没有了连续的概念了,但是我们可以通过找一根线将它们串联起来,这个概念已经在顺序表中的元素外置中引入过,具体的做法是:首先申请一个空间存储元素200,在数据扩充个400以后,在申请一个空间用于存储,然后将200与400之间通过一条线进行连接,使之建立一种关系,同样在扩充600的时候,也会申请一个空间用于存储600,然后通过一条线将400与600进行链接,重复这个过程,就可以扩充任意个数据,当然这里暂时先不用明白这条线是怎么具体链接的,后续会详细讲解。如下表所示
在这里插入图片描述
这样链接好了以后,在想获取数据的时候就可以根据200,沿着这条线往下寻找,就能根据这条线将所有元素串联在一起,而且并不需要预估元素的占用空间是多大(整型数据和char)。这种数据结构就叫做链表。

链表的定义

链表(Linked list)是一种常见的基础数据结构。是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
在这里插入图片描述
即在申请储存单元的时候,对单个的单元进行拓展,不仅保留该数据,还要保留另外的一部分数据,这两部分称为一个整体,叫做节点。其中第一部分保存数据,第二部分保存地址。而为了链接200和400这两个节点,就将第一个节点的链接区储存为400的地址,后面执行相同的步骤,这样就达到了一种线性关系,通过构建这样的一种数据结构来达到这样的链接关系。

单项链表

单项链表也叫单链表,是链表中最简单的一种形式,他的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
在这里插入图片描述
在这里插入图片描述

  1. 表元素elem用来存放具体的数据。
  2. 链接域next用来存放下一个节点的位置(python中的标识)
  3. 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

单链表的操作

下面对该数据结构通过类的方式进行实现,一方面是指数据的保存,一方面是对数据的操作。
具体操作包括:

  1. is_empty():链表是否为空
  2. length():链表长度
  3. travel():遍历链表
  4. add(item):链表头部添加元素
  5. append(item):链表尾部添加元素
  6. insert(pos,item):指定位置添加元素
  7. remove(item):删除节点
  8. delete(self, index):指定位置删除元素
  9. search(self,item):查找指定元素
  10. find(self,index):根据指定位置查找元素
  11. change(self,elem,index):根据指定位置替换值
  12. clear(self):清空链表
  13. sort(self):排序
  14. isExist(self,item):是否存在指定的元素
  15. __init__:初始化节点

单链表实现操作

 

复制代码
# 单链表
# 实现功能
# 声明节点类
class Node(object):
    # 初始化节点
    def __init__(self,elem):
        self.elem=elem
        self.next=None
# 声明链表类
class SingleLinkList(object):
    # 1、初始化置为空
    def __init__(self,node=None):
        self._head=node
    # 2、判断是否为空
    def is_empty(self):
        return self._head==None
    # 3、计算链表长度
    def length(self):
        cur=self._head
        count=0
        while cur != None:
            count=count+1
            cur=cur.next
        return count
    # 4、遍历链表
    def travel(self):
        cur=self._head
        while cur != None:
            print(cur.elem,end=" ")
            cur=cur.next
    # 5、头部添加元素
    def add(self,item):
        node=Node(item)
        node.next=self._head
        self._head=node
    #6、尾部追加元素
    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
    #7、指定位置添加元素
    def insert(self,position,item):
        # 头插法
        if position<0:
            self.add(item)
        # 尾插法
        elif position>(self.length()-1):
            self.append(item)
        else:
            node=Node(item)
            pre=self._head
            count=0
            while count<(position-1):
                pre=pre.next
                count+=1
                node.next=pre.next
                pre.next=node
    # 8、删除指定元素
    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
    # 9、指定位置删除元素
    def delete(self, index):
        # 判空
        lgh=self.length()
        if self.is_empty():
            print('空链表')
            return
        if index < 0 or index > lgh:
            print('索引超过范围')
            return

        if index == 0:
            self._head = self._head.next
        else:
            pre = self._head
            for i in range(lgh):
                if i == index - 1:
                    pre.next = pre.next.next
                    break
                pre = pre.next
        lgh -= 1
        return
    # 10、查找指定的元素
    def search(self,item):
        cur=self._head
        while cur !=None:
            if cur.elem==item:
                return True
            else:
                cur=cur.next
            return False
    #11、根据指定位置查找元素
    def find(self,index):
        len=self.length()
        if self.is_empty():
            print('空链表')
        if index <0 or index >=len:
            print('索引超过范围')
            return
        node=self._head
        for i in range(len):
            if i == index:
                return node.elem
            node = node.next
    # 12、根据位置替换值
    def change(self,elem,index):
        len=self.length()
        if self.is_empty():
            print('空链表')
            return
        if index <0 or index >=len:
            print('索引超出范围')
            return
        node = self._head
        for i in range(len):
            if i==index:
                node.elem=elem
                return
            node=node.next
    # 13、清空链表
    def clear(self):
        self._head=None
        len=self.length()
        len=0
    # 14、排序
    def sort(self):
        len=self.length()
        for i in range(0,len-1):
            current_node=self._head
            for j in range(0,len-i-1):
                if current_node.elem>current_node.next.elem:
                    tmp=current_node.elem
                    current_node.elem=current_node.next.elem
                    current_node.next.elem=tmp
                current_node=current_node.next
    # 15、是否存在指定的元素
    def isExist(self,item):
        count=0
        current_node=self._head
        for i in range(self.length()):
            if current_node.elem==item:
                print("%d在链表中%d处\n" % (item, i + 1))  # i+1是在正常人认为的位置处,程序员一般是从0开始算起
                count = 1
            current_node=current_node.next
        if count==0:
            print("%d不在链表中\n" % item)
# 测试
if __name__ == "__main__":
    lst = SingleLinkList()
    print(lst.is_empty())
    print(lst.length())
    lst.add(1)
    lst.travel()
    print()
    lst.append(10)
    lst.append(11)
    lst.append(12)
    lst.travel()
    print()
    lst.insert(2,7)
    lst.travel()
    print(lst.find(1))
    lst.remove(7)
    lst.travel()
    print()
    print(lst.search(1))
    lst.delete(1)
    lst.travel()
    print()
    lst.change(1,2)
    lst.travel()
    print()
    lst.sort()
    lst.travel()
    print()
    lst.isExist(1)
    lst.clear()
复制代码

 

结果

复制代码

C:\Anaconda3\python.exe "C:\Program Files\JetBrains\PyCharm 2019.1.1\helpers\pydev\pydevconsole.py" --mode=client --port=65143
import sys; print('Python %s on %s' % (sys.version, sys.platform))
sys.path.extend(['C:\\app\\PycharmProjects', 'C:/app/PycharmProjects'])
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
PyDev console: using IPython 7.12.0
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
runfile('C:/app/PycharmProjects/DataStructure/LinkedList/single_linked_list.py', wdir='C:/app/PycharmProjects/DataStructure/LinkedList')
True
0
1
1 10 11 12
1 10 7 11 12 10
1 10 11 12
True
1 11 12
1 11 1
1 1 11
1在链表中1处
1在链表中2处

 
复制代码

 

链表和顺序表的对比

链表失去了顺序表随机读取的优点,同时链表由于增加了节点的指针域,空间开销大,但对储存空间的使用要相对灵活。

链表域顺序表的各种操作复杂度如下所示:

操作链表顺序表
访问元素 O(n) O(1)
在头部插入/删除 O(1) O(n)
在尾部插入/删除 O(n) O(1)
在中间插入/删除 O(n) O(n)

注意虽然表面上看起来复杂度都是O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝和覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作之间的元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。

 
  1. search(item):查找节点是否存在
 posted on   大码王  阅读(472)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

成都

复制代码

喜欢请打赏

扫描二维码打赏

了解更多

点击右上角即可分享
微信分享提示

目录导航