线性结构之---列表

什么是列表?

列表是一种简单强大的数据及结构,提供了丰富的操作接口

一种数据项按照相对位置存放的数据集,被称为无序表

例如:考试分数集合 “54,26,93,17,77,31”

如果用无序表表示就是[54,26,93,17,77,31]

无序表的操作

  • List() : 创建一个空列表
  • add(item) : 添加一个数据项
  • remove() : 从列表移除
  • search() : 在列表中查找item
  • isEmpty() : 返回列表是否为空
  • size() : 返回列表包含了多少数据项
  • append(item) : 添加一个数据项到末尾
  • index(item) : 返回数据项在表中的位置
  • insert(pos,item) : 将数据项插入到pos位置
  • pop() : 从列表末尾移除 

采用链表实现无序表

为了实现无序表,可以采用链表的方案。虽然列表数据结构要求保持数据项的前后相对位置,但这种前后位置的保持,并不要求数据项一次存放在连续的存储空间

如下图,数据项存放位置并没有规则,但如果在数据项之间建立链向指引,就可以保持其前后相对位置

链表的实现:节点Node

链表实现的最基本元素是节点,每个节点包含两个信息:数据项本事,以及指向下一个节点的引用信息

注意next为None的意义是没有下一个节点

可以采用连接节点的方式构建数据集来实现无序表

链表第一个和最后一个节点很重要,如果访问到链表中的所有节点,就必须从第一个节点开始沿着链表遍历下去

所以无序表必须要有对第一个节点的引用信息,设立一个属性head,保存对第一个节点的引用空表的head和None

随着数据项的加入,无序表的head始终指向链条的第一个节点

 

接下来,考虑如何实现向无序表中添加数据项,实现add方法

由于无序表并没有限定数据项之间的顺序,新加入的数据项可以加入到原表的任何位置,按照性能考虑,应添加到最容易加入到的位置上

由链表结构我们知道,要访问到整条链上的所有数据项,都必须从表头head开始沿着next链接逐个向后查询,所以添加新数据项最快捷的位置是表头,整个链表的首位置

​​​​​​​

add方法

按照下图的代码调用,形成链表,30是最先加入数据项,所以称为链表最后一个。

而54是最后加入的所以是第一个数据项

链表的实现:size

size:从链表头head开始遍历到表尾同时变量累加经过的节点个数

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

search

从链表头head开始遍历到表尾,同时判断当前节点的数据项是否目标

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

remove(item)

首先要找到item。这个过程跟search一样,但在删除节点时,需要特别的技巧

current指向的是当前匹配数据项的节点

而删除需要把前一个节点的next指向current的下一个节点

所以我们在search current的同时,还要维护前一个(previous)节点的引用

找到item之后,current指向item节点,previous指向前一个节点,开始执行删除,需要区分两种情况 1.current是首个节点;2.位于链条中间的节点

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

什么是有序表?

有序表是一种数据项依照其某可比性质(如整数大小,字母先后顺序)来决定在列表中的位置

越“小”的数据项越靠近列表的头,越靠“前”

基本操

  • Ordered​​​​​​​List() : 创建一个空列表
  • add(item) : 添加一个数据项
  • remove(item) : 从列表移除
  • search(item) : 在列表中查找item
  • isEmpty() : 返回列表是否为空
  • size() : 返回列表包含了多少数据项
  • pop(pos) : 从列表指定位置移除 

在实现有序表的时候,需要记住的是,数据项的相对位置,取决于他们之间的‘大小’比较

以整数数据项为例,(17,26,31,54,77,93)的链表形式如图

有序表的实现

同样采用链表方法实现

Node定义相同

OrderedList也设置一个head来保存链表表头的引用

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

对于isEmpty/size/remove这些方法,与节点的次序无关,所以其实现跟UnorderedList是一样的

search/add方法则需要有修改

 

search

在无序表的search中,如果需要查找数据项不存在,则会搜索整个链表,知道表尾

对于有序表来说,可以利用链表节点有序排列的特性,来为search节省不存在数据项的查找时间

一旦当前节点的数据项大于所要查找的数据项,则说明链表后面的已经不可能又要查找到的数据项,可以直接返回False

如我们要在下图查找数据项45

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

add方法

相比无序表,改变最大的方法add,因为add方法必须保证加入的数据项添加在合适的位置,已维护整个链表的有序性

比如在(17,26,54,77,93)的有序表中,加入数据项31,我们需要沿着链表,找到第一个比31大的数据项54,将31插入到54的前面

由于涉及到的插入位置是当前节点之前,而链表无法得到“前驱”节点的引用

所以要跟remove方法类似,引入一个previous的引用,跟随当前节点current

一旦找到首个比31大的数据项,previous就派上用场了

代码实现:

def add(self, item):
    current = self.head
    previous = None
    stop = False
    while current != None and 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)

链表实现的算法分析
对于链表复杂度的分析,主要是看相应的方法是否涉及到链表的遍历
对于一个包含节点数为n的链表
isEmpty是O(1),因为仅需要检查head是否为None
size是O(n),因为除了遍历到表尾,没有其它办法得知节点的数量
search/remove以及有序表的add方法,则是O(n),
因为涉及到链表的遍历,按照概率其平均操作的次数是n/2
无序表的add方法是O(1),因为仅需要插入到表头


链表实现的List,跟Python内置的列表数据类型,在有些相同方法的实现上的时间复杂度不同
主要是因为Python内置的列表数据类型是基于顺序存储来实现的,并进行了优化。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值