Python_Example_ Data Structures and Algorithm Analysis 学习/示例
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")
--------
--------------------------------------------
愿:
可以帮助到您,
感谢您的阅读。