一、list的基本实现技术
在数据结构中,如果用python实现线性表,无疑要提到list,list是一种元素个数可变的线性表(而tuple是不变的表,不支持改变其内部状态的任何操作,其他与list性质类似),采用分离式技术实现的动态顺序表,表中元素保存在一块连续存储区内。实现约束有如下两点:
1、基于下标(位置)的高效元素访问和更新,时间复杂度是O(1)
2、允许任意添加元素,不可以出现由于表满而无法加入新元素的情况;而且在添加新元素之后,表对象标识不变。
在python的官方实现中,list的实现策略如下:
1、在建立空表(或很小的表)时,系统分配一块能容纳8个元素的存储区;
2、在执行insert或append等操作来扩充表时,如果元素区满就换一块4倍大的存储区,把所有元素copy过去;
3、如果当前的表已经“很大”(这里阈值为50000),系统将改变策略,换存储区时容量加倍,这是为了避免出现过多的空闲存储位置。
注:python没有提供检查一个list对象的当前存储块容量的操作,也没有设置容量的操作,一切与容量有关的处理都由Python解释器自动完成,这和c++、java等有很大的区别。优点是降低了编程的负担,避免人为操作可能引进的错误。但全部交给解释器来完成也限制了表的使用方式。
小练习:list的内置方法reverse,自己实现的方法:
1 def my_reverse(lst): 2 elems = lst 3 i,j = 0, len(elems)-1 4 while i <j: 5 elems[i], elems[j] = elems[j], elems[i] #这里交换元素写在一行,不需要设置中间的temp作为交换媒介 6 i,j = i+1, j-1 7 return elems 8 a = [1,2,3,4,5,"a"] 9 print a 10 print ' after my reverse',my_reverse(a)
二、单链表类的实现
单链表的基础知识就不往上贴了,下面贴个python实现的实现类
1、利用循环创建一个简单的单链表
1 # -*- coding:utf-8 -*- 2 ''' 3 简单的循环调用一个长度为10的单链表 4 ''' 5 class LNode: #实现单链表的节点类 6 def __init__(self,elem, next_=None): 7 self.elem = elem 8 self.next = next_ #以next_命名,避免与标准函数next重名,这是python的命名习惯 9 10 llist1 = LNode(1) 11 p = llist1 12 13 for i in range(2,11): 14 p.next = LNode(i) 15 p = p.next 16 17 p = llist1 #把链表的指针重新指向第一个节点 18 while p: 19 print p.elem 20 p = p.next
2、单链表类的实现
1 # -*- coding:utf-8 -*- 2 __author__ = 'webber' 3 '''单链表类的实现''' 4 5 class LNode: #实现单链表的节点类 6 def __init__(self,elem, next_=None): 7 self.elem = elem 8 self.next = next_ #以next_命名,避免与标准函数next重名,这是python的命名习惯 9 10 class LinkedListUnderflow(ValueError): #继承标准异常的子类ValueError 11 pass 12 13 class LList: 14 def __init__(self): 15 self._head = None 16 17 def is_empty(self): 18 return self._head is None 19 20 def prepend(self,elem): 21 self._head = LNode(elem,self._head) 22 23 def pop(self): 24 if self._head is None: #无结点,引发异常 25 raise LinkedListUnderflow("in pop") 26 ele = self._head.elem 27 self._head = self._head.next 28 return ele 29 30 def pop_last(self): #这里有两个特殊情况,表为空,或者表中只有一个元素,pop掉最后一个元素的时间复杂度为O(n) 31 if self._head is None: #空表,无结点,引发异常 32 raise LinkedListUnderflow("in pop_last") 33 p = self._head 34 if p.next is None: #表中只有一个元素 35 ele = p.elem 36 self._head = None 37 return ele 38 while p.next.next is not None: #直到p.next是最后的结点 39 p = p.next 40 ele = p.next.elem 41 p.next = None 42 return ele 43 44 def append(self, elem): 45 if self._head is None: 46 self._head = LNode(elem) 47 return 48 p = self._head 49 while p.next: 50 p = p.next 51 p.next = LNode(elem) 52 53 def printall(self): 54 p = self._head 55 while p: 56 print p.elem, 57 if p.next: 58 print ",", 59 p = p.next 60 print "" 61 62 mlist1 = LList() 63 print mlist1.is_empty() 64 for i in range(10): 65 mlist1.prepend(i) 66 for i in range(11,20): 67 mlist1.append(i) 68 mlist1.printall() 69 print mlist1.is_empty() 70 for i in range(5): 71 mlist1.pop() 72 print "pop 5 个数据之后:" 73 mlist1.printall()
3、表的遍历
python语言为内部汇集类型提供的遍历机制是迭代器,标准使用方式是放在for语句头部,在循环体中逐个处理汇集对象的元素,用yield实现。可在上面的单链表类中添加如下方法:
1 def elements(self): 2 p = self._head 3 while p is not None: 4 yield p.elem #返回结点元素 5 p = p.next 6 7 for i in mlist1.elements(): 8 print i,
筛选生成器:下面是一个筛选生成器的方法,可以将单链表中所有符合条件的结点元素返回,这里需要注意两点:一是关于yield和return的用法区别,yield使这个方法变成一个迭代器,每一次循环迭代器使用next方法返回一个值,而return如果执行的话,整个函数就结束了。二是这里在调用该方法时需要一个“判断谓词参数”,在python中可以使用lambda表达式定制这个操作参数,方法和调用如下:
1 def filter(self,pred): #筛选生成器 2 p = self._head 3 while p: 4 if pred(p.elem): 5 yield p.elem 6 p = p.next 7 8 for i in mlist1.filter(lambda i:i>10): #谓词参数,返回单链表中元素大于10的元素 9 print i,