数据结构( Pyhon 语言描述 ) — — 第5章:接口、实现和多态
- 接口
- 接口是软件资源用户可用的一组操作
- 接口中的内容是函数头和方法头,以及它们的文档
- 设计良好的软件系统会将接口与其实现分隔开来
- 多态
- 多态是在两个或多个类的实现中使用相同的运算符号、函数名或方法。多态函数的示例是 str 和 len。多态运算符是 + 和 ==。多态方法的示例是 add 和 isEmpty。
- 将接口与实现隔开的好处
- 降低了用户的学习难度
- 允许用户以即插即用的方式,快速的将资源整合起来
- 让用户有机会在相同资源的不同实现中做出选择
- 允许用户对资源的实现做出修改,而不影响用户代码
- 开发接口
- 包的接口
- 包是一种无序的集合
- 定义包接口
- 在选择方法名和函数名的时候,应该尽量遵从通用、习惯的用法
- 包接口中的函数名、方法名和运算符如下:
- isEmpty
- len
- str
- for…
- in
- +
- ==
- clear
- add
- remove
- 指定参数和返回值
- 对包接口进行优化,是为接口中的操作添加参数,并用考虑它们返回什么值( 如果有返回值的话 )
- 迭代器依赖于 iter 方法
- 包操作及其方法
用户的包操作 |
Bag类中的方法 |
b = <class name>( optional collection> ) |
__init__( self, sourceCollection = none ) |
b.isEmpty() |
isEmpty( self ) |
len(b) |
__len__( self ) |
str( b ) |
__str__( self ) |
item in b |
__contains___( self, item ): 如果包含了__iter__,就不需要该方法 |
b1 + b2 |
__add__( self, other ) |
b == anyObject |
__eq__( self, other ) |
b.clear() |
clear( self ) |
b.add( item ) |
add( self, item ) |
b.remove( item ) |
remove( self, item ) |
- 构造方法和实现类
- 数组包
- 链表包
- 先验条件、后验条件、异常和文档
- 文档字符串
- 个引号括起来的字符串
- 个字符串
- 一个方法,如查没有什么可能的错误条件的话,文档字符串只用说明方法的参数是什么、返回值是什么、以及方法执行了什么样的操作
- 更加详细的文档形式
- 先验条件 ( Precondition )
- 是一条语句,只有该语句为真的时候,方法才能正常运行
- 后验条件( Postcondition )
- 当方法执行完毕后,什么条件会为真
- 异常
- 说明可能发生的异常,通常是无法满足方法的先验条件所致
- 示例
def remove( self, item ):
"""
Preconditon: item is in self.
Raise: KeyError if item is not in self.
Postcondition: item is removed from self.
"""
- 用 Python 编写接口
- 一些语言,如 Java 提供了编写接口的方法。Python 没有这样的方法,但是可以通过提供文档并指导类的开发,从而模拟类似的功能
- 为了创建接口,使用文档来列出每一个方法头,并且用一条单个的 pass 或 return 语句来结束每一个方法
- 示例
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Lijunjie
"""
File: baginterface.py
Author: Lijunjie
"""
class BagInterface( object ):
"""Interface for all bag types."""
#Constructor
def __init__( self, sourceCollection = None ):
"""Sets the initial state of self, which includes the contents
of sourceCollection, if it's present."""
pass
#Accessor methods
def isEmpty( self ):
"""Return True if len( self ) == 0, or False otherwise."""
return True
def __len__( self ):
"""Returns the number of items in self."""
def __str__( self ):
"""Return the string representation of self."""
return ""
def __iter__( self ):
"""Supports iteration over a view of self."""
return None
def __add__( self, other ):
"""Return a new bag containing the contents of self and other"""
return None
def __eq__( self, other ):
"""Return True if self equals other, otherwise False."""
return False
#Mutator methods
def clear( self ):
"""Makes self become empty."""
pass
def add( self, item ):
"""Adds item to self."""
pass
def remove( self, item ):
"""
Precondition: item is in self.
Raise: KeyError if item is not in self.
Postcondition: item is removed form self.
"""
pass
- 开发一个基于数组的实现
- 集合类的设计确定接口后,类自身的设计和实现包含两个步骤
- 选择一个合适的数据结构来包含集合的项,并且确定可能需要表示集合状态的任何其他数据。将这些数据赋值给__init__方法中的实例变量
- 完成接口中相关方法的代码
- 选择并初始化数据结构
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Lijunjie
"""
File: arraybag.py
Author: Lijunjie
"""
from arrays import Array
class ArrayBag( object ):
"""An array-based bag implementation."""
#Class variable
#Constructor
def __init__( self, sourceCollection = None ):
"""Sets the initial state of self, which includes the contents
of sourceCollection, if it's present."""
self._items = Array( ArrayBag.DEFAULT_CAPACTIY )
if sourceCollection:
for item in sourceCollection:
self.add( item )
- 先完成容易完成的方法
- 应该尽可能的在 self 上调用方法或函数,而不是直接使用实例变量
- 代码示例
#Accessor methods
def isEmpty( self ):
"""Return True if len( self ) == 0, or False otherwise."""
def __len__( self ):
"""Returns the number of items in self."""
return self._size
#Mutator methods
def clear( self ):
"""Makes self become empty."""
self._items = Array( ArrayBag.DEFAULT_CAPACTIY )
def add( self, item ):
"""Adds item to self."""
#Check array memory here and increase it if necessary.
self._items[len( self )] = item
- 完成迭代器
- __str__,__add__和__eq__等方法,都需要借助 __iter__方法来正确运行
- __iter__通过 yield 语句,将每一项都发送给 for 循环调用
def __iter__( self ):
"""Supports iteration over a view of self."""
while cursor < len( self ):
yield self._items[cursor]
- 完成使用迭代器的方法
- __str__函数
def __str__( self ):
"""Return the string representation of self."""
return "{" + ", ".join( map( str, self ) ) + "}"
- __add__函数
def __add__( self, other ):
"""Return a new bag containing the contents of self and other"""
result = ArrayBag( self )
for item in other:
result.add( item )
return result
- __eq__函数
def __eq__( self, other ):
"""Return True if self equals other, otherwise False."""
if self is other: return True
if type( self ) != type( other ) or len( self ) != len( other ):
return False
for item in self:
if not item in other:
return False
return True
- in 运算符和 __contains__ 方法
- in 运算符对应 __contains__ 方法
- 当类中不包含这个方法时,这个方法会在 self 上使用 for 循环,并进行一次顺序搜索
- 完成 remove 方法
def remove( self, item ):
"""
Precondition: item is in self.
Raise: KeyError if item is not in self.
Postcondition: item is removed form self.
"""
if not item in self:
raise KeyError( str(item) + " not in bag." )
#Search for index of target item.
for targetItem in self:
if targetItem == item:
break
#Shift items
for i in range( targetIndex, len( self ) - 1 ):
]
#Decrement logical size
#Check array memory here and decrease it if necessary
- 开发一个基于链表的实现
- 之前开发的 ArrayBag 类中的 __isEmpyt__,__len__,__add__,__eq__和__str__并没有直接访问数组变量,因此在 LinkedBag 类中,可以不进行修改。
- 初始化数据结构
"""
File: linkedbag.py
Author: Lijunjie
"""
from node import Node
class LinkedBag( object ):
"""An link-based bag implementation."""
#Constructor
def __init__( self, sourceCollection = None ):
"""Sets the initial state of self, which includes the contents
of sourceCollection, if it's present."""
self._items = None
if sourceCollection:
for item in sourceCollection:
self.add( item )
- 完成迭代器
def __iter__( self ):
"""Supports iteration over a view of self."""
cursor = self._items
while not cursor is None:
yield cursor.data
cursor = cursor.next
- 完成 clear 和 add 方法
- clear方法
def clear( self ):
"""Makes self become empty."""
self._items = None
- add 方法
def add( self, item ):
"""Adds item to self."""
self._items = Node( item, self._items )
- 完成 remove 方法
def remove( self, item ):
"""
Precondition: item is in self.
Raise: KeyError if item is not in self.
Postcondition: item is removed form self.
"""
if not item in self:
raise KeyError( str(item) + " not in bag." )
#Search for the node containing target item.
#probe will point to the target node, and trailer will point to
#the one before it, if it exists.
probe = self._items
trailer = None
for targetItem in self:
if targetItem == item:
break
trailer = probe
probe = probe.next
# Unhook the node to be deleted, either the first one or the
#one thereafter
if probe == self._items:
self._items = self._items.next
else:
trailer.next = probe.next
#Decrement logical size
- 两个包实现的运行时性能
- in 和 remove 操作由于加入了顺序搜索,因此都是线性时间
- == 操作符默认的时间复杂度为
- 剩下的操作都是常数时间,除了 ArrayBag 需要调整数组长度的情况
- 当 ArrayBag 数组的装填因子超过 0.5 时,其内存占用要比相同逻辑大小的 LinkedBag 要小
- 测试两个包的实现
- 测试代码
##!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Lijunjie
"""
FIle: testbag.py
Author: Lijunjie
A test program for bag implementations.
"""
from arraybag import ArrayBag
from linkedbag import LinkedBag
def test( bagType ):
"""Expects a bag type as argument and runs some tests on objects
of that type. """
]
print( "The list of items added is:", lyst )
b1 = bagType( lyst )
print( "Expect 3:", len( b1 ) )
print( "Expect the bag's string:", b1 )
print( "Expect True:", 2018 in b1 )
print( "Expect False:", 2013 in b1 )
print( "Expect the items on spearate lines:" )
for item in b1:
print( item )
b1.clear()
print( "Expect {}:", b1 )
b1.add( 25 )
b1.remove( 25 )
print( "Expect {}:", b1 )
b1 = bagType( lyst )
b2 = bagType( b1 )
print( "Expect True:", b1 == b2 )
print( "Expect False:", b1 is b2 )
print( "Expect two of each items:", b1 + b2 )
for item in lyst:
b1.remove( item )
print( "Expect crash with keyError:" )
b2.remove( 99 )
if __name__ == "__main__":
#test( ArrayBag )
test( LinkedBag)
- 用 UML 图表示包资源
- 统一建模语言( Unified Modeling Language, UML )
- 带有一个接口和两个实现类的一个类图
- 聚合和组合关系
- 每个 LinkedBag 对象都聚合了 0 个或多个节点
- 每个 ArrayBag 对象都是单个 Array 对象的组合
- 组合是整体—部分关系,而聚合是一对多的关系
- 示意图
数据结构( Pyhon 语言描述 ) — — 第5章:接口、实现和多态的更多相关文章
- 数据结构( Pyhon 语言描述 ) — —第10章:树
树的概览 树是层级式的集合 树中最顶端的节点叫做根 个或多个后继(子节点). 没有子节点的节点叫做叶子节点 拥有子节点的节点叫做内部节点 ,其子节点位于层级1,依次类推.一个空树的层级为 -1 树的术 ...
- 数据结构( Pyhon 语言描述 ) — —第9章:列表
概念 列表是一个线性的集合,允许用户在任意位置插入.删除.访问和替换元素 使用列表 基于索引的操作 基本操作 数组与列表的区别 数组是一种具体的数据结构,拥有基于单个的物理内存块的一种特定的,不变的实 ...
- 数据结构( Pyhon 语言描述 ) — — 第7章:栈
栈概览 栈是线性集合,遵从后进先出原则( Last - in first - out , LIFO )原则 栈常用的操作包括压入( push ) 和弹出( pop ) 栈的应用 将中缀表达式转换为后缀 ...
- 数据结构( Pyhon 语言描述 ) — — 第8章:队列
队列概览 队列是线性的集合 队列的插入限制在队尾,删除限制在队头.支持先进先出协议( FIFIO, first-in first-out ) 两个基本操作 add:在队尾添加一项 pop:从队头弹出一 ...
- 数据结构( Pyhon 语言描述 ) — — 第6章:继承和抽象类
继承 新的类通过继承可以获得已有类的所有特性和行为 继承允许两个类(子类和超类)之间共享数据和方法 可以复用已有的代码,从而消除冗余性 使得软件系统的维护和验证变得简单 子类通过修改自己的方法或者添加 ...
- 数据结构( Pyhon 语言描述 ) — — 第3章:搜索、排序和复杂度分析
评估算法的性能 评价标准 正确性 可读性和易维护性 运行时间性能 空间性能(内存) 度量算法的运行时间 示例 """ Print the running times fo ...
- 数据结构( Pyhon 语言描述 ) — — 第2章:集合概览
集合类型 定义 个或多个其他对象的对象.集合拥有访问对象.插入对象.删除对象.确定集合大小以及遍历或访问集合的对象的操作 分类 根据组织方式进行 线性集合 线性集合按照位置排列其项,除了第一项,每一项 ...
- 数据结构( Pyhon 语言描述 ) — — 第4章:数据和链表结构
数据结构是表示一个集合中包含的数据的一个对象 数组数据结构 数组是一个数据结构 支持按照位置对某一项的随机访问,且这种访问的时间是常数 在创建数组时,给定了用于存储数据的位置的一个数目,并且数组的长度 ...
- 数据结构( Pyhon 语言描述 ) — —第11章:集和字典
使用集 集是没有特定顺序的项的一个集合,集中的项中唯一的 集上可以执行的操作 返回集中项的数目 测试集是否为空 向集中添加一项 从集中删除一项 测试给定的项是否在集中 获取两个集的并集 获取两个集的交 ...
随机推荐
- python异常之EOFError: Ran out of input
出现该问题一般是由于你在以写模式打开文件后未关闭的情况下又去以读模式操作该文件时报的错误 # coding = utf-8 import pickle #定义一个boy类 class boy(): d ...
- [题解](堆)luogu_P1631序列合并
思路来自题解 作者: Red_w1nE 更新时间: 2016-11-13 20:46 在Ta的博客查看 72 最近有点忙 没时间贴代码了== [分析] 首先,把A和B两个序列分别从小到大排序,变成两 ...
- UWP 切换语言
关于UWP切换语言的具体可以看这篇.http://www.cnblogs.com/hupo376787/p/7775291.html 这里我就记录一些自己的. 目前大多数软件用的都是利用文本资源文件来 ...
- BZOJ2440(容斥+莫比乌斯函数)
题目本质: 首先有如下结论: 而通过写一写可以发现: 举例来讲,36及其倍数的数,会被1的倍数加一遍,被4的倍数扣一遍,会被9的倍数扣一遍,而为了最终计数为0,需要再加回来一遍,所以在容斥里面是正号. ...
- 转 PHP 正则表达式 以及案例
2.Perl兼容的语法扩充 Perl兼容的正则表达式的模式类似于Perl中的语法,表达式必须包含在定界符中,除数字.字母.反斜线外的任何字符都可以作为定界符.例如,表达式’/^(?i)php[34]/ ...
- JDK原子类操作
JDK原子类操作及原理 在JDK5之后,JDK提供了对变量的原子类操作, java.util.concurrent.atomic里都是原子类 原子类的分类 原子更新基本类型 原子更新数组 原子更新抽象 ...
- 寻找最美的你(select)
Time Limit:2000ms Memory Limit:128MB 题目描述 这个问题是这样的,如果一个区间[L,R]存在一个数ai,使得这个数是这个区间所有数的约数,那么[L,R]这段区间 ...
- java mongodb-crud
本篇文章主要介绍了mongodb对应java的常用增删改查的api,以及和spring集成后mongoTemplate的常用方法使用,废话不多说,直接上代码: 1.首先上需要用到的两个实体类User和 ...
- MoveWindow和SetWindowPos
SetWindowPos即使里面使用的是一样的矩形参数,有时候SetWindowPos还是会改变窗口的大小,真是坑爹!!! MoveWindow就不会改变 mark一下
- Android Studio报错Unable to resolve dependency for ':app@release/compileClasspath':无法引用任何外部依赖的解决办法
Android Studio 在引用外部依赖时,发现一直无法引用外部依赖.刚开始以为是墙的问题,尝试修改Gradle配置,未解决问题. 最终发现原来是在Android Sudio安装优化配置时,将Gr ...