数据结构 --- 链表

数据结构 — 链表

链表

在電腦科學中,链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多(如列表和数组),但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

单向链表

链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。
在这里插入图片描述

实现单向链表(python)

步骤:

  • 创建节点
    # 写一个节点类:
    class Node:
    	def __init__(self,item=None):
    		self.item = item # 节点中存储的值
    		self.next = None # 链接下一个节点的指针
    
  • 链接多个节点,组成链表
    class Node:
    	def __init__(self,item=None):
    		self.item = item 
    		self.next = None 
    # 创建两个节点
    a = Node(1)
    b = Node(2)
    # a链接b
    a.next = b
    

节点插入(头插法&&尾插法)

  • 头插法:在链表的头部插入节点
    • 把节点插入头部会遇到两种情况(self.head存储头部所在节点,self.tail存储尾部所在节点):1.链表为空;2.链表不为空。
      图一

    • 当头节点和尾节点的指向都为空时,此时链表中没有节点,是一个空链表,在这种情况下插入‘节点a’,只需把头节点和尾节点同时指向‘节点a’。

    • 在这里插入图片描述

    • 当链表不为空时,将‘节点b’插入链表头部,并将头节点指向‘节点b’

      • (头插法)代码实现如下:
      	# 链表类
      	class LinkList:
      		class Node:
      			def __init__(self,item=None):
      				self.item = item 
      				self.next = None 
      		def __init__(self):
      			self.head = None # 头节点
      			self.tail = None # 尾节点
      		# 头插法		
      	    def unshift(self, item):
      	    	# 创建要插入的节点
      	       cur_node = self.Node(item) 
      	       # 链表为空时:
      	       if not bool(self.head):
      	           self.head = cur_node
      	           self.tail = cur_node
      	       # 不为空时:
      	       else:
      	           cur_node.next = self.head
      	           self.head = cur_node
      
  • 尾插法:在链表的尾部插入节点
    • 尾插法与头插法类似,1.链表为空;2.链表不为空。
      在这里插入图片描述
      在这里插入图片描述
      • (尾插法)代码实现如下:
      	# 链表类
      class LinkList:
      	class Node:
      		def __init__(self,item=None):
      			self.item = item 
      			self.next = None 
      	def __init__(self):
      		self.head = None # 头节点
      		self.tail = None # 尾节点
      
      	# 尾插法
          def append(self,item):
          	# 创建要插入的节点
              cur_node = self.Node(item)
              # 链表为空时:
              if not bool(self.head):
                  self.head = cur_node
                  self.tail = cur_node
              # 不为空时:
              else:
                  self.tail.next = cur_node
                  self.tail = cur_node
      

指定位置插入节点

在这里插入图片描述

初始时,节点a —> 节点b,创建节点c,接着节点c —> 节点b,最后,节点a —> 节点c (—>表示指向,a.next = b,节点a指向节点b)

# 链表类
class LinkList:
    class Node:
        def __init__(self, item=None):
            self.item = item
            self.next = None

    def __init__(self):
        self.head = None
        self.tail = None
    # 查看链表
    def __repr__(self):
        head = self.head
        data = []
        while head:
            data.append(str(head.item))
            head = head.next
        del head
        return f'<<< {",".join(data)} >>>'
    # 头插法
    def unshift(self, item):
        cur_node = self.Node(item)
        if not bool(self.head):
            self.head = cur_node
            self.tail = cur_node
        else:
            cur_node.next = self.head
            self.head = cur_node
    # 尾插法
    def append(self,item):
        cur_node = self.Node(item)
        if not bool(self.head):
            self.head = cur_node
            self.tail = cur_node
        else:
            self.tail.next = cur_node
            self.tail = cur_node
    # 查看链表长度
    def len(self):
        head = self.head
        length = 0
        while head:
            length += 1
            head = head.next
        del head
        return length
        
    def find_pre_node(self,index):
   	""" 作用:找到插入(待删除)位置所在节点的前一个节点
		有三种情况:
				1.插入(待删除)位置在头部
				2.插入(待删除)位置在尾部
				3.既不在头部,也不在尾部
				---------------------------------
				情况一:返回一个‘start’字符串,
					   让insert函数调用unshift()函数进行头插;
					   让delete函数调用shift()函数进行去头;
				情况二:返回一个‘end’字符串,
					   让insert函数调用append()函数进行尾插;
					   让delete函数调用pop()函数进行去尾;
				情况三:返回插入(待删除)位置所在节点的前一个节点
	"""
        if index == 0:
            return 'start'
        if index == self.len() - 1:
            return 'end'
        head = self.head
        for i in range(index-1):
            head = head.next
        return head
        
    def insert(self,item,index):
        pre_node = self.find_pre_node(index)
        if pre_node == 'start':
            self.unshift(item)
            return
        elif pre_node == 'end':
            self.append(item)
            return
         # index位置上所在的节点
        next_node = pre_node.next
        # 创建待插入的节点
        insert_node = self.Node(item)

        insert_node.next = next_node
        pre_node.next = insert_node

节点删除(去头法&&去尾法)

  • 去头法
    在这里插入图片描述
    • self.head由节点a指向节点b,实现节点a的删除效果
    # 链表类
    class LinkList:
    	class Node:
    		def __init__(self,item=None):
    			self.item = item 
    			self.next = None 
    	def __init__(self):
    		self.head = None # 头节点
    		self.tail = None # 尾节点
    	# 删除头节点
        def shift(self):
            self.head = self.head.next
    
    
  • 去尾法
    在这里插入图片描述
    • self.tail由节点c指向节点b,实现节点c的删除效果
    # 链表类
    class LinkList:
    	class Node:
    		def __init__(self,item=None):
    			self.item = item 
    			self.next = None 
    	def __init__(self):
    		self.head = None # 头节点
    		self.tail = None # 尾节点
    	# 查看链表长度
        def len(self):
            head = self.head
            length = 0
            while head:
                length += 1
                head = head.next
            del head
            return length
        
        # 删除尾结点
        def pop(self):
            head = self.head
            for i in range(self.len()-2):
                head = head.next
            self.tail = head
            self.tail.next = None
    

指定位置删除节点

在这里插入图片描述

# 链表类
class LinkList:
	class Node:
		def __init__(self,item=None):
			self.item = item 
			self.next = None 
	def __init__(self):
		self.head = None # 头节点
		self.tail = None # 尾节点
	# 查看链表长度
   	def len(self):
        head = self.head
        length = 0
        while head:
            length += 1
            head = head.next
        del head
        return length
        
    def find_pre_node(self,index):
   	""" 作用:找到插入(待删除)位置所在节点的前一个节点
		有三种情况:
				1.插入(待删除)位置在头部
				2.插入(待删除)位置在尾部
				3.既不在头部,也不在尾部
				---------------------------------
				情况一:返回一个‘start’字符串,
					   让insert函数调用unshift()函数进行头插;
					   让delete函数调用shift()函数进行去头;
				情况二:返回一个‘end’字符串,
					   让insert函数调用append()函数进行尾插;
					   让delete函数调用pop()函数进行去尾;
				情况三:返回插入(待删除)位置所在节点的前一个节点
		"""
        if index == 0:
            return 'start'
        if index == self.len() - 1:
            return 'end'
        head = self.head
        for i in range(index-1):
            head = head.next
        return head
    # 删除头节点
    def shift(self):
        self.head = self.head.next
    # 删除尾结点
    def pop(self):
        head = self.head
        for i in range(self.len()-2):
            head = head.next
        self.tail = head
        self.tail.next = None
    def delete(self,index):
	    pre_node = self.find_pre_node(index)
	    if pre_node == 'start':
	        self.shift()
	        return
	    elif pre_node == 'end':
	        self.pop()
	        return
	    delete_node = pre_node.next
	    next_node = pre_node.next.next
	
	    pre_node.next = next_node
	    del delete_node

完整代码:

class LinkList:
    class Node:
        def __init__(self, item=None):
            self.item = item
            self.next = None

    def __init__(self):
        self.head = None
        self.tail = None

    # 查看链表
    def __repr__(self):
        head = self.head
        data = []
        while head:
            data.append(str(head.item))
            head = head.next
        del head
        return f'<<< {",".join(data)} >>>'

    # 头插法
    def unshift(self, item):
        cur_node = self.Node(item)
        if not bool(self.head):
            self.head = cur_node
            self.tail = cur_node
        else:
            cur_node.next = self.head
            self.head = cur_node

    # 尾插法
    def append(self, item):
        cur_node = self.Node(item)
        if not bool(self.head):
            self.head = cur_node
            self.tail = cur_node
        else:
            self.tail.next = cur_node
            self.tail = cur_node

    # 查看链表长度
    def len(self):
        head = self.head
        length = 0
        while head:
            length += 1
            head = head.next
        del head
        return length

    def find_pre_node(self, index):
        if index == 0:
            return 'start'
        if index == self.len() - 1:
            return 'end'
        head = self.head
        for i in range(index - 1):
            head = head.next
        return head

    def insert(self, item, index):

        pre_node = self.find_pre_node(index)
        if pre_node == 'start':
            self.unshift(item)
            return
        elif pre_node == 'end':
            self.append(item)
            return
        next_node = pre_node.next
        insert_node = self.Node(item)

        insert_node.next = next_node
        pre_node.next = insert_node

    # 删除头节点
    def shift(self):
        self.head = self.head.next

    # 删除尾结点
    def pop(self):
        head = self.head
        for i in range(self.len() - 2):
            head = head.next
        self.tail = head
        self.tail.next = None

    def delete(self, index):
        pre_node = self.find_pre_node(index)
        if pre_node == 'start':
            self.shift()
            return
        elif pre_node == 'end':
            self.pop()
            return
        delete_node = pre_node.next
        next_node = pre_node.next.next

        pre_node.next = next_node
        del delete_node

如有疑问,或者有不足之处,欢迎在评论区下留言讨论

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值