【数据结构】单链表

线性表:同一种类型的有顺序的一组数据元素

线性表的形式:顺序表、链表

顺序表:表中元素按顺序放在一大块连续的内存中,元素中的顺序由存储顺序来表示
链表:表中元素放在一系列的结点中,通过连接构造。结点可以连续也可以不连续。

结点分为「数据域」和「指针域」。
数据域:保存着作为表元素的数据项;
指针域:保存同一个表里的下一个结点的标识。

在这里插入图片描述

头结点和头指针的区分

头结点 的设立是为了操作的统一和方便,是放在第一个元素的节点之前,它的数据域一般没有意义,并且它本身也不是链表必须要带的。那设立头节点的目的是什么呢?其实就是为了在某些时候可以更方便的对链表进行操作,有了头结点,我们在对第一个元素前插入或者删除结点的时候,它的操作与其它结点的操作就统一了。

头指针 顾名思义,是指向链表第一个结点的指针,如果有头结点的话,那么就是指向头结点的指针。它是链表的必备元素且无论链表是否为空,头指针都不能为空,因为在访问链表的时候你总得知道它在什么位置,这样才能通过它的指针域找到下一个结点的位置,也就是说知道了头指针,整个链表的元素我们都是可以访问的,所以它必须要存在,这也就是我们常说的标识,这也就是为什么我们一般用头指针来表示链表。

单链表

n 个结点链接成一个链表,因为这个链表中的每个结点中只包含一个指针域,所以又叫单链表。单链表的第一个结点的存储位置叫做「头指针」,最后一个结点的指针为「空」,一般用 “^” 表示。
不带头结点的单链表:
在这里插入图片描述
带头结点的单链表:
在这里插入图片描述
空链表:
在这里插入图片描述
为了方便后续的操作,我们一般会先定义一个简单的结点类:

class Node(object):
    def __init__(self,data):
        self.data = data
        self.next = None

单链表的基本操作

首先我们先来创建一个链表类:

class LinkList(object):
	def _init_(self):
	self.head = Node(None)

#判断链表是否为空
	def IsEmpty(self):
		p=self.head #头指针
		
		if p.next == None:
			print("List is empty")
			return True
		return False
#打印链表
	def PrintList(self):
		if self.IsEmpty():
			return 	False
		
		p = self.head
		while p:
			print(p.data,end='')
			p=p.next

1.创建单链表

创建单链表的过程其实就是一个动态生成链表的过程,说简单点就是从一个「空链表」开始,依次建立各个元素的结点,并把它们逐个插入链表,时间复杂度为 O(n):

def InitList(self,data)
	self.head = Node(data[0])#头结点
	p = self.head #头指针

	for i in data[1:]:
		node  = Node(i)
		p.next = node
		p = p.next

2.计算单链表的长度

在使用链表的时候,经常需要求表的长度,为此我们可以创建一个球表长的函数,这个函数就是从左到右扫描,遍历表中的所有结点并完成计数,时间复杂度为 O(n):

def LengthList(self):
    if self.IsEmpty():
        return 0
    p = self.head
    cnt = 0
    while p:
        cnt += 1
        p = p.next
    return cnt

3.单链表的插入

假设我们要将结点 s 插入到 结点 p 的后面,只需要将结点 s 插入到结点 p 和 结点 p.next 之间即可.
在这里插入图片描述

单链表结点的插入根本不需要惊动其它结点,只需要让 s.next 和 p.next 的指针稍作改变即可。这里一定要切记,插入操作的顺序不能改变,至于为什么,你可以拿起纸笔手动的画一下,结果一下子就会出来(对于单链表的表头和表尾的特殊情况,操作是相同的)。

#单链表的插入(在第 s 个结点后面插入 data)
def InsertList(self,s,data):
    if self.IsEmpty() or s < 0 or s > self.LengthList():
        print("Insert failed!")
        return
    p = self.head
    index = 1
    while index < s:
        p = p.next
        index += 1

    node = Node(data)
    node.next = p.next
    p.next = node

4.单链表删除
看完插入,我们现在再来看看单链表的删除。假设我们想要删除一个结点 q,其实就是将它的前继结点 p 的指针绕过 q,直接指向 q 的后继结点即可,具体操作如下图所示:
在这里插入图片描述

#单链表的删除(删除第 s 个结点)
def DeleteList(self, s):
    if self.IsEmpty() or s < 0 or s > self.LengthList():
        print("Delete failed! ")
        return
    p = self.head
    index = 1
    while index < s:
        pre = p
        index += 1
        p = p.next
    pre.next = p.next
    p = None

由 p = None 可以看出,在 Python 中,只需要简单的将指针赋值为 None,就抛弃了链表原有的结点,Python 解释器的存储管理系统会自动回收不用的存储。
5.单链表的读取
在顺序结构中,我们想要获取任意一个元素的存储位置是很容易的,但是在单链表中,第 i 个元素到底在哪我们一开始没办法知道,只能傻傻的从头开始找,所以在对于单链表获取第 i 个元素的操作,算法上相对麻烦一些。

#单链表的读取(获取第 s 个结点的值)
def GetList(self, s):
    if self.IsEmpty() or s < 0 or s > self.LengthList():
        print("Read failed! ")
        return
    p = self.head
    index = 1
    while index < s:
        index += 1
        p = p.next
    print("第 {} 个值为 {}".format(s, p.data))

从上面的代码我们可以很清楚的看出,单链表获取第 i 个元素就是从头开始找,知道第 i 个元素为止,所以我们可以很容易的估算出它的时间复杂度是 O(n)。任何事物都不是完美的,有好的地方就有坏的地方,元素的读取就是单链表美中不足的地方之一。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值