数据结构 09-链表概念及常见链表结构

目   录

1. 链表

1.1 链表概念

1.2 链表优点

1.3 链表缺点

2.常见链表结构

2.1 单链表

2.1.1 单链表结构

2.1.2 单链表代码实现

2.2 单向循环链表

2.2.1 单向循环链表结构

2.2.2 单循环链表代码实现

2.3 双向链表

2.3.1 双向链表结构

2.3.2 双向链表代码实现


1. 链表

1.1 链表概念

        前面提到,栈、队列都可以视作是一种特殊的线性表,在绝大多数语言中都是连续存储的。而链表则是不连续的存储方式,自适应内存大小,通过指针的使用,灵活将不同的内存块联系起来,实现动态增加动态删除。

        链表的基础是结点 node,每个结点应该包含至少两个区域,一个是存放数据的区域,一个是指向下一个节点的指针。对于整个链表而言,应该有指向头结点的头指针,尾部结点根据链表的不同类型可以指向空(单链表),也可以指向头节点(循环链表)。根据指针的配置,结点可以是单向的,也可以是双向的,从而链表可以是单向的,也可以是双向的。

1.2 链表优点

        相对于连续存储的结构, 链表优点还是很明显的:

  1. 内存空间是不连续的,可以充分利用计算机的零碎内存,实现灵活的内存动态管理。
  2. 链表不必在创建时就确定大小, 并且大小可以无限的延伸下去(如果计算机内存支持的话)。
  3. 链表在插入和删除数据时, 只需要移动少量数据,时间复杂度会降低很多。

1.3 链表缺点

        链表也有一些缺点:

  1. 链表如果按照位置访问,访问任何一个位置的元素时, 都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。即无法通过下标直接访问元素。备注:笔者认为,没有完美的数据结构能够满足所有用户需求,无论是栈、队列抑或是链表,都需要结合实际数据特性和用户使用特性来决定数据结构。比如链表的这个缺点,如果数据不需要按照位置访问,可能就不是缺点。
  2. 因为需要存储指向下一个结点的指针,额外要消耗内存。

2.常见链表结构

2.1 单链表

2.1.1 单链表结构

        单链表是最简单的链式存取的数据结构,每个单独数据是以对应的结点来表示的,每个结点由元素和指针构成。

2.1.2 单链表代码实现

        单向链表需要实现的基本操作有:

  1.         创建链表
  2.         新增结点到链表尾部
  3.         删除第n个结点
  4.         读取第n个结点
  5.         逆转顺序读取链表(非必需)

      每个人有每个人的设计代码实现,有些同学在单链表中只设计一个头指针,需要在链表尾部新增数据时候从头指针一直查找到最后,而我喜欢创建头指针、尾指针两个指针,以空间换时间,代码实现也更简单。

下面是我的代码实现:

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

class SingleLink():
    def __init__(self):
        self.phead=None
        self.ptail=None
        self.length=0
    
    def add(self,value):
        node=Node(value)
        if(not self.phead):
            self.phead=node
            self.ptail=node
            self.length=1
        else:
            self.ptail.next=node
            self.ptail=node
            self.ptail.next=None
            self.length+=1

    #删除第 n 个结点
    def delete(self,n):
        #如果当前链表为空,不操作
        if(self.length==0):
            return(None)
        
        # 如果超出现有长度,删除最后一个结点
        if(n>self.length):
            n=self.length
        
        # 如果删除第一个结点,即头节点
        # 则直接移动头指针到下一个结点
        if(n==1):
            self.phead=self.phead.next
            self.length-=1
            return(None)
        
        # 获得头指针
        p=self.phead
        
        # 目的是获得被删除结点的前一个结点
        while(n>2):
            p=p.next
            n-=1
        
        # 如果这是最后一个结点,那么前一个结点直接指向空
        # 如果这不是最后一个结点,那么前一个结点直接指向再下一个结点
        if(p.next.next):
            p.next=p.next.next
        else:
            p.next=None
        self.length-=1
    
    def read(self,n):
        if(n>self.length):
            n=self.length
        p=self.phead
        while(n>1):
            p=p.next
            n-=1
        return(p.val)
    
    def show(self):
        print("current length is {0}".format(self.length))
        p=self.phead
        while( p.next ):
            print(p.val,end=" , ")
            p=p.next
        print(p.val)
        return(None)
    
    def reverse_show(self,node):
        p=node
        if(p.next):
            self.reverse_show(p.next)
        print(p.val,end=" , ")

运行相关测试代码后结果如下:

#创建单链表
a_link=SingleLink()

#填充数据 1~9
for i in range(1,10):
    a_link.add(i)
print()

#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()

#逆序展示数据
print("*"*30+"逆序展示链表数据"+"*"*30)
a_link.reverse_show(a_link.phead)
print()

#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)


#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)


#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)

 

2.2 单向循环链表

2.2.1 单向循环链表结构

        单向循环链表即将单链表的尾结点指向头结点的链表,又称之为循环单链表(Circular linkedlist)。

        

2.2.2 单循环链表代码实现

        单循环链表需要实现的基本操作有:

  1.         创建链表
  2.         新增结点到链表尾部
  3.         新增结点到链表第 n 个结点
  4.         删除第n个结点
  5.         读取第n个结点

        同样,在单循环链表中,如果设计头指针、尾指针两个指针,则不光是空间换时间,而且代码实现会更方便。

下面是我的代码实现:

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

class S_CirLink():
    def __init__(self):
        self.phead=None
        self.ptail=None
        self.length=0
    
    def addTail(self,value):
        node=Node(value)
        if(not self.phead):
            self.phead=node
            self.ptail=node
            node.next=node
            self.length=1
        else:
            self.ptail.next=node
            self.ptail=node
            node.next=self.phead
            self.length+=1

    # n 限制在大于等于 1 
    def addN(self,value,n):
        node=Node(value)
        if(not self.phead):
            self.phead=node
            self.ptail=node
            node.next=node
            self.length=1
        else:
            if(n==1):
                node.next=self.phead
                self.phead=node
                self.ptail.next=self.phead
                self.length+=1
                return(None)
            
            if(n>self.length):
                n=self.length+1
            p=self.phead
            
            while(n>2):
                p=p.next
                n-=1
            node.next=p.next
            p.next=node
            self.length+=1
        return(None)
    
    #删除第 n 个结点
    def delete(self,n):
        #如果当前链表为空,不操作
        if(self.length==0):
            return(None)
        
        # 如果超出现有长度,删除最后一个结点
        if(n>self.length):
            n=self.length
        
        # 如果删除第一个结点,即头节点
        # 则直接移动头指针到下一个结点
        if(n==1):
            if(self.length==1):
                self.phead=None
                self.ptail=None
                self.length=0
                return(None)
            self.phead=self.phead.next
            self.ptail.next=self.phead
            self.length-=1
            return(None)
        
        # 此处处理链表长度大于1 的情况,获得头指针
        p=self.phead
        
        # 目的是获得被删除结点的前一个结点
        while(n>2):
            p=p.next
            n-=1
        
        # 因为是循环链表,所以链表长度大于1时候删除一个结点,
        # 链表肯定不为空,直接指向下一个链表即可
        if(p.next!=self.ptail):
            p.next=p.next.next
        else:
            p.next=p.next.next
            self.ptail=p

        self.length-=1
    
    def read(self,n):
        if(n>self.length):
            n=self.length
        p=self.phead
        while(n>1):
            p=p.next
            n-=1
        return(p.val)
    
    def show(self):
        print("current length is {0}".format(self.length))
        p=self.phead
        while( p.next!=self.phead ):
            print(p.val,end=" , ")
            p=p.next
        print(p.val)
        return(None)

测试代码如下:

#创建单向循环链表
a_link=S_CirLink()

#填充数据 1~9
for i in range(1,10):
    a_link.addTail(i)
print()

#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()


#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)

#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)

#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)

# 增加一个结点,排序为 3
print("Now to add new  node in third place,the value is 11")
a_link.addN(11,3)
a_link.show()

# 增加一个尾结点,排序为 6
print("Now to add new  node in 6th place,the value is 12")
a_link.addN(12,6)
a_link.show()

运行结果:

  

2.3 双向链表

2.3.1 双向链表结构

        双向链表是结点 Node 既有一个 prev (前驱指针) ,又有一个 next (后驱指针) 来构成的一种数据结构。

        

2.3.2 双向链表代码实现

        双向链表需要实现的基本操作有:

  1.         创建双向链表
  2.         新增结点到链表尾部
  3.         新增结点到链表第 n 个结点
  4.         删除第n个结点
  5.         读取第n个结点

下面是我的代码实现:

class Node():
    def __init__(self,value):
        self.val=value
        self.prev=None
        self.next=None

class Bid_Link():
    def __init__(self):
        self.phead=None
        self.ptail=None
        self.length=0
    
    def addTail(self,value):
        node=Node(value)
        if(not self.phead):
            self.phead=node
            self.ptail=node
            self.length=1
        else:
            self.ptail.next=node
            node.prev=self.ptail
            self.ptail=node
            node.next=None
            self.length+=1

    def addN(self,value,n):
        if(not self.phead or n>self.length):
            self.addTail(value)
            return(None)
        
        node=Node(value)
        
        if(n==1):
            node.next=self.phead
            self.phead.prev=node
            self.phead=node
            self.length+=1
            return(None)
            
        p=self.phead
        while(n>2):
            p=p.next
            n-=1
        node.prev=p
        node.next=p.next
        node.next.prev=node
        p.next=node
        self.length+=1
        return(None)
    
    #删除第 n 个结点,n 大于等于 0
    def delete(self,n):
        #如果当前链表为空,不操作
        if(self.length==0):
            return(None)
        
        # 如果超出现有长度,删除最后一个结点
        if(n>self.length):
            n=self.length
            
        # 如果删除第一个结点,即头节点
        # 则直接移动头指针到下一个结点
        if(n==1):
            if(self.length==1):
                self.phead=None
                self.ptail=None
                self.length=0
                return(None)
            self.phead=self.phead.next
            self.phead.prev=None
            self.length-=1
            return(None)
        
        
        # 此处处理链表长度大于1 的情况,获得头指针
        p=self.phead
        
        # 目的是获得被删除结点的前一个结点
        while(n>2):
            p=p.next
            n-=1
        
        # 双向链表,需要处理前驱指针、后驱指针
        tmp=p.next
        if(p.next.next):
            p.next=tmp.next
            tmp.next.prev=p
        else:
            p.next=None
            self.ptail=p
        self.length-=1
        return(None)
    
    def read(self,n):
        if(n>self.length):
            n=self.length
        p=self.phead
        while(n>1):
            p=p.next
            n-=1
        return(p.val)
    
    def show(self):
        print("current length is {0}".format(self.length))
        p=self.phead
        while(p.next):
            print(p.val,end=" , ")
            p=p.next
        print(p.val)
        return(None)

测试代码如下:

#创建双向循环链表
a_link=Bid_Link()

#填充数据 1~9
for i in range(1,10):
    a_link.addTail(i)
print()

#展示数据
print("*"*30+"填充数据 1~9之后链表为"+"*"*30)
a_link.show()


#连续两次删除头节点
print("*"*50)
print("Now to delete first node twice")
a_link.delete(1)
a_link.show()
a_link.delete(1)
a_link.show()
print("*"*50)

#删除中间结点第二个结点
print("Now to delete second node ")
a_link.delete(2)
a_link.show()
print("*"*50)

#连续两次删除尾节点
print("Now to delete last node twice")
a_link.delete(7)
a_link.show()
a_link.delete(6)
a_link.show()
print("*"*50)

# 增加一个结点,排序为 3
print("Now to add new  node in third place,the value is 11")
a_link.addN(11,3)
a_link.show()

# 增加一个尾结点,排序为 6
print("Now to add new  node in 6th place,the value is 12")
a_link.addN(12,6)
a_link.show()

运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南野栀子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值