链表python实现(单链表,双链表,单向循环链表)

线性表

线性表的定义:一些元素的序列,维持着元素之间的一种线性关系。
线性表分为顺序表和链接表(链表)

一、顺序表

1.定义
将表中元素顺序地存放在一大块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。
2.顺序表的两种布局方案
(1)如果一个表里保存的元素类型相同,那么每个表元素所需的存储量相同,即可在表里等距安排同样大小的存储位置。如下图左
(2)如果一个表里保存的元素类型不同,那么每个表元素所需的存储量可能不全相同,因此不能在表里等距安排同样大小的存储位置。对于这种情况,将实际数据元素另行存储,而在顺序表里各单元位置保存对相应元素的引用信息(链接),因为每个链接所需的存储量相同。而后对链接做一次访问,就能得到实际元素的数据。如下图右

在这里插入图片描述
在上图(a)中,c是指数据元素的大小,在上图(b)中,c 是指存储一个链接所需的存储量。
3.一个顺序表对象的完整信息
表头(容量+当前元素个数)+数据区
在这里插入图片描述
4.顺序表的两种实现方式
在这里插入图片描述
5.在python中的应用
list和tuple
tuple是不变的表,不支持改变其内部状态的任何操作。

二、链表

1.定义
将表元素存放在通过链接构造起来的一系列存储块里。
2.

(一)单链表

1.结点
结点表元素域和链接域两部分构成,其表元素域elem保存的是数据项,链接域next保存的是下一个结点的链接
2.单链表的实现形式
(1)从单链表的首结点出发,可以找到这个表里的第一个元素(即这个首结点的elem域),还能找到这个表的下一个结点(即这个首结点的next域),照同样的方式进行下去,能找到表里的所有数据元素。
(2)**表头变量(表头指针)**保存着这个表的首结点的链接
(3)单链表的最后一个结点的next域是None
在这里插入图片描述
3.基本链表操作
创建空链表
判断是否为空链表
链表的长度
遍历链表元素
链表头部插入元素
链表尾部插入元素
链表指定位置插入元素
删除指定元素
查找指定元素是否存在
4.python代码实现

##定义结点,结点是由元素域和下一结点链接域构成的
class Node(object):
    def __init__(self,elem):
        self.elem=elem  #结点的元素值
        self.next=None  #结点指向的下一个链接,初始化为None
class SingleLinkList(object):#单链表
    '''
    链表是否为空
    链表长度
    遍历整个链表
    链表头部添加元素
    链表尾部添加元素
    指定位置添加元素
    删除结点
    查找结点
    '''
    def __init__(self,node=None):
        self.__head=node  #链表的头结点,初始化为None。两横线__表示私有属性
    def is_empty(self):  #判断链表是否为空
        return self.__head==None
    def length(self): #求链表长度
        count=0 
        cur=self.__head
        while cur!=None:
            count+=1
            cur=cur.next
        return count
   
    def travel(self):  #遍历整个链表元素
        cur=self.__head
        while cur!=None:
            print(cur.elem)
            cur=cur.next
    
    def add(self,item): #在链表头部添加元素
        node=Node(item)
        if self.is_empty():
            self.__head=node
        else:
            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):#指定位置添加元素
        count=self.length()
        if pos<=0:
            self.add(item)
        elif 0<pos<count:
            node=Node(item)
            cur=self.__head
            num=1
            while num<pos:
                cur=cur.next
                num+=1
            node.next=cur.next
            cur.next=node                                 
        elif pos>=count:
            self.append(item)
'''
def insert(self,pos,item):
        if pos<=0:
            self.add(item)
        elif pos>=self.length():
            self.append(item)
        else:
            node=Node(item)
            cur=self.__head
            pre=None
            num=0
            while num<pos:
                pre=cur
                cur=cur.next
                num+=1
            node.next=cur
            pre.next=node'''
'''
def insert(self,pos,item):
        if pos<=0:
            self.add(item)
        elif pos>=self.length():
            self.append(item)
        else:
            node=Node(item)
            cur=self.__head
            num=0
            while num< pos-1:
                cur=cur.next
                num+=1
            node.next=cur.next
            cur.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
ll=SingleLinkList() #实例化
ll.append(1)
ll.append(2)
ll.append(3)
ll.travel()
ll.remove(3)

(二)单向循环链表

1.实现形式
单向循环链表的最后一个结点的next域指向表的第一个结点
在这里插入图片描述

2.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  #将_head指向头结点
        if node:
            node.next=node  #指向自己
    def  is_empty(self):
        if self.__head==None:
            return True
        else:
            False
    def length(self):
        if self.__head==None:  #空链表的情况
            return 0
        else:
            cur=self.__head
            count=1
            while cur.next!=self.__head: #尾结点的判断标准————若cur.next==self.__head,那么cur就是尾结点。
                count+=1
                cur=cur.next
            return count
    def travel(self):
        if self.is_empty():  #空链表的情况
            return 
        else:
            cur=self.__head
            while cur.next!=self.__head:#循环终止条件————游标cur到达尾结点
                print(cur.elem)
                cur=cur.next
            print(cur.elem) #尾结点
    def add(self,item):  #头部添加————尾结点的指向改变
        node=Node(item)
        if self.__head==None:  #空链表的情况
            self.__head=node
            node.next=node #指向自己
        else:
            ##需要找到尾结点
            cur=self.__head
            while cur.next!=self.__head:
                cur=cur.next  
            #退出循环后,此时的cur是尾结点
            node.next=self.__head  #新结点node指向原来的头结点
            self.__head=node   #__head指向新结点,即新的头结点
            cur.next=node      #尾结点指向新的头结点
            #先找到尾结点,再改变链接的指向要比先改变链接的指向,再找尾结点的时间复杂度低。————尽量不改变原来的链表
    
    def append(self,item): #尾部添加————尾结点改变,需重新指向头结点
        node=Node(item)
        if self.__head==None:  #空链表的情况
            self.__head=node
            node.next=node
        else:
            cur=self.__head
            while cur.next!=self.__head:
                cur=cur.next
            #退出循环后,此时的cur是尾结点
            cur.next=node
            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 #游标
            num=0
            while num<pos-1:
                num+=1
                cur=cur.next
            #退出循环后,此时的cur后面要插入新的结点
            node.next=cur.next #新结点指向cur后的结点
            cur.next=node
    def remove(self,item):
        if self.__head==None: #空链表,则不执行任何操作
            return 
        else:
            cur=self.__head #游标,需要遍历
            pre=None
            while cur.next!=self.__head:#遍历终止的条件————游标cur到达尾结点
                if cur.elem==item:
                    if cur==self.__head:#考虑头结点的情况 
                            #需要找到尾结点,标明指向
                        rear=self.__head #游标 
                        while rear.next!=self.__head:
                            rear=rear.next 
                        #尾结点————rear
                        self.__head=cur.next
                        rear.next=self.__head
                    else:
                        pre.next=cur.next
                    return  #结束(这里不能写break,因为break跳出循环体后,会执行循环体外的语句)    
                else:
                    pre=cur
                    cur=cur.next
            #退出循环后,考虑尾结点的情况
            if cur.elem==item:
                #考虑只有一个结点的情况
                if cur==self.__head:#__head的指向没有发生变化,仍是指向头结点
                    self.__head=None   
                else:
                    pre.next=self.__head

    
    def search(self,item):
        if self.__head==None: #考虑空链表的情况
            return False
        else:
            cur=self.__head #游标,需要遍历
            while cur.next!=self.__head:#遍历终止的条件————游标cur到达尾结点
                if cur.elem==item:
                    return True
                else:
                    cur=cur.next
            ##退出循环后,此时的cur是尾结点
            #要考虑尾结点的元素值是否等于item
            if cur.elem==item:
                return True
            else:
                return False     

(三)双向链表

1.实现形式
双链表的每一个结点有两个链接:一个prev指向前一个结点,一个next指向后一个结点。
双链表的首结点的prev域指向None,双链表的尾结点的next域指向None
在这里插入图片描述2.python代码实现

#双向链表
class Node(object):
    def __init__(self,elem):
        self.elem=elem  #链表元素
        self.next=None  #后继结点
        self.prev=None  #前驱结点

class DoubleLinkList(object):
    def __init__(self,node=None): #初始化
        self.__head=node   #__head指向头结点
    def is_empty(self):#判断是否是空链表
        if self.__head is None:
            return True
        else:
            return False
    def length(self):
        cur=self.__head #相当于游标,去遍历所有结点
        count=0
        while cur!=None: #结点为None时,链表遍历结束
            count+=1
            cur=cur.next
        return count
    def travel(self):
        cur=self.__head
        while cur!=None:
            print(cur.elem)
            cur=cur.next
    def add(self,item):
        node=Node(item)
        node.next=self.__head  #新结点的后继结点指向原来的头结点
        self.__head.prev=node  #原来头结点的前驱结点指向新结点
        self.__head=node       #__head指向新结点

    def append(self,item):
        node=Node(item)
        if self.__head==None:
            self.__head=node
        else:
            cur=self.__head
            while cur.next!=None:
                cur=cur.next
            cur.next=node
            node.prev=cur
   
    def insert(self,pos,item):
        if pos<=0:
            self.add(item)
        elif pos>=self.length():
            self.append(item)
        else:
            node=Node(item)
            cur=self.__head
            num=0
            while num< pos:
                cur=cur.next
                num+=1
            cur.prev.next=node
            node.prev=cur.prev
            node.next=cur
            cur.prev=node
#None是没有前驱结点和后继结点的
    def remove(self,item):#删除元素————从头开始,删除遇到的第一个指定元素
        cur=self.__head
        while cur!=None: #遍历
            if cur.elem==item:
                if cur==self.__head: #判断此结点是否是头结点
                    self.__head=cur.next 
                    if cur.next!=None: #判断链表是否只有一个结点  '''if cur.next:'''
                        cur.next.prev=None
                        
                else:
                    cur.prev.next=cur.next
                    if cur.next: #判断此结点是否是最后一个结点
                        cur.next.prev=cur.prev
                    
                break
            else:
                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
'''
    def add(self,item):
        node=Node(item)
        node.next=self.__head  #新结点的后继结点指向原来的头结点
        self.__head=node       #__head指向新结点
        node.next.prev=node    #新的结点的后继结点的前驱结点指向新结点
#表示方式不是唯一的
'''
'''
     def insert(self,pos,item):
        if pos<=0:
            self.add(item)
        elif pos>=self.length():
            self.append(item)
        else:
            node=Node(item)
            cur=self.__head
            num=0
            while num< pos-1:
                cur=cur.next
                num+=1
            node.next=cur.next
            cur.next.prev=node
            cur.next=node
            node.prev=cur
'''

三、小结

顺序表和链表的时间复杂度对比
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值