Python数据结构与算法20:基本结构:有序表及其实现

:本文如涉及到代码,均经过Python 3.7实际运行检验,保证其严谨性。

本文阅读时间约为5分钟

有序表Ordered List的介绍

前面介绍了无序表,这一节介绍的是与无序表相对的有序表(Ordered List)。

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

数值越小的数据项就越靠近列表的“头”(head),越靠前;数值越大的数据项就越远离列表的“头”(head)。换句话说,有序表是按数值从小到大排序的。如 Pic-315-1 有序表的示意图 所示:

Pic-315-1 有序表的示意图

Ordered List所定义的操作如下:

  • Ordered List()——创建一个新的有序表。
  • .add(item)——在表中添加一个数据项,并保持整体顺序,此项原不存在。
  • .remove(item)——从有序表中移除一个数据项,此项应存在,有序表被修改。
  • .search(item)——从有序表中查找数据项,以布尔值形式返回是否存在的结果。
  • .isEmpty()——是否空表。
  • .size()——返回表中数据项的个数。
  • .index(item)——返回数据项在表中的位置,此项应该存在。
  • .pop()——移除并返回有序表中最后一项,表中应至少存在一项。
  • .pop(pos)——移除并返回有序表中指定位置的数据项,此位置应存在。
  • .items——返回表中所有的元素。
有序表Ordered List的实现

有序表的实现同样采用链表方法实现。实现的时候,需要记住数据项的相对位置取决于它们之间的大小比较。

有序表适用于一切可比较性质的数据类型,也就是Python中所有定义了gt方法(即'>'操作符)的数据类型。

节点(Node)定义与我们此前学过的无序表时的节点(Node)的定义相同,所以可以把节点的定义拿过来直接使用。

OrderedList也设置了一个head来保存链表表头的引用,这一点也与无序表相同,如下代码所示:

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

至于.isEmpty、.size、.remove这些方法,与节点的次序无关,所以其实现与无序表是一样的。
相比无序表,需要修改的,只有.search()方法和.add()方法。

有序表的.search()和.add()方法

有序表中的.search()方法,与无序表需要遍历整个链表不同,可以根据有序排列的特性,节省不存在数据项的查找时间。比如要找24这个数据项,我们知道不可能在23及前面的整数里面找到。

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

.search()和.add()方法的具体实现及其详细注释见下面代码:

# 有序表的.search方法。
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

#有序表的.add方法。
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)
链表实现的算法分析

对于链表复杂度的分析,主要是看相应的方法是否涉及到链表的遍历。

对于一个包含节点数为n的链表,其各方法的时间复杂度为:

  • .isEmpyt是O(1),仅需要检查head是否为None。
  • .size是O(n),除了遍历到表尾,没有其它办法得知节点的数量。
  • .search/.remove以及有序表的.add方法则是O(n),涉及到链表的遍历,按照概率其平均操作的次数是n/2。
  • 无序表的.add方法是O(1),因为仅需要插入到表头。

以上就是基于链表实现的List(有序表和无序表)。可以发现,它们和Python内置的列表数据类型,在有些相同功能的方法上,时间复杂度有差异。这是因为,Python内置的列表数据类型是基于顺序存储实现的,并进行了某些优化。

To be continued.

你可能感兴趣的:(Python数据结构与算法20:基本结构:有序表及其实现)