Data Structures and Algorithms Python - 3、序列
Created at 2016-09-15 Updated at 2018-05-01 Category Data Structures and Algorithms
问题
数据序列是如何维护的,哪个组织方案最合适
为何在不同类型的序列中,选择了这个,而没有选那个
列表,链表,栈,队列的有趣算法
哪个排序算法更常用
哪个查找算法更合适
列表
无论列表有多大,访问列表中每个位置的时间是一样的。RAM的全称是Random Access Memory,所谓的随机存取,是指存储器中的数据被读取或写入时,所需要的时间与这段信息所在的位置或所写的位置无关。如果是Sequential Access设备,那么所需的时间就与位置有关。
1 | class PyList: |
这里构建了一个列表,它有10个None值。None代表这个引用指向nothing。
实现了加法操作符,可以将两个PyList连接在一起。
append方法,会在容量不够的时候增加容量,每次增加25% 。Python 中的List的容量也是这样增加的,4,8,16,25,35,46,58,72,88
insert方法,会在容量不够的时候增加容量。会导致指定索引之后的数字,往后移动。
delitem方法,可以通过 del list[10] 这样的方法,删除元素。该元素之后的元素统统往前移动,中间不能留空隙。在Python解释器中,为了节省空间,如果删除后,元素的个数比容量小一半,那么会从可用空间中减少一半的容量。
contains中的查找算法,叫做线性查找。
Python中有两个方法可以将对象转换为字符串,一个是str,一个是repr。
Python中有一个evaluate函数,可以评估字符串表达式,例如
1 | eval("1+2") |
它的结果是3。repr方法就是将对象呈现为适用eval函数的版本。
1 | listA=PyList(['a','b','c']) |
这里,我们注意到str和repr方法中,repr是作用到每个元素身上了。这一点非常必要。不然的话,str或repr会将[“a”,”b”]表示为[a,b]
克隆对象
可以看到listA被克隆了,eval(repr(x))这样的克隆,被叫做对对象x的deep clone或deep copy。
1 | #浅拷贝 |
有deep copy,当然也有shallow copy。浅拷贝,是指x和y这两个对象,共享着item1,item2,item3。
多数情况下,元素是不是共享的,都不是太重要。就像上面的例子中,1,2,3是integer,integer是不可变的。
如果共享的是可变元素,那就要非常小心了。在shallow clone中,如果集合的元素是可变的,那么对克隆对象的元素的更改,也会影响到该集合。这种情况在deep clone中就不会发生。
Shallow clone和deep clone不能简单地说哪一个更好,都要取决于应用。deep clone需要额外的性能和存储,但是更安全。
元素排序
通过实现lessthen方法,可以调用sort进行排序。
1 | list1=[1,2,3] |
list1和list3没法比较,因为一个是integer,一个是string。
list1和list3可以比较,因为还没比到3和’a’,就已经分出大小了。
内建的int,float,str都已经实现了lessthen,我们可以直接用。而像dict类型,就没有,需要自己去定义。
Selection Sort
选择排序就是做线性搜索,找到最小的元素,把它放到开始的位置。
1 | def select(seq,start): |
Merge Sort,归并排序
Divide and Conquer,分而治之。将一个问题分成两部分,分别处理每一部分。因为每一小部分比整体更小,所以更易于处理。归并算法可以这样理解:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69#待排序数组:
List([1,6,4,3,5,2])
#第一次分割(其实分割的只是索引,比如 0-2一组,3-5一组,并非将原数组变成了2个新的数组。
#这里为了可视化效果,把索引范围对应的元素,列为一个单独的数组):
#索引分割为:
[0,1,2], [3,4,5]
#可视化效果
[1,6,4], [3,5,2]
#第二次分割:
#对应的索引分割为:
[0],[1,2], [3],[4,5]
#可视化效果
[1],[6,4], [3][5,2]
#全部分割成含有1个元素或2个元素的数组,分割的工作就完成了
#对每个数据内部的元素进行排序。排序的方法同下面数组间排序的方法一样,可视化效果:
[1],[4,6], [3],[2,5]
#到这里,原数组变为
List([1,4,6,3,2,5])
#接着,排序索引为[0,1,2]的两个数组。
#分别从[1] 和[4,6] 这两个数组中,取出第一个元素,进行比较,把小的元素拷贝到一个新的数组中,直到有一个数组先到头
min(1,4)=> newList([1])
#接着,把新生成的数组中的元素,从开始位置,依次替换原数组中的元素
List[0]=newList[0]
#原数组的可视化效果变为
List([1,4,6,3,2,5])
#接着,排序索引为[3,4,5]的两个数组。
#也就是[3] 和 [2,5]
min(3,2)=> newList([2])
min(3,5)=> newList([2,3])
#接着,把新生成的数组中的元素,从开始位置,依次替换原数组中的元素
List[3]=newList[0]
List[4]=newList[1]
#原数组的可视化效果变为
List([1,4,6,2,3,5])
#接着,排序索引为[0,1,2,3,4,5]的两个数组。
#也就是[1,4,6] 和 [2,3,5]
min(1,2)=> newList([1])
min(4,2)=> newList([1,2])
min(4,3)=> newList([1,2,3])
min(4,5)=> newList([1,2,3,4])
min(6,5)=> newList([1,2,3,4,5])
#如果比较完,左边的数组中还有元素,就把左边数组中的元素全部加入到newList中
[6]=> newList([1,2,3,4,5,6])
#接着,把新生成的数组中的元素,从开始位置,依次替换原数组中的元素
List[0]=newList[0]
List[1]=newList[1]
List[2]=newList[2]
List[3]=newList[3]
List[4]=newList[4]
List[5]=newList[5]
#原数组的可视化效果变为
List([1,2,3,4,5,6])
算法如下:
1 | def merge(seq,start,mid,stop): |
Quicksort,快速排序
Magic Method | When it gets invoked (example) | Explanation |
---|---|---|
__new__(cls [,…]) | instance = MyClass(arg1, arg2) | __new__ is called on instance creation |
__init__(self [,…]) | instance = MyClass(arg1, arg2) | __init__ is called on instance creation |
__cmp__(self, other) | self == other, self > other, etc. | Called for any comparison |
__pos__(self) | +self | Unary plus sign |
__neg__(self) | -self | Unary minus sign |
__invert__(self) | ~self | Bitwise inversion |
__index__(self) | x[self] | Conversion when object is used as index |
__nonzero__(self) | bool(self) | Boolean value of the object |
__getattr__(self, name) | self.name # name doesn’t exist | Accessing nonexistent attribute |
__setattr__(self, name, val) | self.name = val | Assigning to an attribute |
__delattr__(self, name) | del self.name | Deleting an attribute |
__getattribute__(self, name) | self.name | Accessing any attribute |
__getitem__(self, key) | self[key] | Accessing an item using an index |
__setitem__(self, key, val) | self[key] = val | Assigning to an item using an index |
__delitem__(self, key) | del self[key] | Deleting an item using an index |
__iter__(self) | for x in self | Iteration |
__contains__(self, value) | value in self, value not in self | Membership tests using in |
__call__(self [,…]) | self(args) | “Calling” an instance |
__enter__(self) | with self as x: | with statement context managers |
__exit__(self, exc, val, trace) | with self as x: | with statement context managers |
__getstate__(self) | pickle.dump(pkl_file, self) | Pickling |
__setstate__(self) | data = pickle.load(pkl_file) | Pickling |