提交 f36ede84 编写于 作者: W wizardforcel

3.3.

上级 c5bdd093
......@@ -158,3 +158,100 @@ Tree(3, Tree(1, Tree(0), Tree(1)), Tree(2, Tree(1), Tree(1, Tree(0), Tree(1))))
这个例子表明,表达式树可以使用树形结构编程表示。嵌套表达式和属性数据结构的联系在我们这一章稍后对解释器设计的讨论中起到核心作用。
## 3.3.3 集合
除了列表、元组和字典之外,Python 拥有第四种容器类型,叫做`set`。集合字面上遵循元素以花括号闭合的数学表示。重复的元素在构造中会移除。集合是无序容器,所以打印出来的顺序可能和元素在集合字面值中的顺序不同。
```py
>>> s = {3, 2, 1, 4, 4}
>>> s
{1, 2, 3, 4}
```
Python 的集合支持多种操作,包括成员测试、长度计算和标准的交集并集操作。
```py
>>> 3 in s
True
>>> len(s)
4
>>> s.union({1, 5})
{1, 2, 3, 4, 5}
>>> s.intersection({6, 5, 4, 3})
{3, 4}
```
除了`union``intersection`,Python 的集合还支持多种其它操作。断言`isdisjoint``issubset``issuperset`提供了集合比较。集合是可变的,并且可以使用`add`、·remove`、`discard`和`pop`一次修改一个元素。额外的方法提供了多元素的修改,例如`clear`和`update`。Python [集合文档](http://docs.python.org/py3k/library/stdtypes.html#set)十分详细并足够易懂。
**实现集合。**抽象上,集合是不同对象的容器,支持成员测试、取交、取并和附加操作。向集合添加元素会返回新的集合,它包含原始集合的所有元素,如果没有重复的话,也包含新的元素。并和交的运算返回出现在任意一个或两个集合中的元素构成的集合。就像任何数据抽象那样,我们可以随意实现任何集合表示上的任何函数,只要它们提供这种行为。
在这章的神域部分,我们会考虑三个实现集合的不同方式,它们在表示上不同。我们会刻画这些不同表示的效率。通过分析集合操作的增长读。我们也会使用这一章之前的`Rlist`和`Tree`类,它们可以编写用于集合元素操作的简单而优雅的递归解决方案。
**作为无序序列的集合。**一种集合的表示方式是看做没有出现多于一次的元素的序列。空集由空序列来表示。成员测试会递归遍历整个列表。
```py
>>> def empty(s):
return s is Rlist.empty
>>> def set_contains(s, v):
"""Return True if and only if set s contains v."""
if empty(s):
return False
elif s.first == v:
return True
return set_contains(s.rest, v)
>>> s = Rlist(1, Rlist(2, Rlist(3)))
>>> set_contains(s, 2)
True
>>> set_contains(s, 5)
False
```
这个`set_contains `的实现需要`Θ(n)`的时间来测试元素的成员性,其中`n`是集合`s`的大小。使用这个线性时间的成员测试函数,我们可以将元素添加到集合中,也是线性时间。
```py
>>> def adjoin_set(s, v):
"""Return a set containing all elements of s and element v."""
if set_contains(s, v):
return s
return Rlist(v, s)
>>> t = adjoin_set(s, 4)
>>> t
Rlist(4, Rlist(1, Rlist(2, Rlist(3))))
```
在设计表示中,一个问题是我们应该关注效率。队两个集合`set1`和`set2`取交需要成员测试,但是这一次每个`set1`的元素必须测试`set2`中的呈圆形,对于两个大小为`n`的集合,这会产生步骤数量上的平方增长度`Θ(n^2)`。
```py
>>> def intersect_set(set1, set2):
"""Return a set containing all elements common to set1 and set2."""
return filter_rlist(set1, lambda v: set_contains(set2, v))
>>> intersect_set(t, map_rlist(s, square))
Rlist(4, Rlist(1))
```
在计算两个集合的并时,我们必须小心不要两次包含任意一个元素。`union_set `函数也需要线性数量的成员测试,同样会产生包含`Θ(n^2)`步骤的过程。
```py
>>> def union_set(set1, set2):
"""Return a set containing all elements either in set1 or set2."""
set1_not_set2 = filter_rlist(set1, lambda v: not set_contains(set2, v))
return extend_rlist(set1_not_set2, set2)
>>> union_set(t, s)
Rlist(4, Rlist(1, Rlist(2, Rlist(3))))
```
**作为有序元组的集合。**一种加速我们的集合操作的方式是修改表示,使集合元素递增排列。为了这样做,我们需要一些方式来比较两个对象,使我们能判断哪个更大。Python 中,许多不同对象类型都可以使用`<``>`运算符比较,但是我们会专注于这个例子中的数值。我们会通过将元素递增排列来表示数值集合。
有序的一个优点会在`set_contains`体现:在检查对象是否存在时,我们不再需要扫描整个集合。如果我们到达了大于要寻找的元素的集合元素,我们就知道这个元素不在集合中:
```py
>>> def set_contains(s, v):
if empty(s) or s.first > v:
return False
elif s.first == v:
return True
return set_contains(s.rest, v)
>>> set_contains(s, 0)
False
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册