数据结构 | 线性数据结构——列表

目录

一、无序列表抽象数据类型

二、实现无序列表:链表

2.1 Node类

2.2 UnorderedList类

三、有序列表抽象数据类型

四、实现有序列表


列表是元素的集合,其中每一个元素都有一个相对于其他元素的位置。更具体地说,这种列表成为无序列表。可以认为列表有第一个元素、第二个元素。第三个元素,等等;也可以称第一个元素为列表的起点,称最后一个元素为列表的终点。为简单起见,我们假设列表中没有重复的元素。

一、无序列表抽象数据类型

如前所述,无序列表是元素的集合,其中每一个元素都有一个相对于其他元素的位置。以下是无序列表支持的操作。

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

二、实现无序列表:链表

为了实现无序列表,我们要构建链表。无序列表需要维持元素之间的相对位置,但是并不需要在连续的内存空间中维护这些位置信息。如果可以为每一个元素维护一份信息,即下一个元素的位置,那么这些元素的相对位置就能通过指向下一个元素的链接来表示。

需要注意的是,必须指明列表中第一个元素的位置。一旦知道第一个元素的位置,就能根据其中的链接信息访问第二个元素,接着访问第三个元素,依此类推。指向链表第一个元素的引用被称作。最后一个元素需要知道自己没有下一个元素。

2.1 Node类

节点是构建链表的基本数据结构。每一个节点对象都必须持有至少两份信息。首先,节点必须包含列表元素,我们称之为节点的数据变量。其次,节点必须保存指向下一个节点的引用。在构建节点时,需要为其提供初始值。Node类也包含访问和修改数据的方法,以及指向下一个元素的引用。

>>> temp=Node(93)
>>> temp.getData()
93

特殊的Python引用值None在Node类以及之后的链表中起到了重要的作用。指向None的引用代表着后面没有元素。注意,Node的构造方法将next的初始值设为None。由于这有时被称为“将节点接地”,因此,我们使用接地符号来代表指向None的引用。将None作为next的初始值是不错的做法。

class Node:
    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

2.2 UnorderedList类

如前所述,无序列表是基于节点集合来构建的,每一个节点都通过显式的引用指向下一个节点。只要知道第一个节点的位置(第一个节点包含第一个元素),其后的每一个元素都能通过下一个引用找到。因此,UnorderedList类必须包含指向第一个节点的引用。注意,每一个列表对象都保存了指向列表头部的引用

UnorderedList类的构造方法如下:

class UnorderedList:
    def __init__(self):
        self.head=None

最开始构建列表时,其中没有元素。与在Node类中一样,特殊引用值None用于表明列表的头部没有指向任何节点。列表的头部指向包含列表的第一个元素的节点,这个节点包含指向下一个节点(元素)的引用,依此类推。非常重要的一点是,列表类本身并不包含任何节点对象,而只有指向整个链表结构中第一个节点的引用。

isEmpty方法如下:

def isEmpty(self):
    return self.head==None

isEmpty方法检查列表的头部是否为指向None的引用。布尔表达式self.head==None当且仅当链表中没有节点才为真。由于新的链表是空的,因此构造方法必须和检查是否为空保持一致。这体现了使用None表示链表末尾的好处。在Python中,None可以和任何引用进行比较。如果两个引用都指向同一个对象,那么它们就是相等的。

由于链表只提供一个入口(头部),因此其他所有节点都只能通过第一个节点以及next链表来访问。这意味着添加新节点最简便的位置就是头部,或者说链表的起点。我们把新元素作为列表的第一个元素,并且把已有的元素链接到该元素的后面。

add方法如下:

def add(self,item):
    temp=Node(item)
    temp.setNext(self.head)
    self.head=temp

由于头节点是唯一指向列表节点的外部引用,因此,如果颠倒第3行和第4行的顺序,所有的已有节点都将丢失并且无法访问

接下来要实现的方法——length、search以及remove——都基于链表遍历这个技术。遍历是指系统地访问每一个节点,具体做法是用一个外部引用从列表的头节点开始访问。随着访问每一个节点,我们将这个外部引用通过“遍历”下一个引用来指向下一个节点。

length方法:

def length(self):
    current=self.head
    count=0
    while current!=None:
        count=count+1
        current=current.getNext()
    return count

search方法:

def search(self,item):
    current=self.head
    found=False
    while current!=None and not found:
        if current.getData()==item:
            found=True
        else:
            current=current.getNext()
    return found

remove方法:

def remove(self,item):
    current=self.head
    previous=None
    found=False
    while not found:
        if current.getData()==item:
            found=True
        else:
            previous=current
            current=current.getNext()
    if previous==None:
        self.head=current.getNext()
    else:
        previous.setNext(current.getNext())

三、有序列表抽象数据类型

在有序列表中,元素的相对位置取决于它们的基本特征。它们通常以升序或者降序排列,并且我们假设元素之间能进行有意义的比较。有序列表的众多操作与无序列表的相同。

  • OrderedList()创建一个空的有序列表。它不需要参数,且会返回一个空列表。
  • add(item)假设item之前不在列表中,并向其中添加item,同时保持整个列表的顺序。它接受一个元素作为参数,无返回值。
  • remove(item)假设item已经在列表中,并从其中移除item。它接受一个元素作为参数,并且修改列表。
  • search(item)在列表中搜索item。它接受一个元素作为参数,并且返回布尔值。
  • isEmpty()检查列表是否为空。它不需要参数,并且会返回布尔值。
  • length()返回列表中元素的个数。它不需要参数,并且返回一个整数。
  • index(item)假设item已经在列表中,并返回该元素在列表中的位置。它接受一个元素作为i参数,并返回该元素的下标。
  • pop()假设列表不为空,并移除列表中的最后一个元素。它不需要参数,且会返回一个元素。
  • pop(pos)假设在指定位置pos存在元素,并移除该位置上的元素。它接受位置参数,且会返回一个元素。

四、实现有序列表

class OrderedList:
    def __init__(self):
        self.head=None
    
    def search(self,item):
        current=self.head
        found=False
        stop=False
        while current!=None and not found and not stop:
            if current.getData()==item:
                found=True
            else:
                if current.getData()>item:
                    stop=True
                else:
                    current=current.getNext()
        return found
    
    def add(self,item):
        current=self.head
        previous=None
        stop=False
        while current!=None and not stop:
            if current.getData()>item:
                stop=True
            else:
                previous=current
                current=current.getNext()
        temp=Node(item)
        if previous==None:
            temp.setNext(self.head)
            self.head=temp
        else:
            temp.setNext(current)
            previous.setNext(temp)

因为isEmpty和length仅与列表中的节点数目有关,而与实际的元素值无关,所以这两个方法在有序列表中的实现与在无序列表中一样。同理,由于仍然需要找到目标元素并且通过更改链接来移除节点,因此remove方法的实现也一样。剩下的两个方法,search和add,需要做一些修改。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天下弈星~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值