Author: 楚格
2018-11-19 19:05:11
IDE: Pycharm2018.02 Python 3.7
KeyWord : Data Structures and Algorithm Analysis
Explain:
---------------------------------------------
---------
1 # coding=utf-8
2 #---------------------------------
3 '''
4 # Author : chu ge
5 # Function: Data Structures and Algorithm Analysis
6 #
7 '''
8 #---------------------------------
9 '''
10 # --------------------------------
11 # 导入模块
12 # 1.系统库
13 # 2.第三方库
14 # 3.相关定义库
15 # --------------------------------
16 '''
17 # 1.系统库
18 import sys
19 import os
20 import time
21 import timeit # 性能分析
22 from timeit import Timer
23
24 #2.第三方库
25
26
27 #
28 '''
29 ============================================================================
30 #》》》》》》》》》》》》》》
31
32 Data Structures and Algorithm Analysis
33
34 ----------------------------------------------
35 1. 概念
36 -----------------------
37 #
38 e.g:
39 if __name__ == "__main__":
40 result:
41 -----------------------
42 1.1 第一次尝试
43
44 -----------------------
45 1.2算法的提出
46
47 算法是独立存在的一种解决问题的方法和思想。
48 对于算法而言,实现的语言并不重要,重要的是思想。
49
50 算法的五大特性
51 有输入: 算法具有0个或多个输入
52 有输出: 算法至少有1个或多个输出
53 有穷性: 算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成
54 确定性: 算法中的每一步都有确定的含义,不会出现二义性
55 可行性: 算法的每一步都是可行的,也就是说每一步都能够执行有限的次数完成
56
57 -----------------------
58 1.3 第二次尝试
59
60 -----------------------
61 1.4 算法效率衡量
62
63 执行时间反应算法效率
64 对于同一问题,我们给出了两种解决算法,在两种算法的实现中,
65 我们对程序执行的时间进行了测算,发现两段程序执行的时间相差悬殊
66 (214.583347秒相比于0.182897秒),
67 由此得出结论:实现算法程序的执行时间可以反应出算法的效率,即算法的优劣。
68
69 时间复杂度与“大O记法”
70 我们假定计算机执行算法每一个基本操作的时间是固定的一个时间单位,
71 那么有多少个基本操作就代表会花费多少时间单位。
72 算然对于不同的机器环境而言,确切的单位时间是不同的,
73 但是对于算法进行多少个基本操作(即花费多少时间单位),在规模数量级上却是相同的,
74 由此可以忽略机器环境的影响而客观的反应算法的时间效率。
75
76
77 对于算法的时间效率,我们可以用“大O记法”来表示。
78 “大O记法”:
79 对于单调的整数函数f,如果存在一个整数函数g和实常数c>0,使得对于
80 充分大的n总有f(n)<=c*g(n),就说函数g是f的一个渐近函数(忽略常数),
81 记为f(n)=O(g(n))。也就是说,在趋向无穷的极限意义下,
82 函数f的增长速度受到函数g的约束,亦即函数f与函数g的特征相似。
83
84 时间复杂度:
85 假设存在函数g,使得算法A处理规模为n的问题示例所用时间为
86 T(n)=O(g(n)),则称O(g(n))为算法A的渐近时间复杂度,简称时间复杂度,记为T(n)
87
88
89 如何理解“大O记法”
90 对于算法进行特别具体的细致分析虽然很好,但在实践中的实际价值有限。
91 对于算法的时间性质和空间性质,最重要的是其数量级和趋势,
92 这些是分析算法效率的主要部分。而计量算法基本操作数量的规模函数中,
93 那些常量因子可以忽略不计。例如,可以认为3n2和100n2属于同一个量级,
94 如果两个算法处理同样规模实例的代价分别为这两个函数,
95 就认为它们的效率“差不多”,都为n2级。
96
97
98 最坏时间复杂度
99
100 分析算法时,存在几种可能的考虑:
101 算法完成工作最少需要多少基本操作,即最优时间复杂度。
102 算法完成工作最多需要多少基本操作,即最坏时间复杂度。
103 算法完成工作平均需要多少基本操作,即平均时间复杂度。
104 对于最优时间复杂度,其价值不大,因为它没有提供什么有用信息,
105 其反映的只是最乐观最理想的情况,没有参考价值。
106 对于最坏时间复杂度,提供了一种保证,表明算法在此种程度的基本操作中一定能完成工作。
107 对于平均时间复杂度,是对算法的一个全面评价,因此它完整全面的反映了这个算法的性质。
108 但另一方面,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。
109 而且,对于平均情况的计算,也会因为应用算法的实例分布可能并不均匀而难以计算。
110 因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。
111
112
113
114 时间复杂度的几条基本计算规则:
115
116 基本操作,即只有常数项,认为其时间复杂度为O(1)
117 顺序结构,时间复杂度按加法进行计算
118 循环结构,时间复杂度按乘法进行计算
119 分支结构,时间复杂度取最大值
120 判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略
121 在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度
122
123 -----------------------
124 1.7 python 内置类型性能分析
125
126 timeit模块
127 timeit模块可以用来测试一小段Python代码的执行速度。
128
129 class timeit.Timer(
130 stmt='pass',
131 setup='pass',
132 timer=<timer function>
133 )
134 Timer:是测量小段代码执行速度的类。
135 stmt:参数是要测试的代码语句(statment);
136 setup:参数是运行代码时需要的设置;
137 timer:参数是一个定时器函数,与平台有关。
138
139 #通常使用
140 timeit.Timer.timeit(number=1000000)
141
142 Timer:类中测试语句执行速度的对象方法。可替换!!!
143 number:参数是测试代码时的测试次数,默认为1000000次。
144 方法返回执行代码的平均耗时,一个float类型的秒数。
145
146 e.g:
147
148 def Function_Test_A():
149 l = []
150 for i in range(1000):
151 l = l + [i]
152
153 def Function_Test_B():
154 l = []
155 for i in range(1000):
156 l.append(i)
157
158 def Function_Test_C():
159 l = [i for i in range(1000)]
160
161 def Function_Test_D():
162 l = list(range(1000))
163
164 if __name__ == "__main__":
165 # 固定格式
166 #创建对象:函数名 测试代码语句 运行代码设置
167 time_A = Timer("Function_Test_A()", "from __main__ import Function_Test_A")
168 # 执行速度设置 固定格式
169 print("time_A:", time_A.timeit(number=100), "seconds")
170
171 time_B = Timer("Function_Test_B()", "from __main__ import Function_Test_B")
172 print("time_B ", time_B.timeit(number=100), "seconds")
173 time_C = Timer("Function_Test_C()", "from __main__ import Function_Test_C")
174 print("time_C ", time_C.timeit(number=100), "seconds")
175 time_D = Timer("Function_Test_D()", "from __main__ import Function_Test_D")
176 print("time_D ", time_D.timeit(number=100), "seconds")
177 #
178
179 result:
180
181 -----------------------
182 1.8 数据结构
183
184
185 数据是一个抽象的概念,将其进行分类后得到程序设计语言中的基本类型。
186 如:int,float,char等。数据元素之间不是独立的,存在特定的关系,
187 这些关系便是结构。数据结构指数据对象中数据元素之间的关系。
188
189 Python给我们提供了很多现成的数据结构类型,这些系统自己定义好的,
190 不需要我们自己去定义的数据结构叫做Python的内置数据结构,
191 比如列表、元组、字典。而有些数据组织方式,Python系统里面没有直接定义,
192 需要我们自己去定义实现这些数据的组织方式,这些数据组织方式称之为Python的扩展数据结构,比如栈,队列等。
193
194 算法与数据结构的区别
195 数据结构只是静态的描述了数据元素之间的关系。
196 高效的程序需要在数据结构的基础上设计和选择算法。
197
198 程序 = 数据结构 + 算法
199
200 总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体.
201
202 抽象数据类型(Abstract Data Type)
203 抽象数据类型(ADT)的含义是指一个数学模型以及定义在此数学模型上的一组操作。
204 即把数据类型和数据类型上的运算捆在一起,进行封装。
205 引入抽象数据类型的目的是,把数据类型的表示和数据类型上运算的实现,
206 与这些数据类型和运算在程序中的引用隔开,使它们相互独立。
207
208 最常用的数据运算有五种:
209 1.插入
210 2.删除
211 3.修改
212 4.查找
213 5.排序
214
215 ----------------------------------------------
216 2. 顺序表
217
218 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,
219 需要创建这种元素组,用变量记录它们,传进传出函数等。
220 一组数据中包含的元素个数可能发生变化(可以增加或删除元素)。
221
222 对于这种需求,最简单的解决方案便是将这样一组元素看成一个序列,
223 用元素在序列里的位置和顺序,表示实际应用中的某种有意义的信息,
224 或者表示数据之间的某种关系。
225
226 这样的一组序列元素的组织形式,我们可以将其抽象为线性表。
227 一个线性表是某类元素的一个集合,还记录着元素之间的一种顺序关系。
228 线性表是最基本的数据结构之一,在实际程序中应用非常广泛,
229 它还经常被用作更复杂的数据结构的实现基础。
230
231
232 根据线性表的实际存储方式,分为两种实现模型:
233
234 顺序表,将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。
235
236 链表,将元素存放在通过链接构造起来的一系列存储块中。
237 -----------------------
238 2.1 顺序表的基本形式
239
240 图a表示的是顺序表的基本形式,数据元素本身连续存储,每个元素所占的存储单元大小固定相同,
241 元素的下标是其逻辑地址,而元素存储的物理地址(实际内存地址)
242 可以通过存储区的起始地址Loc (e0)加上逻辑地址(第i个元素)
243 与存储单元大小(c)的乘积计算而得,即:Loc(ei) = Loc(e0) + c*i
244 故,访问指定元素时无需从头遍历,通过计算便可获得对应地址,其时间复杂度为O(1)。
245 如果元素的大小不统一,则须采用图b的元素外置的形式,将实际数据元素另行存储,
246 而顺序表中各单元位置保存对应元素的地址信息(即链接)。
247 由于每个链接所需的存储量相同,通过上述公式,可以计算出元素链接的存储位置,
248 而后顺着链接找到实际存储的数据元素。注意,图b中的c不再是数据元素的大小,
249 而是存储一个链接地址所需的存储量,这个量通常很小。
250 图b这样的顺序表也被称为对实际数据的索引,这是最简单的索引结构。
251
252 -----------------------
253 2.2 顺序表的结构与实现
254
255 顺序表的结构
256 一个顺序表的完整信息包括两部分,一部分是表中的元素集合,
257 另一部分是为实现正确操作而需记录的信息,即有关表的整体情况的信息,
258 这部分信息主要包括元素存储区的容量和当前表中已有的元素个数两项。
259
260 顺序表的两种基本实现方式
261 顺序表的实现方式
262 图a为一体式结构,存储表信息的单元与元素存储区以连续的方式安排在
263 一块存储区里,两部分数据的整体形成一个完整的顺序表对象。一体式结
264 构整体性强,易于管理。但是由于数据元素存储区域是表对象的一部分,
265 顺序表创建后,元素存储区就固定了。
266
267 图b为分离式结构,表对象里只保存与整个表有关的信息(即容量和元素个
268 数),实际数据元素存放在另一个独立的元素存储区里,通过链接与基本表
269 对象关联。
270
271 元素存储区替换
272 一体式结构由于顺序表信息区与数据区连续存储在一起,所以若想更换数据区,
273 则只能整体搬迁,即整个顺序表对象(指存储顺序表的结构信息的区域)改变了。
274
275 分离式结构若想更换数据区,只需将表信息区中的数据区链接地址更新即可,
276 而该顺序表对象不变。
277
278 元素存储区扩充
279 采用分离式结构的顺序表,若将数据区更换为存储空间更大的区域,
280 则可以在不改变表对象的前提下对其数据存储区进行了扩充,所有使用这
281 个表的地方都不必修改。只要程序的运行环境(计算机系统)还有空闲存
282 储,这种表结构就不会因为满了而导致操作无法进行。人们把采用这种技
283 术实现的顺序表称为动态顺序表,因为其容量可以在使用中动态变化。
284
285 扩充的两种策略
286 每次扩充增加固定数目的存储位置,如每次扩充增加10个元素位置,
287 这种策略可称为线性增长。
288 特点:节省空间,但是扩充操作频繁,操作次数多。每次扩充容量加倍,
289 如每次扩充增加一倍存储空间。
290 特点:减少了扩充操作的执行次数,但可能会浪费空间资源。以空间换
291 时间,推荐的方式。
292 -----------------------
293 2.3 顺序表的操作
294
295 顺序表增加元素
296 a. 尾端加入元素,时间复杂度为O(1)
297 b. 非保序的加入元素(不常见),时间复杂度为O(1)
298 c. 保序的元素加入,时间复杂度为O(n)
299
300 删除元素
301 顺序表删除元素
302 a. 删除表尾元素,时间复杂度为O(1)
303 b. 非保序的元素删除(不常见),时间复杂度为O(1)
304 c. 保序的元素删除,时间复杂度为O(n)
305 -----------------------
306 2.4 Python中的顺序表
307 Python中的list和tuple两种类型采用了顺序表的实现技术,具有
308 前面讨论的顺序表的所有性质。tuple是不可变类型,即不变的顺序表,因
309 此不支持改变其内部状态的任何操作,而其他方面,则与list的性质类似。
310 list的基本实现技术。Python标准类型list就是一种元素个数可变的线
311 性表,可以加入和删除元素,并在各种操作中维持已有元素的顺序(即保序
312 ),而且还具有以下行为特征:
313 基于下标(位置)的高效元素访问和更新,时间复杂度应该是O(1);
314 为满足该特征,应该采用顺序表技术,表中元素保存在一块连续的存储区中。
315 允许任意加入元素,而且在不断加入元素的过程中,表对象的标识(函数
316 id得到的值)不变。为满足该特征,就必须能更换元素存储区,并且为保
317 证更换存储区时list对象的标识id不变,只能采用分离式实现技术。
318
319 在Python的官方实现中,list就是一种采用分离式技术实现的动态
320 顺序表。这就是为什么用list.append(x) (或 list.insert(len
321 (list), x),即尾部插入)比在指定位置插入元素效率高的原因。
322
323 在Python的官方实现中,list实现采用了如下的策略:在建立空表
324 (或者很小的表)时,系统分配一块能容纳8个元素的存储区;在执行插入
325 操作(insert或append)时,如果元素存储区满就换一块4倍大的存储区。
326 但如果此时的表已经很大(目前的阀值为50000),则改变策略,采用加一
327 倍的方法。引入这种改变策略的方式,是为了避免出现过多空闲的存储位置。
328
329 ----------------------------------------------
330 3. 链表
331
332 为什么需要链表
333 顺序表的构建需要预先知道数据大小来申请连续的存储空间,
334 而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。
335 链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
336
337 链表的定义
338 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是
339 不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放
340 下一个节点的位置信息(即地址)。
341
342 -----------------------
343 3.1 单向链表
344
345 单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包
346 含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下
347 一个节点,而最后一个节点的链接域则指向一个空值。
348 *表元素域elem用来存放具体的数据。
349 *链接域next用来存放下一个节点的位置(python中的标识)
350 *变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。
351
352 节点实现
353 class Class_Single_Node(object):
354 # 单链表的结点
355 def __init__(self,item):
356 # _item存放数据元素
357 self.item = item
358 # _next是下一个节点的标识
359 self.next = None
360
361 单链表的操作
362 length() 链表长度
363 travel() 遍历整个链表
364 is_empty() 链表是否为空
365 add(item) 链表头部添加元素
366 append(item) 链表尾部添加元素
367 remove(item) 删除节点
368 search(item) 查找节点是否存在
369 insert(pos, item) 指定位置添加元素
370
371 单链表的操作实现
372 e.g:
373 # 单链表
374 #节点实现
375 class Class_Single_Node(object):
376 # 单链表的结点
377 def __init__(self,item):
378 # _item存放数据元素
379 self.item = item
380 # _next是下一个节点的标识
381 self.next = None
382
383 #单链表的操作实现
384 class SingleLinkList(object):
385 # 单链表头文件
386 def __init__(self):
387 self._head = None
388
389 # 判断链表是否为空
390 def is_empty(self):
391 return self._head == None
392
393 # 链表长度
394 def length(self):
395 # cur初始时指向头节点
396 current = self._head
397 count = 0
398 # 尾节点指向None,当未到达尾部时
399 while current != None:
400 count += 1
401 current = current.next # 将cur后移一个节点
402 return count
403
404 # 遍历链表
405 def travel(self):
406 current = self._head
407 while current != None:
408 print ("Travel Item : [%s]"%(current.item))
409 current = current.next
410 print ("Current Item : (%s)" % (current))
411
412 # 头部添加元素
413 def add(self, item):
414 # 先创建一个保存item值的节点 这是创建的前提条件
415 Node = Class_Single_Node(item)
416 # 将新节点的链接域next指向头节点,即_head指向的位置
417 Node.next = self._head
418 # 将链表的头_head指向新节点
419 self._head = Node
420
421 # 尾部添加元素
422 def append(self, item):
423 Node = Class_Single_Node(item)
424 # 先判断链表是否为空,若是空链表,则将_head指向新节点
425 if self.is_empty():
426 self._head = Node
427 # 若不为空,则找到尾部,将尾节点的next指向新节点
428 else:
429 current = self._head
430 while current.next != None:
431 current = current.next
432 current.next = Node
433
434 # 指定位置添加元素
435 def insert(self, pos, item):
436 # 若指定位置pos为第一个元素之前,则执行头部插入
437 if pos <= 0:
438 self.add(item)
439 # 若指定位置超过链表尾部,则执行尾部插入
440 elif pos > (self.length()-1):
441 self.append(item)
442 # 找到指定位置
443 else:
444 Node = Class_Single_Node(item) # 创建新的列表
445 count = 0
446 # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
447 previous = self._head
448 while count < (pos-1):
449 count += 1
450 previous = previous.next
451 # 先将新节点node的next指向插入位置的节点
452 Node.next = previous.next
453 # 将插入位置的前一个节点的next指向新节点
454 previous.next = Node
455
456 # 删除节点
457 def remove(self,item):
458 current = self._head
459 previous = None
460 while current != None:
461 # 找到了指定元素
462 if current.item == item:
463 # 如果第一个就是删除的节点
464 if not previous:
465 # 将头指针指向头节点的后一个节点
466 self._head = current.next
467 else:
468 # 将删除位置前一个节点的next指向删除位置的后一个节点
469 previous.next = current.next
470 break
471 else:
472 # 继续按链表后移节点
473 previous = current
474 current = current.next
475
476 #查找节点是否存在
477 def search(self,item):
478 # 表查找节点是否存在,并返回True或者False
479 current = self._head
480 while current != None:
481 if current.item == item:
482 return True
483 current = current.next
484 return False
485
486
487 if __name__ == "__main__":
488 single_list_name_A = SingleLinkList()
489 single_list_name_A.add(11) # 头部添加元素
490 single_list_name_A.add(12) # 头部添加元素
491 single_list_name_A.add(13) # 头部添加元素
492 single_list_name_A.append(24) # 尾部添加元素
493 single_list_name_A.insert(3, 35) # 指定位置添加元素
494 single_list_name_A.append(26) # 尾部添加元素
495 single_list_name_A.travel() # 遍历链表
496 print ("Length:[%s]"%(single_list_name_A.length()))
497 print(single_list_name_A.search(35)) # 查找节点是否存在
498 print(single_list_name_A.search(15)) # 查找节点是否存在
499 single_list_name_A.remove(11) # 删除节点
500 single_list_name_A.travel() # 遍历链表
501 print("Length:[%s]" % (single_list_name_A.length()))
502 result:
503 Travel Item : [13]
504 Travel Item : [12]
505 Travel Item : [11]
506 Travel Item : [35]
507 Travel Item : [24]
508 Travel Item : [26]
509 Current Item : (None)
510 Length:[6]
511 True
512 False
513 Travel Item : [13]
514 Travel Item : [12]
515 Travel Item : [35]
516 Travel Item : [24]
517 Travel Item : [26]
518 Current Item : (None)
519 Length:[5]
520
521 链表与顺序表的对比
522 链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,
523 空间开销比较大,但对存储空间的使用要相对灵活。
524 链表与顺序表的各种操作复杂度如下所示:
525
526 操作 链表 顺序表
527 访问元素 O(n) O(1)
528 在头部插入/删除 O(1) O(n)
529 在尾部插入/删除 O(n) O(1)
530 在中间插入/删除 O(n) O(n)
531 注意虽然表面看起来复杂度都是 O(n),但是链表和顺序表在插入和
532 删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和
533 插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝
534 覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要
535 对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。
536
537 -----------------------
538 3.2 单向循环链表
539 单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再
540 为None,而是指向链表的头节点。
541
542 单向循环链表操作
543 is_empty() 判断链表是否为空
544 length() 返回链表的长度
545 travel() 遍历
546 add(item) 在头部添加一个节点
547 append(item) 在尾部添加一个节点
548 insert(pos, item) 在指定位置pos添加节点
549 remove(item) 删除一个节点
550 search(item) 查找节点是否存在
551
552 e.g:
553 # 单向循环链表
554 # 单项节点创建
555 # class Class_Single_Node(object):
556 # # 单链表的结点
557 # def __init__(self,item):
558 # # _item存放数据元素
559 # self.item = item
560 # # _next是下一个节点的标识
561 # self.next = None
562
563 class Class_SinCyc_Linkedlist(object):
564 def __init__(self):
565 self._head = None
566
567 # 判断链表是否为空
568 def is_empty(self):
569 return self._head == None
570
571 # 返回链表的长度
572 def length(self):
573 # 如果链表为空,返回长度0
574 if self.is_empty():
575 return 0
576 count = 1
577 current = self._head
578 while current.next != self._head:
579 count += 1
580 current = current.next
581 return count
582
583 # 遍历链表
584 def travel(self):
585 # 判断是否为空
586 if self.is_empty():
587 return
588 current = self._head
589 print("Travel Item : [%s]" % (current.item))
590 while current.next != self._head:
591 current = current.next
592 print("Travel Item : [%s]" % (current.item))
593 print("Travel Finish ")
594
595 # 头部添加节点
596 def add(self, item):
597 Node = Class_Single_Node(item)
598 # 判断是否为空
599 if self.is_empty():
600 self._head = Node
601 Node.next = self._head
602 else:
603 #添加的节点指向_head
604 Node.next = self._head
605 # 移到链表尾部,将尾部节点的next指向node
606 current = self._head
607 while current.next != self._head:
608 current = current.next
609 current.next = Node
610 #_head指向添加node的
611 self._head = Node
612 # 尾部添加节点
613 def append(self, item):
614 Node = Class_Single_Node(item)
615 if self.is_empty():
616 self._head = Node
617 Node.next = self._head
618 else:
619 # 移到链表尾部
620 current = self._head
621 while current.next != self._head:
622 current = current.next
623 # 将尾节点指向node
624 current.next = Node
625 # 将node指向头节点_head
626 Node.next = self._head
627 # 指定位置添加节点
628 def insert(self, pos, item):
629 if pos <= 0:
630 self.add(item)
631 elif pos > (self.length()-1):
632 self.append(item)
633 else:
634 Node = Class_Single_Node(item)
635 current = self._head
636 count = 0
637 # 移动到指定位置的前一个位置
638 while count < (pos-1):
639 count += 1
640 current = current.next
641 Node.next = current.next
642 current.next = Node
643
644 def remove(self, item):
645 """删除一个节点"""
646 # 若链表为空,则直接返回
647 if self.is_empty():
648 return
649 # 将cur指向头节点
650 current = self._head
651 pre = None
652 # 若头节点的元素就是要查找的元素item
653 if current.item == item:
654 # 如果链表不止一个节点
655 if current.next != self._head:
656 # 先找到尾节点,将尾节点的next指向第二个节点
657 while current.next != self._head:
658 current = current.next
659 # cur指向了尾节点
660 current.next = self._head.next
661 self._head = self._head.next
662 else:
663 # 链表只有一个节点
664 self._head = None
665 else:
666 pre = self._head
667 # 第一个节点不是要删除的
668 while current.next != self._head:
669 # 找到了要删除的元素
670 if current.item == item:
671 # 删除
672 pre.next = current.next
673 return
674 else:
675 pre = current
676 current = current.next
677 # current 指向尾节点
678 if current.item == item:
679 # 尾部删除
680 pre.next = current.next
681 # 查找节点是否存在
682 def search(self, item):
683 if self.is_empty():
684 return False
685 current = self._head
686 if current.item == item:
687 return True
688 while current.next != self._head:
689 current = current.next
690 if current.item == item:
691 return True
692 return False
693
694 if __name__ == "__main__":
695 # 单链表循环
696 single_list_name_B = Class_SinCyc_Linkedlist()
697 print("Length:[%s]" % (single_list_name_B.length()))
698 single_list_name_B.add(11) # 头部添加元素
699 single_list_name_B.add(12) # 头部添加元素
700 single_list_name_B.add(13) # 头部添加元素
701 single_list_name_B.append(21) # 尾部添加元素
702 single_list_name_B.insert(1, 31) # 指定位置添加元素
703 single_list_name_B.insert(3, 32) # 指定位置添加元素
704 single_list_name_B.insert(5, 33) # 指定位置添加元素
705 single_list_name_B.append(22) # 尾部添加元素
706 single_list_name_B.travel() # 遍历链表
707 print("Length:[%s]" % (single_list_name_B.length()))
708 print(single_list_name_B.search(11))# 查找节点是否存在
709 print(single_list_name_B.search(22))# 查找节点是否存在
710 print(single_list_name_B.search(55))# 查找节点是否存在
711 single_list_name_B.remove(11)
712 single_list_name_B.travel() # 遍历链表
713 print("Length:[%s]" % (single_list_name_B.length()))
714 #
715 result:
716 Length:[0]
717 Travel Item : [13]
718 Travel Item : [31]
719 Travel Item : [12]
720 Travel Item : [32]
721 Travel Item : [11]
722 Travel Item : [33]
723 Travel Item : [21]
724 Travel Item : [22]
725 Travel Finish
726 Length:[8]
727 True
728 True
729 False
730 Travel Item : [13]
731 Travel Item : [31]
732 Travel Item : [12]
733 Travel Item : [32]
734 Travel Item : [33]
735 Travel Item : [21]
736 Travel Item : [22]
737 Travel Finish
738 Length:[7]
739
740 -----------------------
741 3.3 双向链表
742
743 一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链
744 接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一
745 个指向下一个节点,当此节点为最后一个节点时,指向空值。
746
747 双向链表操作
748 is_empty() 链表是否为空
749 length() 链表长度
750 travel() 遍历链表
751 add(item) 链表头部添加
752 append(item) 链表尾部添加
753 insert(pos, item) 指定位置添加
754 remove(item) 删除节点
755 search(item) 查找节点是否存在
756
757 e.g:
758 # 双向链表节点
759 class Class_Double_Node(object):
760 def __init__(self, item):
761 # _item存放数据元素
762 self.item = item
763 # _next是下一个节点的标识
764 self.next = None
765 # _prev是上一个节点的标识
766 self.prev = None
767
768 # 双向链表操作
769 class Class_Double_LinkList(object):
770 def __init__(self):
771 self._head = None
772
773 # 判断链表是否为空
774 def is_empty(self):
775 return self._head == None
776
777 # 链表的长度
778 def length(self):
779 current = self._head
780 count = 0
781 while current != None:
782 count += 1
783 current = current.next
784 return count
785
786 # 遍历链表
787 def travel(self):
788 current = self._head
789 while current != None:
790 print("Travel Item : [%s]" % (current.item))
791 current = current.next
792 print("Travel Finish ")
793
794 # 头部插入元素
795 def add(self, item):
796 Node = Class_Double_Node(item)
797 # 如果是空链表,将_head指向node
798 if self.is_empty():
799 self._head = Node
800 else:
801 # 将node的next指向_head的头节点
802 Node.next = self._head
803 # 将_head的头节点的prev指向node
804 self._head.prev = Node
805 # 将_head 指向node
806 self._head = Node
807
808 # 尾部插入元素
809 def append(self, item):
810 Node = Class_Double_Node(item)
811 # 如果是空链表,将_head指向node
812 if self.is_empty():
813 self._head = Node
814 else:
815 # 移动到链表尾部
816 current = self._head
817 while current.next != None:
818 current = current.next
819 # 将尾节点cur的next指向node
820 current.next = Node
821 # 将node的prev指向cur
822 Node.prev = current
823
824 # 指定位置插入元素
825 def insert(self, pos, item):
826 if pos <= 0:
827 self.add(item)
828 elif pos > (self.length()-1):
829 self.append(item)
830 else:
831 Node = Class_Double_Node(item)
832 current = self._head
833 count = 0
834 # 移动到指定位置的前一个位置
835 while count < (pos-1):
836 count += 1
837 current = current.next
838 # 将node的prev指向cur
839 Node.prev = current
840 # 将node的next指向cur的下一个节点
841 Node.next = current.next
842 # 将cur的下一个节点的prev指向node
843 current.next.prev = Node
844 # 将cur的next指向node
845 current.next = Node
846 # 删除元素
847 def remove(self, item):
848 """删除元素"""
849 if self.is_empty():
850 return
851 else:
852 current = self._head
853 if current.item == item:
854 # 如果首节点的元素即是要删除的元素
855 if current.next == None:
856 # 如果链表只有这一个节点
857 self._head = None
858 else:
859 # 将第二个节点的prev设置为None
860 current.next.prev = None
861 # 将_head指向第二个节点
862 self._head = current.next
863 return
864 while current != None:
865 if current.item == item:
866 # 将cur的前一个节点的next指向cur的后一个节点
867 current.prev.next = current.next
868 # 将cur的后一个节点的prev指向cur的前一个节点
869 current.next.prev = current.prev
870 break
871 current = current.next
872
873 # 查找元素是否存在
874 def search(self, item):
875 current = self._head
876 while current != None:
877 if current.item == item:
878 return True
879 current = current.next
880 return False
881
882 if __name__ == "__main__":
883 # 双向链表
884 single_list_name_C = Class_Double_LinkList()
885 print("Length:[%s]" % (single_list_name_C.length()))
886 single_list_name_C.add(111) # 头部添加元素
887 single_list_name_C.add(112) # 头部添加元素
888 single_list_name_C.add(113) # 头部添加元素
889 single_list_name_C.add(114) # 头部添加元素
890 single_list_name_C.add(115) # 头部添加元素
891 single_list_name_C.append(211) # 尾部添加元素
892 single_list_name_C.append(212) # 尾部添加元素
893 single_list_name_C.append(213) # 尾部添加元素
894 single_list_name_C.travel() # 遍历链表
895 print("Length:[%s]" % (single_list_name_C.length()))
896 single_list_name_C.insert(2, 311) # 指定位置添加元素
897 single_list_name_C.insert(4, 312) # 指定位置添加元素
898 single_list_name_C.insert(6, 313) # 指定位置添加元素
899 print(single_list_name_C.search(111)) # 查找节点是否存在
900 print(single_list_name_C.search(211)) # 查找节点是否存在
901 print(single_list_name_C.search(311)) # 查找节点是否存在
902 single_list_name_C.travel() # 遍历链表
903 print("Length:[%s]" % (single_list_name_C.length()))
904 single_list_name_C.remove(112)
905 single_list_name_C.remove(113)
906 single_list_name_C.remove(114)
907 single_list_name_C.remove(115)
908 single_list_name_C.remove(211)
909 single_list_name_C.remove(212)
910 single_list_name_C.travel() # 遍历链表
911 print("Length:[%s]" % (single_list_name_C.length()))
912
913 result:
914 Length:[0]
915 Travel Item : [115]
916 Travel Item : [114]
917 Travel Item : [113]
918 Travel Item : [112]
919 Travel Item : [111]
920 Travel Item : [211]
921 Travel Item : [212]
922 Travel Item : [213]
923 Travel Finish
924 Length:[8]
925 True
926 True
927 True
928 Travel Item : [115]
929 Travel Item : [114]
930 Travel Item : [311]
931 Travel Item : [113]
932 Travel Item : [312]
933 Travel Item : [112]
934 Travel Item : [313]
935 Travel Item : [111]
936 Travel Item : [211]
937 Travel Item : [212]
938 Travel Item : [213]
939 Travel Finish
940 Length:[11]
941 Travel Item : [311]
942 Travel Item : [312]
943 Travel Item : [313]
944 Travel Item : [111]
945 Travel Item : [213]
946 Travel Finish
947 Length:[5]
948
949 ----------------------------------------------
950 4. 栈
951
952 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素、
953 访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶端
954 指标,英语:top)进行加入数据(英语:push)和输出数据(英语:
955 pop)的运算。没有了位置概念,保证任何时候可以访问、删除的元素都
956 是此前最后存入的那个元素,确定了一种默认的访问顺序。
957
958 由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO,
959 Last In First Out)的原理运作。
960
961
962 ----------------------------------------------
963 5. 队列
964
965 队列(queue)是只允许在一端进行插入操作,而在另一端进行删
966 除操作的线性表。
967 队列是一种先进先出的(First In First Out)的线性表,简
968 称FIFO。允许插入的一端为队尾,允许删除的一端为队头。队列不允许
969 在中间部位进行操作!假设队列是q=(a1,a2,……,an),那么a1就
970 是队头元素,而an是队尾元素。这样我们就可以删除时,总是从a1开始,
971 而插入时,总是在队列最后。这也比较符合我们通常生活中的习惯,排在
972 第一个的优先出列,最后来的当然排在队伍最后。
973
974 -----------------------
975 5.1 队列的实现
976 同栈一样,队列也可以用顺序表或者链表实现。
977 操作
978 Queue() 创建一个空的队列
979 enqueue(item) 往队列中添加一个item元素
980 dequeue() 从队列头部删除一个元素
981 is_empty() 判断一个队列是否为空
982 size() 返回队列的大小
983
984 e.g:
985 # 队列
986 class Class_Queue(object):
987 def __init__(self):
988 self.items = []
989
990 def is_empty(self):
991 return self.items == []
992
993 # 进队列
994 def enqueue(self, item):
995 self.items.insert(0,item)
996
997 # 出队列
998 def dequeue(self):
999 return self.items.pop()
1000
1001 # 大小
1002 def size(self):
1003 return len(self.items)
1004
1005 if __name__ == "__main__":
1006 # 队列
1007 queue_name_A = Class_Queue() # 创建对象
1008 queue_name_A.enqueue("hello") # 进队列
1009 queue_name_A.enqueue("world") # 进队列
1010 queue_name_A.enqueue("it cast") # 进队列
1011 print(queue_name_A.size())
1012 queue_name_A.dequeue() # 出队列
1013 print(queue_name_A.size())
1014 queue_name_A.dequeue() # 出队列
1015 print(queue_name_A.size())
1016 queue_name_A.dequeue() # 出队列
1017 print(queue_name_A.size())
1018 result:
1019 3
1020 2
1021 1
1022 0
1023
1024 -----------------------
1025 5.2 双端队列
1026
1027 双端队列(Class_Double_Queue,全名double-ended queue),是一种具有
1028 队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定
1029 插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。
1030
1031 操作
1032 Class_Double_Queue() 创建一个空的双端队列
1033 add_front(item) 从队头加入一个item元素
1034 add_rear(item) 从队尾加入一个item元素
1035 remove_front() 从队头删除一个item元素
1036 remove_rear() 从队尾删除一个item元素
1037 is_empty() 判断双端队列是否为空
1038 size() 返回队列的大小
1039
1040 e.g:
1041 # 双端队列
1042 # 创建双端队列
1043 class Class_Double_Queue(object):
1044 def __init__(self):
1045 self.items = []
1046
1047 #判断队列是否为空
1048 def is_empty(self):
1049 return self.items == []
1050
1051 #在队头添加元素
1052 def add_front(self, item):
1053 self.items.insert(0,item)
1054
1055 # 在队尾添加元素
1056 def add_rear(self, item):
1057 self.items.append(item)
1058
1059 #从队头删除元素
1060 def remove_front(self):
1061 return self.items.pop(0)
1062
1063 #从队尾删除元素
1064 def remove_rear(self):
1065 return self.items.pop()
1066
1067 #队列大小
1068 def size(self):
1069 return len(self.items)
1070
1071 if __name__ == "__main__":
1072 Class_Double_Queue = Class_Double_Queue()
1073 Class_Double_Queue.add_front(111) # 从队头加入一个item元素
1074 Class_Double_Queue.add_front(112) # 从队头加入一个item元素
1075 Class_Double_Queue.add_rear(213) # 从队尾加入一个item元素
1076 Class_Double_Queue.add_rear(214) # 从队尾加入一个item元素
1077 Class_Double_Queue.size()
1078 print(Class_Double_Queue.size())
1079 Class_Double_Queue.remove_front() # 从队头删除一个item元素
1080 print(Class_Double_Queue.size())
1081 Class_Double_Queue.remove_front() # 从队头删除一个item元素
1082 print(Class_Double_Queue.size())
1083 Class_Double_Queue.remove_rear() # 从队尾删除一个item元素
1084 print(Class_Double_Queue.size())
1085 Class_Double_Queue.remove_rear() # 从队尾删除一个item元素
1086 print(Class_Double_Queue.size())
1087
1088 result:
1089 4
1090 3
1091 2
1092 1
1093 0
1094
1095 ----------------------------------------------
1096 6. 排序与搜索
1097
1098 排序算法(英语:Sorting algorithm)是一种能将一串数据依
1099 照特定顺序进行排列的一种算法。
1100
1101 排序算法的稳定性。稳定性:稳定排序算法会让原本有相等键值的纪
1102 录维持相对次序。也就是如果一个排序算法是稳定的,当有两个相等键值
1103 的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将
1104 会是在S之前。
1105 当相等的元素是无法分辨的,比如像是整数,稳定性并不是一个问题。
1106 然而,假设以下的数对将要以他们的第一个数字来排序。
1107 (4, 1) (3, 1) (3, 7)(5, 6)
1108 在这个状况下,有可能产生两种不同的结果,一个是让相等键值的
1109 纪录维持相对的次序,而另外一个则没有:
1110 (3, 1) (3, 7) (4, 1) (5, 6) (维持次序)
1111 (3, 7) (3, 1) (4, 1) (5, 6) (次序被改变)
1112 不稳定排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排
1113 序算法从来不会如此。不稳定排序算法可以被特别地实现为稳定。作这件
1114 事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个
1115 对象间之比较,(比如上面的比较中加入第二个标准:第二个键值的大小)
1116 就会被决定使用在原先数据次序中的条目,当作一个同分决赛。然而,要
1117 记住这种次序通常牵涉到额外的空间负担。
1118
1119 -----------------------
1120 6.1 冒泡排序
1121
1122 冒泡排序(英语:Bubble Sort)是一种简单的排序算法。它重复
1123 地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们
1124 交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说
1125 该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换
1126 慢慢“浮”到数列的顶端。
1127
1128 冒泡排序算法的运作如下:
1129 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
1130 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步
1131 做完后,最后的元素会是最大的数。针对所有的元素重复以上的步骤,除
1132 了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何
1133 一对数字需要比较。
1134 e.g:
1135 # 冒泡排序
1136 def Function_Algorithm_BubbleSort(alist):
1137 local_var_alist = alist
1138 # print('local_var_alist',local_var_alist)
1139 # range(start,end,scan)
1140 # start:开始 end:结束 scan:步进长度,负为减少+(-X)
1141 for var_A in range(len(local_var_alist)-1,0,-1):
1142 # print("--------------------------")
1143 # print('var_A', var_A)
1144 # var_A表示每次遍历需要比较的次数,是逐渐减小的
1145 for var_B in range(var_A):
1146 # print('var_B', var_B)
1147 # print(local_var_alist[var_B], local_var_alist[var_B + 1])
1148 if local_var_alist[var_B] > local_var_alist[var_B + 1]:
1149 ### 二个数据交换,以下三步用一个表达式代替
1150 # # var_name = local_var_alist[var_B]
1151 # # local_var_alist[var_B] = local_var_alist[var_B + 1]
1152 # # local_var_alist[var_B + 1] = var_name
1153 local_var_alist[var_B], local_var_alist[var_B+1] = local_var_alist[var_B+1], local_var_alist[var_B]
1154
1155 if __name__ == "__main__":
1156 BubbleSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
1157 print("P",BubbleSort_name_A) # 前
1158 Function_Algorithm_BubbleSort(BubbleSort_name_A)
1159 print("N",BubbleSort_name_A) # 后
1160 result:
1161 P [54, 26, 93, 17, 77, 31, 44, 55, 20]
1162 N [17, 20, 26, 31, 44, 54, 55, 77, 93]
1163
1164 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
1165 最坏时间复杂度:O(n2)
1166 稳定性:稳定
1167
1168
1169 -----------------------
1170 6.2 选择排序
1171
1172 选择排序(Selection sort)是一种简单直观的排序算法。它的
1173 工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序
1174 列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,
1175 然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
1176 选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终
1177 位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有
1178 一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多
1179 n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序
1180 属于非常好的一种。
1181
1182 e.g:
1183 # 选择排序
1184 def Function_Algorithm_SelectionSort(alist):
1185 local_var_alist = alist
1186
1187 number = len(local_var_alist)
1188 # 需要进行n-1次选择操作
1189 for var_A in range(number-1):
1190 # print("--------------------------")
1191 min_index = var_A # 记录最小位置
1192 # print('var_A: ', var_A, " --- min_index : ", min_index)
1193 # 从i+1位置到末尾选择出最小数据
1194 for var_B in range(var_A+1, number):
1195 # print("var_B:(%s) | var_A:(%s) | number:(%s)"%(var_B,var_A+1,number))
1196 # print(local_var_alist[var_B],local_var_alist[min_index])
1197
1198 if local_var_alist[var_B] < local_var_alist[min_index]:
1199 min_index = var_B
1200 # print(local_var_alist[var_B], local_var_alist[min_index])
1201 # 如果选择出的数据不在正确位置,进行交换
1202 if min_index != var_A:
1203 local_var_alist[var_A], local_var_alist[min_index] = local_var_alist[min_index], local_var_alist[var_A]
1204 # print(">>",local_var_alist[var_A],local_var_alist[min_index])
1205
1206 if __name__ == "__main__":
1207 SelectionSort_name_A = [54, 226, 93, 17, 77, 31, 44, 55, 20]
1208 print("P",SelectionSort_name_A)
1209 Function_Algorithm_SelectionSort(SelectionSort_name_A)
1210 print("N",SelectionSort_name_A)
1211
1212 result:
1213 P [54, 226, 93, 17, 77, 31, 44, 55, 20]
1214 N [17, 20, 31, 44, 54, 55, 77, 93, 226]
1215
1216 时间复杂度
1217 最优时间复杂度:O(n2)
1218 最坏时间复杂度:O(n2)
1219 稳定性:不稳定(考虑升序每次选择最大的情况)
1220
1221 -----------------------
1222 6.3 插入排序
1223 插入排序(英语:Insertion Sort)是一种简单直观的排序算法。
1224 它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从
1225 后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描
1226 过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
1227
1228
1229
1230 e.g:
1231 def Function_Algorithm_InsertSort(alist):
1232 local_var_alist = alist
1233 # 从第二个位置,即下标为1的元素开始向前插入
1234 for var_A in range(1, len(local_var_alist)):
1235 # 从第i个元素开始向前比较,如果小于前一个元素,交换位置
1236 for var_B in range(var_A, 0, -1):
1237 if local_var_alist[var_B] < local_var_alist[var_B-1]:
1238 local_var_alist[var_B], local_var_alist[var_B-1] = local_var_alist[var_B-1], local_var_alist[var_B]
1239
1240 if __name__ == "__main__":
1241 InsertionSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
1242 print("P",InsertionSort_name_A)
1243 Function_Algorithm_InsertSort(InsertionSort_name_A)
1244 print("N",InsertionSort_name_A)
1245 result:
1246 P [54, 26, 93, 17, 77, 31, 44, 55, 20]
1247 N [17, 20, 26, 31, 44, 54, 55, 77, 93]
1248
1249 时间复杂度
1250 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
1251 最坏时间复杂度:O(n2)
1252 稳定性:稳定
1253
1254 -----------------------
1255 6.4 快速排序
1256
1257 快速排序(英语:Quicksort),又称划分交换排序(partition
1258 -exchange sort),通过一趟排序将要排序的数据分割成独立的两
1259 部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后
1260 再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归
1261 进行,以此达到整个数据变成有序序列。
1262
1263 步骤为:
1264 1)从数列中挑出一个元素,称为"基准"(pivot),
1265 2)重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基
1266 准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之
1267 后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
1268 3)递归地(recursive)把小于基准值元素的子数列和大于基准值元素
1269 的子数列排序。
1270 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被
1271 排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的
1272 迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
1273
1274 e.g:
1275 # 快速排序
1276 #
1277 def Function_Algorithm_QuickSort(alist, start, end):
1278 """快速排序"""
1279 local_var_alist = alist
1280 local_var_start = start
1281 local_var_end = end
1282
1283 # 递归的退出条件
1284 if local_var_start >= local_var_end:
1285 return
1286
1287 # 设定起始元素为要寻找位置的基准元素
1288 list_mid = local_var_alist[local_var_start]
1289 # low为序列左边的由左向右移动的游标
1290 list_low = local_var_start
1291 # high为序列右边的由右向左移动的游标
1292 list_high = local_var_end
1293
1294 print("1 >>",list_low,list_mid,list_high)
1295
1296 while list_low < list_high:
1297 print("L H",list_low,list_high)
1298 # 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
1299 while list_low < list_high and local_var_alist[list_high] >= list_mid:
1300 list_high -= 1
1301 # 将high指向的元素放到low的位置上
1302 local_var_alist[list_low] = local_var_alist[list_high]
1303 print("2 >>", local_var_alist[list_low] )
1304 # 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
1305 while list_low < list_high and local_var_alist[list_low] < list_mid:
1306 list_low += 1
1307 # 将low指向的元素放到high的位置上
1308 local_var_alist[list_high] = local_var_alist[list_low]
1309 print("3 >>", local_var_alist[list_high])
1310 print("----------")
1311 # 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
1312 # 将基准元素放到该位置
1313
1314 local_var_alist[list_low] = list_mid
1315 print("4 >>", local_var_alist[list_low])
1316 print("==================")
1317 # # 对基准元素左边的子序列进行快速排序
1318 Function_Algorithm_QuickSort(local_var_alist, local_var_start, list_low-1)
1319 #
1320 # # 对基准元素右边的子序列进行快速排序
1321 Function_Algorithm_QuickSort(local_var_alist, list_low+1, local_var_end)
1322
1323
1324 if __name__ == "__main__":
1325 QuickSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
1326 print("P", QuickSort_name_A)
1327 Function_Algorithm_QuickSort(QuickSort_name_A, 0, len(QuickSort_name_A) - 1)
1328 print("N", QuickSort_name_A)
1329 result:
1330 P [54, 26, 93, 17, 77, 31, 44, 55, 20]
1331 1 >> 0 54 8
1332 L H 0 8
1333 2 >> 20
1334 3 >> 93
1335 ----------
1336 L H 2 8
1337 2 >> 44
1338 3 >> 77
1339 ----------
1340 L H 4 6
1341 2 >> 31
1342 3 >> 31
1343 ----------
1344 4 >> 54
1345 ==================
1346 1 >> 0 20 4
1347 L H 0 4
1348 2 >> 17
1349 3 >> 26
1350 ----------
1351 L H 1 3
1352 2 >> 26
1353 3 >> 26
1354 ----------
1355 4 >> 20
1356 ==================
1357 1 >> 2 44 4
1358 L H 2 4
1359 2 >> 31
1360 3 >> 31
1361 ----------
1362 4 >> 44
1363 ==================
1364 1 >> 2 31 3
1365 L H 2 3
1366 2 >> 26
1367 3 >> 26
1368 ----------
1369 4 >> 31
1370 ==================
1371 1 >> 6 77 8
1372 L H 6 8
1373 2 >> 55
1374 3 >> 55
1375 ----------
1376 4 >> 77
1377 ==================
1378 N [17, 20, 26, 31, 44, 54, 55, 77, 93]
1379
1380 时间复杂度
1381 最优时间复杂度:O(nlogn)
1382 最坏时间复杂度:O(n2)
1383 稳定性:不稳定
1384 从一开始快速排序平均需要花费O(n log n)时间的描述并不明显。
1385 但是不难观察到的是分区运算,数组的元素都会在每次循环中走访过一次,
1386 使用O(n)的时间。在使用结合(concatenation)的版本中,这项运
1387 算也是O(n)。
1388 在最好的情况,每次我们运行一次分区,我们会把一个数列分为两
1389 个几近相等的片段。这个意思就是每次递归调用处理一半大小的数列。
1390 因此,在到达大小为一的数列前,我们只要作log n次嵌套的调用。这
1391 个意思就是调用树的深度是O(log n)。但是在同一层次结构的两个程
1392 序调用中,不会处理到原来数列的相同部分;因此,程序调用的每一层
1393 次结构总共全部仅需要O(n)的时间(每个调用有某些共同的额外耗费,
1394 但是因为在每一层次结构仅仅只有O(n)个调用,这些被归纳在O(n)系
1395 数中)。结果是这个算法仅需使用O(n log n)时间。
1396 -----------------------
1397 6.5 希尔排序
1398
1399 希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,
1400 是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算
1401 法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按
1402 下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐
1403 减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成
1404 一组,算法便终止。
1405
1406 希尔排序过程
1407 希尔排序的基本思想是:将数组列在一个表中并对列分别进行插入
1408 排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来
1409 进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算
1410 法,算法本身还是使用数组进行排序。
1411
1412 例如,假设有这样一组数
1413 [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],
1414 如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表
1415 中来更好地描述算法,这样他们就应该看起来是这样(竖着的元素是步长组
1416 成):
1417 13 14 94 33 82
1418 25 59 94 65 23
1419 45 27 73 25 39
1420 10
1421 然后我们对每列进行排序:
1422 10 14 73 25 23
1423 13 27 94 33 39
1424 25 59 94 65 82
1425 45
1426
1427 将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13
1428 27 94 33 39 25 59 94 65 82 45 ]。这时10已经移至正确位置
1429 了,然后再以3为步长进行排序:
1430 10 14 73
1431 25 23 13
1432 27 94 33
1433 39 25 59
1434 94 65 82
1435 45
1436 排序之后变为:
1437 10 14 13
1438 25 23 33
1439 27 25 59
1440 39 65 73
1441 45 94 82
1442 94
1443 最后以1步长进行排序(此时就是简单的插入排序了)
1444
1445 e.g:
1446 # 希尔排序
1447 def Function_Algorithm_ShellSort(alist):
1448 n = len(alist)
1449 # 初始步长
1450 var = n / 2
1451 gap = int(var)
1452 print(gap,type(gap))
1453 while gap > 0:
1454 # 按步长进行插入排序
1455 for i in range(gap, n):
1456 j = i
1457 # 插入排序
1458 while j>=gap and alist[j-gap] > alist[j]:
1459 alist[j-gap], alist[j] = alist[j], alist[j-gap]
1460 j -= gap
1461 # 得到新的步长
1462 gap = gap / 2
1463
1464
1465 if __name__ == "__main__":
1466 ShellSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20, 99]
1467 print(ShellSort_name_A)
1468 Function_Algorithm_ShellSort(ShellSort_name_A)
1469 print(ShellSort_name_A)
1470 result:
1471 时间复杂度
1472 最优时间复杂度:根据步长序列的不同而不同
1473 最坏时间复杂度:O(n2)
1474 稳定想:不稳定
1475 -----------------------
1476 6.6 归并排序
1477
1478 归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是
1479 先递归分解数组,再合并数组。将数组分解最小之后,然后合并两个有序
1480 数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相
1481 应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个
1482 数组的剩余部分复制过来即可。
1483
1484 e.g:
1485
1486 if __name__ == "__main__":
1487
1488 result:
1489
1490
1491 -----------------------
1492
1493
1494 -----------------------
1495 6.8 搜索
1496
1497 搜索是在一个项目集合中找到一个特定项目的算法过程。搜索通常的答案
1498 是真的或假的,因为该项目是否存在。 搜索的几种常见方法:顺序查找、
1499 二分法查找、二叉树查找、哈希查找
1500
1501 二分法查找
1502 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;
1503 其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法
1504 适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升
1505 序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,
1506 则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中
1507 间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进
1508 一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找
1509 成功,或直到子表不存在为止,此时查找不成功。
1510 e.g:
1511 # 非递归实现
1512 def binary_search(alist, item):
1513 first = 0
1514 last = len(alist)-1
1515 while first<=last:
1516 midpoint = (first + last)/2
1517 if alist[midpoint] == item:
1518 return True
1519 elif item < alist[midpoint]:
1520 last = midpoint-1
1521 else:
1522 first = midpoint+1
1523 return False
1524
1525 # 递归实现
1526 def binary_search(alist, item):
1527 if len(alist) == 0:
1528 return False
1529 else:
1530 midpoint = len(alist)//2
1531 if alist[midpoint]==item:
1532 return True
1533 else:
1534 if item<alist[midpoint]:
1535 return binary_search(alist[:midpoint],item)
1536 else:
1537 return binary_search(alist[midpoint+1:],item)
1538
1539
1540 if __name__ == "__main__":
1541 #------------------------------------
1542 testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
1543 print(binary_search(testlist, 3))
1544 print(binary_search(testlist, 13))
1545 #------------------------------------
1546 testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
1547 print(binary_search(testlist, 3))
1548 print(binary_search(testlist, 13))
1549
1550
1551 result:
1552
1553 ----------------------------------------------
1554 7. 树与树算法
1555
1556 树的概念
1557 树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象
1558 数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由
1559 n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是
1560 因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它
1561 具有以下的特点:
1562 *每个节点有零个或多个子节点;
1563 *没有父节点的节点称为根节点;
1564 *每一个非根节点有且只有一个父节点;
1565 *除了根节点外,每个子节点可以分为多个不相交的子树;
1566 比如说:
1567 tree Treedatastructure
1568
1569 树的术语
1570 节点的度:一个节点含有的子树的个数称为该节点的度;
1571 树的度:一棵树中,最大的节点的度称为树的度;
1572 叶节点或终端节点:度为零的节点;
1573 父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
1574 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
1575 兄弟节点:具有相同父节点的节点互称为兄弟节点;
1576 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
1577 树的高度或深度:树中节点的最大层次;
1578 堂兄弟节点:父节点在同一层的节点互为堂兄弟;
1579 节点的祖先:从根到该节点所经分支上的所有节点;
1580 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
1581 森林:由m(m>=0)棵互不相交的树的集合称为森林;
1582 树的种类
1583 无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;
1584 有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
1585 二叉树:每个节点最多含有两个子树的树称为二叉树;
1586 完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层
1587 外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地
1588 紧密排列,这样的二叉树被称为完全二叉树,其中满二叉树的定义是所有
1589 叶节点都在最底层的完全二叉树;
1590 平衡二叉树(AVL树):当且仅当任何节点的两棵子树的高度差不大于1的二叉树;
1591 排序二叉树(二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树);
1592 霍夫曼树(用于信息编码):带权路径最短的二叉树称为哈夫曼树或最优二叉树;
1593 B树:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多余两个子树。
1594 树的存储与表示
1595 顺序存储:将数据结构存储在固定的数组中,然在遍历速度上有一
1596 定的优势,但因所占空间比较大,是非主流二叉树。二叉树通常以链式存储。
1597
1598 树的顺序存储。链式存储和树的链式存储
1599
1600 由于对节点的个数无法掌握,常见树的存储表示都转换成二叉树进行
1601 处理,子节点个数最多为2
1602
1603 常见的一些树的应用场景
1604 1.xml,html等,那么编写这些东西的解析器的时候,不可避免用到树
1605 2.路由协议就是使用了树的算法
1606 3.mysql数据库索引
1607 4.文件系统的目录结构
1608 5.所以很多经典的AI算法其实都是树搜索,此外机器学习中的decision tree也是树结构
1609
1610
1611 -----------------------
1612 7.1 二叉树
1613
1614 二叉树的基本概念
1615 二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子
1616 树”(left subtree)和“右子树”(right subtree)
1617
1618 二叉树的性质(特性)
1619 性质1: 在二叉树的第i层上至多有2^(i-1)个结点(i>0)
1620 性质2: 深度为k的二叉树至多有2^k - 1个结点(k>0)
1621 性质3: 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
1622 性质4:具有n个结点的完全二叉树的深度必为 log2(n+1)
1623 性质5:对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,
1624 其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必
1625 为i/2(i=1 时为根,除外)
1626
1627 (1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层
1628 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子
1629 结点都是从左到右依次排布,这就是完全二叉树。
1630
1631 完全二叉树
1632 (2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处
1633 在最底层的二叉树。
1634
1635 满二叉树
1636
1637 二叉树的节点表示以及树的创建
1638 通过使用Node类中定义三个属性,分别为elem本身的值,还
1639 有lchild左孩子和rchild右孩子
1640
1641 class Node(object):
1642 """节点类"""
1643 def __init__(self, elem=-1, lchild=None, rchild=None):
1644 self.elem = elem
1645 self.lchild = lchild
1646 self.rchild = rchild
1647 树的创建,创建一个树的类,并给一个root根节点,一开始为空,随后添加节点
1648
1649 class Tree(object):
1650 """树类"""
1651 def __init__(self, root=None):
1652 self.root = root
1653
1654 def add(self, elem):
1655 """为树添加节点"""
1656 node = Node(elem)
1657 #如果树是空的,则对根节点赋值
1658 if self.root == None:
1659 self.root = node
1660 else:
1661 queue = []
1662 queue.append(self.root)
1663 #对已有的节点进行层次遍历
1664 while queue:
1665 #弹出队列的第一个元素
1666 cur = queue.pop(0)
1667 if cur.lchild == None:
1668 cur.lchild = node
1669 return
1670 elif cur.rchild == None:
1671 cur.rchild = node
1672 return
1673 else:
1674 #如果左右子树都不为空,加入队列继续判断
1675 queue.append(cur.lchild)
1676 queue.append(cur.rchild)
1677 e.g:
1678
1679 if __name__ == "__main__":
1680
1681 result:
1682
1683 -----------------------
1684 7.2 二叉树的遍历
1685
1686 树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信
1687 息的访问,即依次对树中每个结点访问一次且仅访问一次,我们把这种对
1688 所有节点的访问称为遍历(traversal)。那么树的两种重要的遍历模式
1689 是深度优先遍历和广度优先遍历,深度优先一般用递归,广度优先一般用
1690 队列。一般情况下能用递归实现的算法大部分也能用堆栈来实现。
1691
1692 深度优先遍历
1693 对于一颗二叉树,深度优先搜索(Depth First Search)是沿着
1694 树的深度遍历树的节点,尽可能深的搜索树的分支。那么深度遍历有重要
1695 的三种方法。这三种方式常被用于访问树的节点,它们之间的不同在于访
1696 问每个节点的次序不同。这三种遍历分别叫做先序遍历(preorder),
1697 中序遍历(inorder)和后序遍历(postorder)。我们来给出它们的
1698 详细定义,然后举例看看它们的应用。
1699
1700 先序遍历 在先序遍历中,我们先访问根节点,然后递归使用先序遍历访
1701 问左子树,再递归使用先序遍历访问右子树
1702
1703 根节点->左子树->右子树
1704 def preorder(self, root):
1705 """递归实现先序遍历"""
1706 if root == None:
1707 return
1708 print root.elem
1709 self.preorder(root.lchild)
1710 self.preorder(root.rchild)
1711 中序遍历 在中序遍历中,我们递归使用中序遍历访问左子树,然后访问
1712 根节点,最后再递归使用中序遍历访问右子树
1713
1714 左子树->根节点->右子树
1715 def inorder(self, root):
1716 """递归实现中序遍历"""
1717 if root == None:
1718 return
1719 self.inorder(root.lchild)
1720 print root.elem
1721 self.inorder(root.rchild)
1722 后序遍历 在后序遍历中,我们先递归使用后序遍历访问左子树和右子树,
1723 最后访问根节点。
1724
1725 左子树->右子树->根节点
1726 def postorder(self, root):
1727 """递归实现后续遍历"""
1728 if root == None:
1729 return
1730 self.postorder(root.lchild)
1731 self.postorder(root.rchild)
1732 print root.elem
1733
1734 三种遍历结果
1735 课堂练习: 按照如图树的结构写出三种遍历的顺序:
1736 树练习
1737 结果:
1738 先序:a b c d e f g h
1739 中序:b d c e a f h g
1740 后序:d e c b h g f a
1741 思考:哪两种遍历方式能够唯一的确定一颗树???
1742
1743 广度优先遍历(层次遍历)
1744 从树的root开始,从上到下从从左到右遍历整个树的节点
1745
1746 def breadth_travel(self, root):
1747 """利用队列实现树的层次遍历"""
1748 if root == None:
1749 return
1750 queue = []
1751 queue.append(root)
1752 while queue:
1753 node = queue.pop(0)
1754 print node.elem,
1755 if node.lchild != None:
1756 queue.append(node.lchild)
1757 if node.rchild != None:
1758 queue.append(node.rchild)
1759 e.g:
1760
1761 if __name__ == "__main__":
1762
1763 result:
1764
1765 ----------------------------------------------
1766
1767 ============================================================================
1768 '''
1769 #
1770
1771
1772
1773 #
1774 '''
1775 # ============================================================================
1776 # Function:
1777 # Explain : 输入参数
1778 # : 输出参数
1779 # ============================================================================
1780 '''
1781
1782 #-----------------------
1783 # 1.7 list的操作测试
1784
1785 def Function_Test_A():
1786 l = []
1787 for i in range(1000):
1788 l = l + [i]
1789
1790 def Function_Test_B():
1791 l = []
1792 for i in range(1000):
1793 l.append(i)
1794
1795 def Function_Test_C():
1796 l = [i for i in range(1000)]
1797
1798 def Function_Test_D():
1799 l = list(range(1000))
1800
1801 #-----------------------
1802 # 单链表
1803 #节点实现创建
1804 class Class_Single_Node(object):
1805 # 单链表的结点
1806 def __init__(self,item):
1807 # _item存放数据元素
1808 self.item = item
1809 # _next是下一个节点的标识
1810 self.next = None
1811
1812 #单链表的操作实现
1813 class SingleLinkList(object):
1814 # 单链表头文件
1815 def __init__(self):
1816 self._head = None
1817
1818 # 判断链表是否为空
1819 def is_empty(self):
1820 return self._head == None
1821
1822 # 链表长度
1823 def length(self):
1824 # cur初始时指向头节点
1825 current = self._head
1826 count = 0
1827 # 尾节点指向None,当未到达尾部时
1828 while current != None:
1829 count += 1
1830 current = current.next # 将cur后移一个节点
1831 return count
1832
1833 # 遍历链表
1834 def travel(self):
1835 current = self._head
1836 while current != None:
1837 print ("Travel Item : [%s]"%(current.item))
1838 current = current.next
1839 print ("Current Item : (%s)" % (current))
1840
1841 # 头部添加元素
1842 def add(self, item):
1843 # 先创建一个保存item值的节点 这是创建的前提条件
1844 Node = Class_Single_Node(item)
1845 # 将新节点的链接域next指向头节点,即_head指向的位置
1846 Node.next = self._head
1847 # 将链表的头_head指向新节点
1848 self._head = Node
1849
1850 # 尾部添加元素
1851 def append(self, item):
1852 Node = Class_Single_Node(item)
1853 # 先判断链表是否为空,若是空链表,则将_head指向新节点
1854 if self.is_empty():
1855 self._head = Node
1856 # 若不为空,则找到尾部,将尾节点的next指向新节点
1857 else:
1858 current = self._head
1859 while current.next != None:
1860 current = current.next
1861 current.next = Node
1862
1863 # 指定位置添加元素
1864 def insert(self, pos, item):
1865 # 若指定位置pos为第一个元素之前,则执行头部插入
1866 if pos <= 0:
1867 self.add(item)
1868 # 若指定位置超过链表尾部,则执行尾部插入
1869 elif pos > (self.length()-1):
1870 self.append(item)
1871 # 找到指定位置
1872 else:
1873 Node = Class_Single_Node(item) # 创建新的列表
1874 count = 0
1875 # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
1876 previous = self._head
1877 while count < (pos-1):
1878 count += 1
1879 previous = previous.next
1880 # 先将新节点node的next指向插入位置的节点
1881 Node.next = previous.next
1882 # 将插入位置的前一个节点的next指向新节点
1883 previous.next = Node
1884
1885 # 删除节点
1886 def remove(self,item):
1887 current = self._head
1888 previous = None
1889 while current != None:
1890 # 找到了指定元素
1891 if current.item == item:
1892 # 如果第一个就是删除的节点
1893 if not previous:
1894 # 将头指针指向头节点的后一个节点
1895 self._head = current.next
1896 else:
1897 # 将删除位置前一个节点的next指向删除位置的后一个节点
1898 previous.next = current.next
1899 break
1900 else:
1901 # 继续按链表后移节点
1902 previous = current
1903 current = current.next
1904
1905 #查找节点是否存在
1906 def search(self,item):
1907 # 表查找节点是否存在,并返回True或者False
1908 current = self._head
1909 while current != None:
1910 if current.item == item:
1911 return True
1912 current = current.next
1913 return False
1914
1915 #-----------------------
1916 # 单向循环链表
1917 # 单项节点创建 class Class_Single_Node(object):
1918
1919 class Class_SinCyc_Linkedlist(object):
1920 def __init__(self):
1921 self._head = None
1922
1923 # 判断链表是否为空
1924 def is_empty(self):
1925 return self._head == None
1926
1927 # 返回链表的长度
1928 def length(self):
1929 # 如果链表为空,返回长度0
1930 if self.is_empty():
1931 return 0
1932 count = 1
1933 current = self._head
1934 while current.next != self._head:
1935 count += 1
1936 current = current.next
1937 return count
1938
1939 # 遍历链表
1940 def travel(self):
1941 # 判断是否为空
1942 if self.is_empty():
1943 return
1944 current = self._head
1945 print("Travel Item : [%s]" % (current.item))
1946 while current.next != self._head:
1947 current = current.next
1948 print("Travel Item : [%s]" % (current.item))
1949 print("Travel Finish ")
1950
1951 # 头部添加节点
1952 def add(self, item):
1953 Node = Class_Single_Node(item)
1954 # 判断是否为空
1955 if self.is_empty():
1956 self._head = Node
1957 Node.next = self._head
1958 else:
1959 #添加的节点指向_head
1960 Node.next = self._head
1961 # 移到链表尾部,将尾部节点的next指向node
1962 current = self._head
1963 while current.next != self._head:
1964 current = current.next
1965 current.next = Node
1966 #_head指向添加node的
1967 self._head = Node
1968 # 尾部添加节点
1969 def append(self, item):
1970 Node = Class_Single_Node(item)
1971 if self.is_empty():
1972 self._head = Node
1973 Node.next = self._head
1974 else:
1975 # 移到链表尾部
1976 current = self._head
1977 while current.next != self._head:
1978 current = current.next
1979 # 将尾节点指向node
1980 current.next = Node
1981 # 将node指向头节点_head
1982 Node.next = self._head
1983 # 指定位置添加节点
1984 def insert(self, pos, item):
1985 if pos <= 0:
1986 self.add(item)
1987 elif pos > (self.length()-1):
1988 self.append(item)
1989 else:
1990 Node = Class_Single_Node(item)
1991 current = self._head
1992 count = 0
1993 # 移动到指定位置的前一个位置
1994 while count < (pos-1):
1995 count += 1
1996 current = current.next
1997 Node.next = current.next
1998 current.next = Node
1999
2000 def remove(self, item):
2001 """删除一个节点"""
2002 # 若链表为空,则直接返回
2003 if self.is_empty():
2004 return
2005 # 将cur指向头节点
2006 current = self._head
2007 pre = None
2008 # 若头节点的元素就是要查找的元素item
2009 if current.item == item:
2010 # 如果链表不止一个节点
2011 if current.next != self._head:
2012 # 先找到尾节点,将尾节点的next指向第二个节点
2013 while current.next != self._head:
2014 current = current.next
2015 # cur指向了尾节点
2016 current.next = self._head.next
2017 self._head = self._head.next
2018 else:
2019 # 链表只有一个节点
2020 self._head = None
2021 else:
2022 pre = self._head
2023 # 第一个节点不是要删除的
2024 while current.next != self._head:
2025 # 找到了要删除的元素
2026 if current.item == item:
2027 # 删除
2028 pre.next = current.next
2029 return
2030 else:
2031 pre = current
2032 current = current.next
2033 # current 指向尾节点
2034 if current.item == item:
2035 # 尾部删除
2036 pre.next = current.next
2037 # 查找节点是否存在
2038 def search(self, item):
2039 if self.is_empty():
2040 return False
2041 current = self._head
2042 if current.item == item:
2043 return True
2044 while current.next != self._head:
2045 current = current.next
2046 if current.item == item:
2047 return True
2048 return False
2049
2050 #-----------------------
2051 # 双向链表
2052
2053 # 双向链表节点
2054 class Class_Double_Node(object):
2055 def __init__(self, item):
2056 # _item存放数据元素
2057 self.item = item
2058 # _next是下一个节点的标识
2059 self.next = None
2060 # _prev是上一个节点的标识
2061 self.prev = None
2062
2063 # 双向链表操作
2064 class Class_Double_LinkList(object):
2065 def __init__(self):
2066 self._head = None
2067
2068 # 判断链表是否为空
2069 def is_empty(self):
2070 return self._head == None
2071
2072 # 链表的长度
2073 def length(self):
2074 current = self._head
2075 count = 0
2076 while current != None:
2077 count += 1
2078 current = current.next
2079 return count
2080
2081 # 遍历链表
2082 def travel(self):
2083 current = self._head
2084 while current != None:
2085 print("Travel Item : [%s]" % (current.item))
2086 current = current.next
2087 print("Travel Finish ")
2088
2089 # 头部插入元素
2090 def add(self, item):
2091 Node = Class_Double_Node(item)
2092 # 如果是空链表,将_head指向node
2093 if self.is_empty():
2094 self._head = Node
2095 else:
2096 # 将node的next指向_head的头节点
2097 Node.next = self._head
2098 # 将_head的头节点的prev指向node
2099 self._head.prev = Node
2100 # 将_head 指向node
2101 self._head = Node
2102
2103 # 尾部插入元素
2104 def append(self, item):
2105 Node = Class_Double_Node(item)
2106 # 如果是空链表,将_head指向node
2107 if self.is_empty():
2108 self._head = Node
2109 else:
2110 # 移动到链表尾部
2111 current = self._head
2112 while current.next != None:
2113 current = current.next
2114 # 将尾节点cur的next指向node
2115 current.next = Node
2116 # 将node的prev指向cur
2117 Node.prev = current
2118
2119 # 指定位置插入元素
2120 def insert(self, pos, item):
2121 if pos <= 0:
2122 self.add(item)
2123 elif pos > (self.length()-1):
2124 self.append(item)
2125 else:
2126 Node = Class_Double_Node(item)
2127 current = self._head
2128 count = 0
2129 # 移动到指定位置的前一个位置
2130 while count < (pos-1):
2131 count += 1
2132 current = current.next
2133 # 将node的prev指向cur
2134 Node.prev = current
2135 # 将node的next指向cur的下一个节点
2136 Node.next = current.next
2137 # 将cur的下一个节点的prev指向node
2138 current.next.prev = Node
2139 # 将cur的next指向node
2140 current.next = Node
2141 # 删除元素
2142 def remove(self, item):
2143 """删除元素"""
2144 if self.is_empty():
2145 return
2146 else:
2147 current = self._head
2148 if current.item == item:
2149 # 如果首节点的元素即是要删除的元素
2150 if current.next == None:
2151 # 如果链表只有这一个节点
2152 self._head = None
2153 else:
2154 # 将第二个节点的prev设置为None
2155 current.next.prev = None
2156 # 将_head指向第二个节点
2157 self._head = current.next
2158 return
2159 while current != None:
2160 if current.item == item:
2161 # 将cur的前一个节点的next指向cur的后一个节点
2162 current.prev.next = current.next
2163 # 将cur的后一个节点的prev指向cur的前一个节点
2164 current.next.prev = current.prev
2165 break
2166 current = current.next
2167
2168 # 查找元素是否存在
2169 def search(self, item):
2170 current = self._head
2171 while current != None:
2172 if current.item == item:
2173 return True
2174 current = current.next
2175 return False
2176
2177 #-----------------------
2178 # 队列
2179 class Class_Queue(object):
2180 def __init__(self):
2181 self.items = []
2182
2183 def is_empty(self):
2184 return self.items == []
2185
2186 # 进队列
2187 def enqueue(self, item):
2188 self.items.insert(0,item)
2189
2190 # 出队列
2191 def dequeue(self):
2192 return self.items.pop()
2193
2194 # 大小
2195 def size(self):
2196 return len(self.items)
2197
2198 #-----------------------
2199 # 双端队列
2200 # 创建双端队列
2201 class Class_Double_Queue(object):
2202 def __init__(self):
2203 self.items = []
2204
2205 #判断队列是否为空
2206 def is_empty(self):
2207 return self.items == []
2208
2209 #在队头添加元素
2210 def add_front(self, item):
2211 self.items.insert(0,item)
2212
2213 # 在队尾添加元素
2214 def add_rear(self, item):
2215 self.items.append(item)
2216
2217 #从队头删除元素
2218 def remove_front(self):
2219 return self.items.pop(0)
2220
2221 #从队尾删除元素
2222 def remove_rear(self):
2223 return self.items.pop()
2224
2225 #队列大小
2226 def size(self):
2227 return len(self.items)
2228
2229 #-----------------------
2230 # 冒泡排序
2231 def Function_Algorithm_BubbleSort(alist):
2232 local_var_alist = alist
2233 # print('local_var_alist',local_var_alist)
2234 # range(start,end,scan)
2235 # start:开始 end:结束 scan:步进长度,负为减少+(-X)
2236 for var_A in range(len(local_var_alist)-1,0,-1):
2237 # print("--------------------------")
2238 # print('var_A', var_A)
2239 # var_A表示每次遍历需要比较的次数,是逐渐减小的
2240 for var_B in range(var_A):
2241 # print('var_B', var_B)
2242 # print(local_var_alist[var_B], local_var_alist[var_B + 1])
2243 if local_var_alist[var_B] > local_var_alist[var_B + 1]:
2244 ### 二个数据交换,以下三步用一个表达式代替
2245 # # var_name = local_var_alist[var_B]
2246 # # local_var_alist[var_B] = local_var_alist[var_B + 1]
2247 # # local_var_alist[var_B + 1] = var_name
2248 local_var_alist[var_B], local_var_alist[var_B+1] = local_var_alist[var_B+1], local_var_alist[var_B]
2249
2250 #-----------------------
2251 # 选择排序
2252 def Function_Algorithm_SelectionSort(alist):
2253 local_var_alist = alist
2254
2255 number = len(local_var_alist)
2256 # 需要进行n-1次选择操作
2257 for var_A in range(number-1):
2258 # print("--------------------------")
2259 min_index = var_A # 记录最小位置
2260 # print('var_A: ', var_A, " --- min_index : ", min_index)
2261 # 从i+1位置到末尾选择出最小数据
2262 for var_B in range(var_A+1, number):
2263 # print("var_B:(%s) | var_A:(%s) | number:(%s)"%(var_B,var_A+1,number))
2264 # print(local_var_alist[var_B],local_var_alist[min_index])
2265
2266 if local_var_alist[var_B] < local_var_alist[min_index]:
2267 min_index = var_B
2268 # print(local_var_alist[var_B], local_var_alist[min_index])
2269 # 如果选择出的数据不在正确位置,进行交换
2270 if min_index != var_A:
2271 local_var_alist[var_A], local_var_alist[min_index] = local_var_alist[min_index], local_var_alist[var_A]
2272 # print(">>",local_var_alist[var_A],local_var_alist[min_index])
2273
2274 #-----------------------
2275 # 插入排序
2276 def Function_Algorithm_InsertSort(alist):
2277 local_var_alist = alist
2278 # 从第二个位置,即下标为1的元素开始向前插入
2279 for var_A in range(1, len(local_var_alist)):
2280 # 从第i个元素开始向前比较,如果小于前一个元素,交换位置
2281 for var_B in range(var_A, 0, -1):
2282 if local_var_alist[var_B] < local_var_alist[var_B-1]:
2283 local_var_alist[var_B], local_var_alist[var_B-1] = local_var_alist[var_B-1], local_var_alist[var_B]
2284
2285 #-----------------------
2286 # 快速排序
2287 #
2288 def Function_Algorithm_QuickSort(alist, start, end):
2289 """快速排序"""
2290 local_var_alist = alist
2291 local_var_start = start
2292 local_var_end = end
2293
2294 # 递归的退出条件
2295 if local_var_start >= local_var_end:
2296 return
2297
2298 # 设定起始元素为要寻找位置的基准元素
2299 list_mid = local_var_alist[local_var_start]
2300 # low为序列左边的由左向右移动的游标
2301 list_low = local_var_start
2302 # high为序列右边的由右向左移动的游标
2303 list_high = local_var_end
2304
2305 print("1 >>",list_low,list_mid,list_high)
2306
2307 while list_low < list_high:
2308 print("L H",list_low,list_high)
2309 # 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
2310 while list_low < list_high and local_var_alist[list_high] >= list_mid:
2311 list_high -= 1
2312 # 将high指向的元素放到low的位置上
2313 local_var_alist[list_low] = local_var_alist[list_high]
2314 print("2 >>", local_var_alist[list_low] )
2315 # 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
2316 while list_low < list_high and local_var_alist[list_low] < list_mid:
2317 list_low += 1
2318 # 将low指向的元素放到high的位置上
2319 local_var_alist[list_high] = local_var_alist[list_low]
2320 print("3 >>", local_var_alist[list_high])
2321 print("----------")
2322 # 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
2323 # 将基准元素放到该位置
2324
2325 local_var_alist[list_low] = list_mid
2326 print("4 >>", local_var_alist[list_low])
2327 print("==================")
2328 # # 对基准元素左边的子序列进行快速排序
2329 Function_Algorithm_QuickSort(local_var_alist, local_var_start, list_low-1)
2330 #
2331 # # 对基准元素右边的子序列进行快速排序
2332 Function_Algorithm_QuickSort(local_var_alist, list_low+1, local_var_end)
2333
2334 #-----------------------
2335 # 希尔排序
2336 def Function_Algorithm_ShellSort(alist):
2337 n = len(alist)
2338 # 初始步长
2339 var = n / 2
2340 gap = int(var)
2341 print(gap,type(gap))
2342 while gap > 0:
2343 # 按步长进行插入排序
2344 for i in range(gap, n):
2345 j = i
2346 # 插入排序
2347 while j>=gap and alist[j-gap] > alist[j]:
2348 alist[j-gap], alist[j] = alist[j], alist[j-gap]
2349 j -= gap
2350 # 得到新的步长
2351 gap = gap / 2
2352
2353
2354
2355 #-----------------------
2356 # 归并排序
2357 # def merge_sort(alist):
2358 # if len(alist) <= 1:
2359 # return alist
2360 # # 二分分解
2361 # num = len(alist)/2
2362 # print(num)
2363 # left = merge_sort(alist[:num])
2364 # print(left)
2365 # right = merge_sort(alist[num:])
2366 # # 合并
2367 # return merge(left,right)
2368
2369 # def merge(left, right):
2370 # '''合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组'''
2371 # #left与right的下标指针
2372 # l, r = 0, 0
2373 # result = []
2374 # while l<len(left) and r<len(right):
2375 # if left[l] < right[r]:
2376 # result.append(left[l])
2377 # l += 1
2378 # else:
2379 # result.append(right[r])
2380 # r += 1
2381 # result += left[l:]
2382 # result += right[r:]
2383 # return result
2384
2385
2386 #-----------------------
2387 #
2388
2389
2390 #----------------------------------------------
2391 # ============================================================================
2392 '''
2393 # ============================================================================
2394 # 测试专用
2395 # ============================================================================
2396 '''
2397 if __name__ == "__main__":
2398
2399 # #-----------------------
2400 # # 引入
2401 # start_time = time.time()
2402 #
2403 # # 注意是三重循环
2404 # for a in range(0, 1001):
2405 # for b in range(0, 1001):
2406 # for c in range(0, 1001):
2407 # if a ** 2 + b ** 2 == c ** 2 and a + b + c == 1000:
2408 # print("a, b, c: %d, %d, %d" % (a, b, c))
2409 #
2410 # end_time = time.time()
2411 # print("elapsed: %f" % (end_time - start_time))
2412 # print("complete!")
2413 # #
2414
2415
2416
2417 #-----------------------
2418 # start_time = time.time()
2419 #
2420 # # 注意是两重循环
2421 # for a in range(0, 1001):
2422 # for b in range(0, 1001 - a):
2423 # c = 1000 - a - b
2424 # if a ** 2 + b ** 2 == c ** 2:
2425 # print("a, b, c: %d, %d, %d" % (a, b, c))
2426 #
2427 # end_time = time.time()
2428 # print("elapsed: %f" % (end_time - start_time))
2429 # print("complete!")
2430 # #
2431
2432
2433
2434 # -----------------------
2435 # 1.7
2436 # # 固定格式
2437 # #创建对象:函数名 测试代码语句 运行代码设置
2438 # time_A = Timer("Function_Test_A()", "from __main__ import Function_Test_A")
2439 # # 执行速度设置 固定格式
2440 # print("time_A:", time_A.timeit(number=100), "seconds")
2441 #
2442 # time_B = Timer("Function_Test_B()", "from __main__ import Function_Test_B")
2443 # print("time_B ", time_B.timeit(number=100), "seconds")
2444 # time_C = Timer("Function_Test_C()", "from __main__ import Function_Test_C")
2445 # print("time_C ", time_C.timeit(number=100), "seconds")
2446 # time_D = Timer("Function_Test_D()", "from __main__ import Function_Test_D")
2447 # print("time_D ", time_D.timeit(number=100), "seconds")
2448 # #
2449
2450
2451
2452 # # -----------------------
2453 # # 单链表
2454 # single_list_name_A = SingleLinkList()
2455 # single_list_name_A.add(11) # 头部添加元素
2456 # single_list_name_A.add(12) # 头部添加元素
2457 # single_list_name_A.add(13) # 头部添加元素
2458 # single_list_name_A.append(24) # 尾部添加元素
2459 # single_list_name_A.insert(3, 35) # 指定位置添加元素
2460 # single_list_name_A.append(26) # 尾部添加元素
2461 # single_list_name_A.travel() # 遍历链表
2462 # print ("Length:[%s]"%(single_list_name_A.length()))
2463 # print(single_list_name_A.search(35)) # 查找节点是否存在
2464 # print(single_list_name_A.search(15)) # 查找节点是否存在
2465 # single_list_name_A.remove(11) # 删除节点
2466 # single_list_name_A.travel() # 遍历链表
2467 # print("Length:[%s]" % (single_list_name_A.length()))
2468 # #
2469
2470
2471 # # -----------------------
2472 # # 单链表循环
2473 # single_list_name_B = Class_SinCyc_Linkedlist()
2474 # print("Length:[%s]" % (single_list_name_B.length()))
2475 # single_list_name_B.add(11) # 头部添加元素
2476 # single_list_name_B.add(12) # 头部添加元素
2477 # single_list_name_B.add(13) # 头部添加元素
2478 # single_list_name_B.append(21) # 尾部添加元素
2479 # single_list_name_B.insert(1, 31) # 指定位置添加元素
2480 # single_list_name_B.insert(3, 32) # 指定位置添加元素
2481 # single_list_name_B.insert(5, 33) # 指定位置添加元素
2482 # single_list_name_B.append(22) # 尾部添加元素
2483 # single_list_name_B.travel() # 遍历链表
2484 # print("Length:[%s]" % (single_list_name_B.length()))
2485 # print(single_list_name_B.search(11))# 查找节点是否存在
2486 # print(single_list_name_B.search(22))# 查找节点是否存在
2487 # print(single_list_name_B.search(55))# 查找节点是否存在
2488 # single_list_name_B.remove(11)
2489 # single_list_name_B.travel() # 遍历链表
2490 # print("Length:[%s]" % (single_list_name_B.length()))
2491 # #
2492
2493
2494 # # -----------------------
2495 # # 双向链表
2496 # single_list_name_C = Class_Double_LinkList()
2497 # print("Length:[%s]" % (single_list_name_C.length()))
2498 # single_list_name_C.add(111) # 头部添加元素
2499 # single_list_name_C.add(112) # 头部添加元素
2500 # single_list_name_C.add(113) # 头部添加元素
2501 # single_list_name_C.add(114) # 头部添加元素
2502 # single_list_name_C.add(115) # 头部添加元素
2503 # single_list_name_C.append(211) # 尾部添加元素
2504 # single_list_name_C.append(212) # 尾部添加元素
2505 # single_list_name_C.append(213) # 尾部添加元素
2506 # single_list_name_C.travel() # 遍历链表
2507 # print("Length:[%s]" % (single_list_name_C.length()))
2508 # single_list_name_C.insert(2, 311) # 指定位置添加元素
2509 # single_list_name_C.insert(4, 312) # 指定位置添加元素
2510 # single_list_name_C.insert(6, 313) # 指定位置添加元素
2511 # print(single_list_name_C.search(111)) # 查找节点是否存在
2512 # print(single_list_name_C.search(211)) # 查找节点是否存在
2513 # print(single_list_name_C.search(311)) # 查找节点是否存在
2514 # single_list_name_C.travel() # 遍历链表
2515 # print("Length:[%s]" % (single_list_name_C.length()))
2516 # single_list_name_C.remove(112)
2517 # single_list_name_C.remove(113)
2518 # single_list_name_C.remove(114)
2519 # single_list_name_C.remove(115)
2520 # single_list_name_C.remove(211)
2521 # single_list_name_C.remove(212)
2522 # single_list_name_C.travel() # 遍历链表
2523 # print("Length:[%s]" % (single_list_name_C.length()))
2524 # #
2525
2526
2527
2528 # # # -----------------------
2529 # # 队列
2530 # queue_name_A = Class_Queue() # 创建对象
2531 # queue_name_A.enqueue("hello") # 进队列
2532 # queue_name_A.enqueue("world") # 进队列
2533 # queue_name_A.enqueue("it cast") # 进队列
2534 # print(queue_name_A.size())
2535 # queue_name_A.dequeue() # 出队列
2536 # print(queue_name_A.size())
2537 # queue_name_A.dequeue() # 出队列
2538 # print(queue_name_A.size())
2539 # queue_name_A.dequeue() # 出队列
2540 # print(queue_name_A.size())
2541 # #
2542
2543
2544 # # -----------------------
2545 # # 双端队列
2546 # Class_Double_Queue = Class_Double_Queue()
2547 # Class_Double_Queue.add_front(111) # 从队头加入一个item元素
2548 # Class_Double_Queue.add_front(112) # 从队头加入一个item元素
2549 # Class_Double_Queue.add_rear(213) # 从队尾加入一个item元素
2550 # Class_Double_Queue.add_rear(214) # 从队尾加入一个item元素
2551 # Class_Double_Queue.size()
2552 # print(Class_Double_Queue.size())
2553 # Class_Double_Queue.remove_front() # 从队头删除一个item元素
2554 # print(Class_Double_Queue.size())
2555 # Class_Double_Queue.remove_front() # 从队头删除一个item元素
2556 # print(Class_Double_Queue.size())
2557 # Class_Double_Queue.remove_rear() # 从队尾删除一个item元素
2558 # print(Class_Double_Queue.size())
2559 # Class_Double_Queue.remove_rear() # 从队尾删除一个item元素
2560 # print(Class_Double_Queue.size())
2561 # #
2562
2563
2564
2565 # #-----------------------
2566 # # 冒泡排序
2567 # BubbleSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
2568 # print("P",BubbleSort_name_A) # 前
2569 # Function_Algorithm_BubbleSort(BubbleSort_name_A)
2570 # print("N",BubbleSort_name_A) # 后
2571 # #
2572
2573
2574 # # #-----------------------
2575 # # 选择排序
2576 # SelectionSort_name_A = [54, 226, 93, 17, 77, 31, 44, 55, 20]
2577 # print("P",SelectionSort_name_A)
2578 # Function_Algorithm_SelectionSort(SelectionSort_name_A)
2579 # print("N",SelectionSort_name_A)
2580 # #
2581
2582
2583
2584 # # #-----------------------
2585 # # 插入排序
2586 # InsertionSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
2587 # print("P",InsertionSort_name_A)
2588 # Function_Algorithm_InsertSort(InsertionSort_name_A)
2589 # print("N",InsertionSort_name_A)
2590 # #
2591
2592
2593 # # #-----------------------
2594 # # #快速排序
2595 # QuickSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20]
2596 # print("P", QuickSort_name_A)
2597 # Function_Algorithm_QuickSort(QuickSort_name_A, 0, len(QuickSort_name_A) - 1)
2598 # print("N", QuickSort_name_A)
2599 # #
2600
2601
2602
2603 # #-----------------------
2604 # # 希尔排序
2605 # ShellSort_name_A = [54, 26, 93, 17, 77, 31, 44, 55, 20, 99]
2606 # print(ShellSort_name_A)
2607 # Function_Algorithm_ShellSort(ShellSort_name_A)
2608 # print(ShellSort_name_A)
2609 # #
2610
2611
2612 # #-----------------------
2613 # # 归并排序 不成立
2614 # alist = [54, 26, 93, 17, 77, 31, 44, 55, 20,78]
2615 # # sorted_alist = merge_sort(alist)
2616 # asd = merge_sort(alist)
2617 # print(asd)
2618 # # print(sorted_alist)
2619
2620 print(" learn finish")
----------------------------------------------------