链接表

本文介绍了链接表的概念,强调了单向链接表的特性,包括节点结构和链表的基本操作,如创建空链表、删除链表、判断是否为空、首端插入和一般插入、删除元素等。此外,还讨论了扫描、定位和遍历链表的方法,以及单链表类的实现,包括节点类和自定义异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接表把每个元素储存在一批独立的储存块里,在每个节点中显式的保存下一个节点的链接,从每个节点都可以找到与其相关的下一个节点。

单向链接表

节点为一个二元组,分别保存着元素数据和下一个节点的链接,在尾节点的链接域设置一个空链接来表示表的结束。
单链表
定义一个简单的表节点类:

class LNode:
    def __init__(self, elem, next_=None):
        self.elem = elem
        self.next = next_ 

链表基本操作

  • 创建空链表:
    只需要把相应的表头变量设置为空链接:None,就代表没有后续元素,即为一个空表。O(1)
  • 删除链表:
    应丢弃这个表中的所有节点,在Python中只需把表的指针赋值为None,就抛弃了所有的节点,Python的存储管理系统会自动回收内存。O(1)
  • 判断表是否为空:
    检查表头的链接是否为空。O(1)
加入元素:

链接表加入元素不需要移动已有的数据,只要通过修改链接把新节点加入到合适的位置就行;这里有两种情况:

  • 首端插入
    创建一个新节点,把原表首节点连接存入到新链接的链接域(原表首节点现在在新节点之后),修改表头变量,指向新节点,新节点称为表的开始。O(1)
    单链表表首
q = LNode(13)
q.next = head.next
head = q
  • 一般情况下插入
    找到要插入位置之前的那个点,将它链接域的值复制到新节点的链接域,然后将自己的链接域改为新节点的链接。O(n)
    单链表表首
q =LNode(13)
q.next = pre.next
pre.next = q
删除元素:
  • 删除表首元素,将表头指针指向第二个节点。O(1)
head = head.next
  • 一般情况下元素删除,找到要删除元素的前一个节点,修改链接域,指向下一个节点。O(n)
pre.next = pre.next.next
扫描、定位和遍历

单链表只有一个方向,只知道一个表头变量,所以对表的检查都是从表头变量开始,沿着表中链接逐步进行,这种操作称为扫描,基本操作模式为:

p = head
while p is not None and 其他条件:
    对p节点里的数据操作
    p = p.next

变量p称为扫描指针,每次迭代前检查p的值来判断随后操作的合法性。

  • 按下标定位O(n)
p = head
while p is not None and i>0:
    i -=1
    p = p.next
  • 按元素定位O(n)
    假设需要满足函数pred()
p = head
while p is not None and not pred(p.elem):
    p = p.next
  • 遍历O(n)
p = head
while p is not None:
    print p.elem
    p = p.next
求表的长度O(n)
def length(head):
    p, n = head, 0
    while p is not None:
        n += 1
        p = p.next
    return n

单链表类的实现

  • 节点类的使用
class LNode:
    def __init__(self, elem, next_=None):
        self.elem = elem
        self.next = next_

llistl = LNode(1)  #实例化一个节点
p = llistl  #p指向第一个节点

for i in range(2, 11):
    p.next = LNode(i)  #第一个节点的链接域指向下一个实例化的节点
    p = p.next  #将p指向下一个节点,然后循环

p = llistl
while p is not None:
    print p.elem
    p = p.next

输出:

1
2
3
4
5
6
7
8
9
10
  • 自定义异常
class LinkedListUnderflow(ValueError):
    pass
  • LList类的定义
class LList():
    def __init__(self):
        self._head = None

    def is_empty(self):
        return self._head is None

    def prepend(self, elem):  #在首部添加元素
        self._head = LNode(elem, self._head)  #把新元素的链接域设为原来_head的值,_head指向新元素,为第一个元素,新元素又指向旧元素

    def pop(self):  #删除首个元素并返回它的值
        if self._head is None:  #无节点引发异常
            raise LinkedListUnderflow("in pop")
        e = self._head.elem  #获取首节点的元素
        self._head = self._head.next  #_head指向下一个元素
        return e

    def append(self, elem):  #在表后加入元素,两种情况
        if self._head is None:  #空链表加入方法
            self._head = LNode(elem)
            return
        p = self._head  #从头检查,直到检查到最后一个元素,在它的next里加入新元素的链接
        while p.next is not None:
            p = p.next
        p.next = LNode(elem)

    def pop_last(self):  #删除最后元素并返回它的值
        if self._head is None:  #为空表时引发异常
            raise LinkedListUnderflow("in pop_last")
        if self._head.next is None:  #只有一个元素的情况
            e = self._head.elem
            self._head = None
            return e
        p = self._head  #p.next.next为None的元素为倒数第二个元素
        while p.next.next is not None:
            p = p.next
        e = p.next.elem
        p.next = None
        return e

    def find(self, pred):
        p = self._head
        while p is not None:
            if pred(p.elem):
                return p.elem
            p = p.next

    def printall(self):  #打印表中元素
        p = self._head
        while p is not None:
            print p.elem, end=''
            if p.next is not None:
                print ',', end=''
            p = p.next
        print 'END'

    def for_each(self, proc):  #对每个元素进行谓语函数的操作
        p = self._head
        while p is not None:
            proc(p.elem)
            p = p.next

#为了使LList可迭代,最简单的方式是定义生成器函数。
    def elements(self):
        p = self._head
        while p is not None:
            yield p.elem
            p = p.next
#这样LList.elements()为一个生成器,就可以用for来迭代LList.elements()了

#把生成器和上边的find方法结合就可以做成一个筛选器
    def filter(self, pred):
        p = self._head
        while p is not None:
            if pred(p.elem):
                yield p.elem
            p = p.next
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值