数据结构与算法分析(三):基本数据结构(3)--列表

本系列为《Python数据结构与算法分析》第二版学习笔记,作者:布拉德利.米勒;戴维.拉努姆。

1、列表

列表是元素集合,其中每个元素都有一个相对于其他元素的位置,更具体的说,这种列表称为无序列表。
无序列表支持的操作:

  • List()创建一个空列表。它不需要参数,且会返回一个空列表
  • add(item)假设元素item之前不在列表中,并向其中添加item。
  • remove(item)假设元素item已经在列表中,并从其中移除item。
  • search(item)在列表中搜索item,返回布尔值。
  • isEmpty()检查列表是否为空,返回布尔值。
  • append(item)假设元素item之前不在列表中,并在列表的最后位置添加item。
  • index(item)假设元素已经在列表中,返回该元素在列表中的位置,它接收一个元素作为参数,返回该元素的下标。
  • insert(pos, item)假设元素Item之前不在列表中,同时假设pos是合理的值,并在位置pos处添加元素item。
  • pop()假设列表不为空,移除列表中的最后一个元素。
  • pop(pos)假设在指定位置pos处存在元素,移除该位置上的元素,它接收位置参数且会返回一个元素。

2、链表

无序列表需要维持元素之间的相对位置,但是不需要在连续的内存空间中维护这些位置信息。为了实现无序列表,我们构建链表。
节点是构造链表的基本数据结构,每一个节点对象必须持有至少两份信息。首先,节点必须包含列表元素,我们称之为数据变量。其次,节点必须保存指向下一个节点的引用。
构造Node类

class Node:
    # 初始化节点,将next初始值设为None,这也被称为将节点接地
    def __init__(self, initdata):
        self.data = initdata
        self.next = None

    def getData(self):
        return self.data

    def getNext(self):
        return self.next

    def setData(self, newdata):
        self.data = newdata

    def setNext(self, newnext):
        self.next = newnext

3、无序列表

无序列表是基于节点集合来构造的,每一个节点都通过显式的引用指向下一个节点。只要知道第一个节点的位置,其后的每一个元素都能通过下一个引用找到。因此无序列表类必须包含指向第一个节点的引用。

构造无序列表类:

class UnorderedList:
    # None表明列表的头部没有指向任何节点,列表本身并不包含任何节点对象,而只有指向整个链表结构中第一个节点的引用
    def __init__(self):
        self.head = None

    # isEmpty方法检查列表的头部是否指向None的引用
    def isEmpty(self):
        return self.head is None

    # add方法为列表添加元素,列表中的每一个元素都必须被存放在一个节点对象中
    def add(self, item):
        # 第一步,为元素创建一个新节点
        temp = Node(item)
        # 第二步,将新节点的next引用指向当前列表的第一个节点
        temp.setNext(self.head)
        # 第三步,修改列表的头节点,使其指向新创建的节点
        self.head = temp

    # 为了实现length方法,需要遍历链表并且记录访问过多少个节点
    def length(self):
        # current为外部引用,它被初始化为列表的头节点
        current = self.head
        count = 0
        # 遍历列表,只要current没有指向列表的结尾,就将其指向下一个节点
        while current is not None:
            count += 1
            current = current.getNext()

        return count

    # search方法的实现与length方法相似
    def search(self, item):
        # 从头节点开始
        current = self.head
        found = False
        # 遍历列表,如果当前元素值与搜索值不同而且未到末尾,就将current指向下一个节点
        while current is not None and not found:
            if current.getData() is item:
                found = True
            else:
                current = current.getNext()

        return found

    def remove(self, item):
        # 为了方便移除目标元素,这里引入双指针,快指针current和慢指针previous,这里假设目标值在列表中
        # 在遍历过程中,current与之前一样,标记在链表中的当前位置,慢指针previous总是指向current上次访问的节点
        current = self.head
        previous = None
        found = False
        # 遍历列表
        while not found:
            # 如果发现目标值,退出遍历
            if current.getData() == item:
                found = True
            # 如果未发现目标值,则将快慢指针向前移动一次
            # 必须先将previous移动到current的位置,然后再移动current,这个顺序不能颠倒
            else:
                previous = current
                current = current.getNext()
        # 如果被移除的元素正好是链表的第一个元素,那么current会指向链表中的第一个节点,previous的值则是None
        # 这种情况下,需要修改链表的头节点,而不是Previous指向的节点
        if previous is None:
            self.head = current.getNext()
        else:
            previous.setNext(current.getNext())

4、链表分析

在分析链表操作的时间复杂度时,考虑其是否需要遍历列表。以有n个节点的链表为例,isEmpty方法的时间复杂度是O(1),这是因为它只需要执行一步操作,即检查head引用是否为None。length方法时间复杂度为O(n),向无序列表中添加元素是O(1),这是因为无序链表新添元素都放在第一个位置。但对于有序列表的search、remove以及add都需要进行遍历操作,所有它们的时间复杂度都为O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值