python数据结构与算法知识点_数据结构与算法系列(三)—— 经典知识点总结

引入

程序设计语言基本数据类型:int,float,char

Python内置数据结构:list,dict,tuple.

Python扩展数据结构:栈,队列

存储一个student的name,age,hometown的方式

列表+元组:[

('zhangsan',24,'beijing'),

('zhangsan',24,'beijing'),

('zhangsan',24,'beijing'),

]for stu instus:if stu[0] == 'zhangsan':

列表+字典 [

{'name':'zhangsan'},

{'age':23},

{'hometown':'beijjing'},

]

字典:{'zhangsan':{'age':24,'hometown':'beijing',

}

}

stu['zhangsan']

经典知识点总结

1.算法与数据结构的概念

算法是指要解决问题的思路

数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。

2.数据结构和算法的区别

(1).数据结构只是静态的描述了数据元素之间的关系

(2).高效的程序需要在数据结构的基础上设计和选择算法

程序= 算法 +数据结构

总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体

3.抽象数据类型(Abstract Data Type)

ADT概念:是指一个数学模型以及定义在这个数学模型上的一组操作的集合,即把数据类型和数据类型上的运算绑定在一起,

进行封装。对外只声明存储方式和调用方法,具体实现隐藏。

引入抽象数据类型的目的是把数据类型的表示和数据类型上的运算的实现与这些数据类型和运算在程序中的引用隔开,使他们相互独立。

常用的数据运算有五种:

插入

删除

修改

查找

排序

4.时间复杂度

衡量程序执行效率的快慢,称为时间复杂度。

算法完成任务最少需要多少基本操作,即最优时间复杂度。(最乐观最理想,价值不大)

算法完成任务最多需要多少基本操作,即最差时间复杂度。(提供了一种保证,主要关注)

算法完成任务平均需要多少基本操作,即平均时间复杂度。(算法的全面评价)

时间复杂度的几条基本计算规则1.基本操作,即只有常数项,认为其时间复杂度为〇(1)2.顺序结构,时间复杂度按加法计算3.循环结构,时间复杂度按乘法计算4.分支结构,时间复杂度取最大值5.判断一个算法的效率时,往往只需关注操作数量的最高次频,其他次要项和常数项可以忽略6.在没有特殊说明时,我们所分析的算法的时间复杂度,通常指的都是最坏时间复杂度。

常见时间复杂度比较:〇(1)

5.线性表:

线性表:一组序列元素的组织形式,一个线性表是某类元素的集合,还记录着元素之间的一种顺序关系,线性表是最基本的数据结构之一。

顺序表:将元素顺序的存放在一块连续的存储区里,元素间的顺序关系由他们的存储顺序自然表示。

链表:将元素存放在通过链接构造起来的一系列存储块中。

6.顺序表

顺序表:数据元素本身连续存储,每个元素所占的存储单元大小固定相同,元素的下标是其逻辑地址,而元素存储的物理地址(实际内存地址)可以通过存储区的起始地址Loc(e0)加上逻辑地址

(第i个元素)与存储单元大小(c)的乘积计算而得,即:Loc(ei) = Loc(e0)+c*i

故,访问指定元素无需从头遍历,通过计算便可获得对应地址,其时间复杂度为〇(1)

注:操作系统最小寻址单位是字节。int类型占四个字节,char类型占1个字节。计算机存储索引从0开始,表示偏移量。

顺序表的存储方式:顺序表的基本方式,顺序表的外置元素方式

顺序表的结构:一部分是表中元素的集合,另一部分是为实现正确操作而需记录的信息

表头信息(表头存储区的容量,当前表中已有元素个数),数据区

顺序表存储结构:一体式,分离式。区别:增加容量时,分离式表头不变,一体式表头改变

7.链表的提出

顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。

链表结构可以充分利用计算机的内存空间,实现灵活的内存动态管理。

8.链表

8.1-定义:链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放

下一个节点的位置信息(即地址)。8.2-单向链表:也叫单链表,是链表中最简单的一种形式。它的每个节点包含两个域,一个信息域(元素域),一个链接域。这个链接指向链表中的

下一个结点,而最后一个节点的链接则指向一个空值。

表元素域elem用来存放具体的数据

链接域next用来存放下一个节点的位置(python中的标识)

变量p指向链表的头结点(首节点)的位置,从p出发能找到表中的任意节点。8.3python变量标识的本质

a= 10,首先会在内存中开启两个内存块,一个存储10,一个存储地址,这个地址指向10,给这个地址取名a。

a,b=b,a 交换的是a,b原来维护的指向内存块的地址。8.4双向链表:每个节点有两个链接,一个指向前一个节点(前驱),一个指向后一个节点(后继)。当此节点为第一个节点时,前驱为空,

当此节点为尾节点时,后继为空。

9.链表和顺序表的对比

9.1顺序表

优点:(1) 方法简单,各种高级语言中都有数组,容易实现。

(2) 不用为表示结点间的逻辑关系而增加额外的存储开销。

(3) 顺序表具有按元素序号随机访问的特点。

缺点:(1) 在顺序表中做插入删除操作时,需要对所有元素进行前后移位操作,只能通过拷贝和覆盖的方式,

平均移动大约表中一半的元素,因此对n较大的顺序表效率低。

(2) 需要预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,

又会造成溢出。9.2链表

优点:(1) 在链表中做插入删除操作时,不会影响前面和后面的节点,因此对n较大的链表效率高。

(2) 不需要预先分配足够大的存储空间,避免造成空间闲置或溢出的情况。

缺点:(1) 需要为表示结点间的逻辑关系(指针变量)而增加额外的存储开销。

(2) 只能通过遍历找到某个节点,不能使用下标直接定位节点。9.3选择合适的数据结构9.3.1基于存储的考虑

顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模,也就是说事先对"MAXSIZE"要有合适的设定,过大造成浪费,

过小造成溢出。可见对线性表的长度或存储规模难以估计时,不宜采用顺序表;链表不用事先估计存储规模,但链表的存储密度较低

(存储密度是指一个结点中数据元素所占的存储单元和整个结点所占的存储单元之比,显然链式存储结构的存储密度是小于1的)。9.3.2基于运算的考虑

在顺序表中按序号访问 ai的时间性能时O(1),而链表中按序号访问的时间性能O(n),所以如果经常做的运算是按序号访问数据元素,

显然顺序表优于链表;而在顺序表中做插入、删除时平均移动表中一半的元素,当数据元素的信息量较大且表较长时,这一点是不应忽视的;

在链表中作插入、删除,虽然也要找插入位置,但操作主要是比较操作,从这个角度考虑显然后者优于前者。9.3.3基于环境的考虑

顺序表容易实现,任何高级语言中都有数组类型,链表的操作是基于指针的,相对来讲前者简单些,也是用户考虑的一个因素。

注:顺序表和链表抓主要用于存储,栈和队列主要用于对数据的操作。

10.栈:只允许在表的一端进行操作的线性表,FILO(先进后出)

11.队列:只允许在表尾插入,表头删除的线性表,FIFO(先进先出)

12.双端队列:具有栈和队列的性质的数据结构,可以在队列的任意一端入队和出队

13:栈(Stack)和队列(Queue)是两种操作受限的线性表。

线性表:线性表是一种线性结构,它是一个含有n≥0个结点的有限序列,同一个线性表中的数据元素数据类型相同并且满足“一对一”的逻辑关系。

“一对一”的逻辑关系指的是对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点,有且仅有一个终端结点没有后继但有

一个前驱结点,其它的结点都有且仅有一个前驱和一个后继结点。

这种受限表现在:栈的插入和删除操作只允许在表的尾端进行(在栈中成为“栈顶”),满足“FIFO:First In Last Out”;

队列只允许在表尾插入数据元素,在表头删除数据元素,满足“First In First Out”。

栈与队列的相同点:1.都是线性结构。2.插入操作都是限定在表尾进行。3.都可以通过顺序结构和链式结构实现。、4.插入与删除的时间复杂度都是O(1),在空间复杂度上两者也一样。5.多链栈和多链队列的管理模式可以相同。

栈与队列的不同点:1.删除数据元素的位置不同,栈的删除操作在表尾进行,队列的删除操作在表头进行。 2.应用场景不同;常见栈的应用场景包括括号问题的求解,表达式的转换和求值,函数调用和递归实现,深度优先搜索遍历等;常见的队列的应用场景包括计算机系统中各种资源的管理,消息缓冲器的管理和广度优先搜索遍历等。3.顺序栈能够实现多栈空间共享,而顺序队列不能。

14.排序

稳定性:两个相同的元素在排序之后相对位置不发生改变称之为稳定排序。14.1交换排序:

冒泡排序:每次循环找出最大值或最小值

时间复杂度:最优 〇(n) 序列有序

最差 〇(n2)

稳定性:稳定

快速排序:划分交换排序(partition-exchange sort),通过一趟偶排序将要排序的数据分割成独立的两部分,一部分的元素比另一部分的元素都要小。

然后在按此方法对两部分数据分别进行快速排序,整个排序可以递归进行,以此达到整个数据变成有序序列

时间复杂度:最优 〇(nlogn)

最差 〇(n2)

稳定性:不稳定14.2选择排序:每次从无序序列中选择一个最大值或最小值放在一端。

时间复杂度:最优 〇(n2)

最差 〇(n2)

稳定性:不稳定(考虑升序每次选择最大的情况)2,2,1

14.3插入排序14.3.1直接插入排序:每次从无序序列中按顺序拿一个元素插入有序序列中的正确位置。

时间复杂度:最优 〇(n) 升序排序,序列已经处于升序状态

最差 〇(n2)

稳定性:稳定14.3.2希尔排序:缩小增量排序

时间复杂度:最优 根据步长序列的不同而不同

最差 〇(n2)

稳定性:不稳定2,2,1

14.4归并排序:分治法,先递归分解数组,再合并数组

时间复杂度: 最优:〇(nlogn)

最差: 〇(nlogn)

稳定性:稳定

15.搜索

二分查找法:又称折半查找。优点是比较次数少,查找速度快,平均性能好。缺点是要求待查表为有序表,且插入删除困难。因此,折半查找适用于不经常变 动而查找频繁的有序列表。

时间复杂度: 最优:〇(1)

最差: 〇(logn)

16.树:由n(n>=1)个有限节点组成一个具有层次关系的集合。一对多。

特点:(1)每个节点有零个或多个子节点

(2)没有父节点的节点称为根节点

(3)每一个非根节点有且只有一个父节点

(4)除了根节点外,每个子节点可以分为多个不相交的子树。

术语:节点的度:一个节点含有子树的个数

树的度:一棵树中,最大节点的度称为树的度。

叶节点或终端节点:度为零的节点。

父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。

子节点:一个节点含有的子树的根节点称为该节点的子节点。

兄弟节点:具有相同的父节点的节点互称为兄弟节点。

节点的层次:从根节点开始定义,根为第一层,根的子节点为第2层,以此类推。

树的深度或高度:树中节点的最大层次。

堂兄弟节点:父节点在同一层次的节点互称为堂兄弟。

节点的祖先:从根到该节点所经分支上的所有节点。

子孙:以某节点为根的子树中任一节点成为该节点的子孙。

森林:由m(m>=0)棵互不相交的树的集合称为森林。

树的种类:

无序树:树中任意节点的子节点之间没有顺序关系,这种关系成为无序树。

有序树:树中任意节点的子节点之间有顺序关系。这种关系称为有序树。

二叉树:每个节点最多含有两个子树的树称为二叉树。

完全二叉树:对于一个二叉树,假设其深度为d.除了第d层外,其他各层的节点数目均已达最大值,且第d层所有节点

从左到右连续紧密排列。对于这样的二叉树称为完全二叉树。

满二叉树:所有叶节点都在最底层的完全二叉树。

平衡二叉树(AVL树):当且仅当任何节点的两颗子树的高度差不大于1的二叉树。

排序二叉树(二叉查找树,二叉搜索树,有序二叉树)

哈夫曼树(用于信息编码):带权路径最短的二叉树称为哈夫曼树或最优二叉树。

B树:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多余两个子树。

17.树的存储方式

顺序存储:速度快,所占空间大。

链式存储:可以存储。缺点:指针域个数不定。

18.应用场景:

(1)xml,html

(2)路由协议

(3)mysql数据库索引

(4)文件系统的目录结构

(5)很多经典的AI算法,比如机器学习的(decision tree)决策树也是树结构

19.二叉树:每个节点最多含有两个子树的树称为二叉树。

性质1:二叉树第i层最多只有2^(i-1)个节点。

性质2:深度为k的二叉树最多有(2^k)-1个节点

性质3:叶子节点的个数与度为2的节点的个数满足n0=n2+1性质4: 具有n个节点的完全二叉树的深度必为log2(n+1)

性质5:完全二叉树,从上到下,从左到右,编号为i的节点,其左孩子编号为2i,右孩子编号为2i+1,其父节点为i/2(根节点除外)

20.二叉树的遍历

广度遍历:队列:先进先出

深度优先:栈:后进先出

前序遍历:根左右

中序遍历:左根右

后序遍历:左右根

先序:01 3 7 8 4 9 2 5 6中序:7 3 8 1 9 4 0 5 2 6后序:7 8 3 9 4 1 5 6 20

01 2

3 4 5 6

7 89

算法实现(基于Python)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/6

@Author: Zhang Yafei"""

"""时间复杂度:衡量算法执行效率的快慢

a+b+c=1000,且a^2+b^2=c^2(a,b,c为自然数),如何求出所有a,b,c的自然数组合?

a,b,c

总时间=基本运算数量*执行次数

每台机器执行的总时间不同

但是执行基本运算数量大体相同"""

importtime

start_time=time.time()#for a in range(1001):#for b in range(1001):#for c in range(1001):#if a+b+c==1000 and a**2+b**2==c**2:#print('a,b,c:',a,b,c) #222秒

"""T = 1000 * 1000 * 1000 * 2

T = 2000 * 2000 * 2000 * 2

T = N * N * N *2

T(n) = n^3 * 2

T(n) = n^3 * 10

T(n) = n^3 * k

从数学上,T(n) = k*g(n),在现实中,省去细枝末叶,只剩下最显著特征

T(n) = g(n)

g(n) = n^3"""

#顺序#条件#循环

for a in range(1001):for b in range(1001):

c= 1000-a-bif a**2+b**2==c**2:print('a,b,c:',a,b,c) #1秒

end_time =time.time()print('times:',end_time-start_time)print('finished')"""T(n) = n * n *(1+max(1,0))

= n^2*2

= 〇(n^2)"""

1.算法基础

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/6

@Author: Zhang Yafei"""

from timeit importTimer"""li1 = [1,2]

li2 = [23,5]

li = li1 + li2

li = [i for i in range(10000)]

li = list(range(10000))"""

deft1():

li=[]for i in range(10000):

li.append(i)deft2():

li=[]for i in range(10000):#li = li + [i] #218秒

li += [i] #1.04

deft3():

li= [i for i in range(10000)]deft4():

li= list(range(10000))deft5():

li=[]for i in range(10000):

li.extend([i])

timer1= Timer("t1()","from __main__ import t1")print('append:',timer1.timeit(1000))

timer2= Timer("t2()","from __main__ import t2")print('+:',timer2.timeit(1000))

timer3= Timer("t3()","from __main__ import t3")print('[i for i in range]:',timer3.timeit(1000))

timer4= Timer("t4()","from __main__ import t4")print('list(range())',timer4.timeit(1000))

timer5= Timer("t5()","from __main__ import t5")print('extend:',timer5.timeit(1000))deft6():

li=[]for i in range(10000):

li.append(i)deft7():

li=[]for i in range(10000):

li.insert(0,i)#timer6 = Timer("t6()","from __main__ import t6")#print('append:',timer6.timeit(1000))

timer7 = Timer("t7()","from __main__ import t7")print('insert:',timer7.timeit(1000))

2.list效率对比

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/11

@Author: Zhang Yafei"""

importsysfrom timeit importTimer

reps= 1000size= 10000

defforStatement():

res=[]for x inrange(size):

res.append(abs(x))#列表解析

deflistComprehension():

res= [abs(x) for x inrange(size)]#map

defmapFunction():

res=list(map(abs, range(size)))#生成器表达式

defgeneratorExpression():

res= list(abs(x) for x inrange(size))if __name__ == '__main__':print(sys.version)

timer1= Timer("forStatement()", "from __main__ import forStatement")print('for循环append', timer1.timeit(reps))

timer2= Timer("listComprehension()", "from __main__ import listComprehension")print('列表生成式', timer2.timeit(reps))

timer3= Timer("mapFunction()", "from __main__ import mapFunction")print('map:', timer3.timeit(reps))

timer4= Timer("generatorExpression()", "from __main__ import generatorExpression")print('生成器表达式', timer4.timeit(reps))

3.for_map_list生成式_生成器表达式

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/8

@Author: Zhang Yafei"""

classNode(object):"""节点"""

def __init__(self,elem):

self.elem=elem

self.next=NoneclassSingleLinkList(object):"""单链表"""

def __init__(self,node=None):

self.__head =nodedef __str__(self):if not self.__head:return 'None'

else:

cur= self.__headlist_str= ''

whilecur:

cur_str= '{}->'.format(cur.elem) if cur.next elsestr(cur.elem)

list_str+=cur_str

cur=cur.nextreturnlist_strdefis_empty(self):"""链表是否为空"""

return self.__head isNonedeflength(self):"""链表长度"""

#cur游标,用来移动遍历节点

cur = self.__head

#count记录数量

count =0while cur: #cur.next == None

cur =cur.next

count+= 1

returncountdeftravel(self):"""遍历整个链表"""cur= self.__head

whilecur:print(cur.elem,end=" ")

cur=cur.nextprint('')defadd(self,item):"""链表头部添加元素,头插法"""node=Node(item)

node.next= self.__headself.__head =nodedefappend(self,item):"""链表尾部添加元素,尾插法"""node=Node(item)if self.is_empty():#链表判空

self.__head =nodeelse:

cur= self.__head

whilecur.next:

cur=cur.next

cur.next=nodedef insert(self,pos,item): #insert(2,100)

"""指定位置添加元素

:param pos 从0开始"""

if pos<=0:

self.add(item)elif pos>(self.length()-1):

self.append(item)else:

node=Node(item)

pre= self.__headcount=0while count < pos-1:

pre=pre.next

count+= 1

#当循环退出后,pre指向pos-1位置

node.next =pre.next

pre.next=nodedefremove(self,item):"""删除节点"""cur= self.__headprev=Nonewhilecur:if cur.elem ==item:#先判断此节点是否是头结点

if cur == self.__head:

self.__head =cur.nextelse:

prev.next=cur.nextbreak

else:

prev=cur

cur=cur.nextdefsearch(self,item):"""查询节点是否存在"""cur= self.__head

whilecur:if cur.elem ==item:returnTrue

cur=cur.nextreturnFalsedefindex(self,item):"""查询节点是否存在"""cur= self.__headcount=0whilecur:if cur.elem ==item:returncount

cur=cur.next

count+= 1

return '{} is not in linklist'.format(item)defvalue(self,index):"""查找指定位置的值"""

ifself.is_empty():returnNoneelif index>self.length()-1:return 'linklist index out of range'cur= self.__headcount=0while count

count+= 1cur=cur.nextreturncur.elemif __name__ == '__main__':

ll=SingleLinkList()print(ll.is_empty())print(ll.length())#print(ll)

ll.append(1)print(ll.is_empty())print(ll.length())

ll.append(2)

ll.add(8)

ll.append(3)

ll.append(4)

ll.append(5)

ll.append(6)#print(ll)

ll.insert(-1,9) #9,8,123456

ll.travel()

ll.insert(3,100) #9,8,1,100,23456

ll.travel()

ll.insert(10,200) #9,8,1,100,23456,200

ll.travel()

ll.remove(9)

ll.travel()

ll.remove(100)

ll.travel()

ll.remove(200)

ll.travel()print(ll.value(3))print(ll.index(7))

4.单链表

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/9

@Author: Zhang Yafei"""

classNode(object):"""结点"""

def __init__(self,item):

self.elem=item

self.prev=None

self.next=NoneclassDoubleLinkList(object):"""双链表"""

def __init__(self,node=None):#默认为None第一次创建空链表

self.__head =nodedef __str__(self):

self.travel()return

defis_empty(self):"""链表是否为空"""

return self.__head isNonedeflength(self):"""链表长度"""

#cur游标,用来移动遍历节点

cur = self.__head

#count记录数量

count =0while cur: #cur.next == None

cur =cur.next

count+= 1

returncountdeftravel(self):"""遍历整个链表"""cur= self.__head

whilecur:print(cur.elem,end=" ")

cur=cur.nextprint('')defadd(self,item):"""链表头部添加元素,头插法"""node=Node(item)

node.next= self.__headself.__head =node

node.prev=Nonedefappend(self,item):"""链表尾部添加元素,尾插法"""node=Node(item)if self.is_empty():#链表判空

self.__head =nodeelse:

cur= self.__head

whilecur.next:

cur=cur.next

cur.next=node

node.prev=curdef insert(self,pos,item): #insert(2,100)

"""指定位置添加元素

:param pos 从0开始"""

if pos<=0:

self.add(item)elif pos>(self.length()-1):

self.append(item)else:

cur= self.__headcount=0while count

cur=cur.next

count+= 1

#当循环退出后,pre指向pos-1位置

node =Node(item)

node.next=cur

node.prev=cur.prev

cur.prev.next=node

cur.prev=nodedefremove(self,item):"""删除节点"""

ifself.is_empty():returncur= self.__head

whilecur:if cur.elem ==item:#先判断此节点是否是头结点

if cur == self.__head:

self.__head =cur.nextifcur.next:#判断链表是否只有一个节点

cur.next.prev =Noneelse:

cur.prev.next=cur.nextifcur.next:#判断链表是否是尾节点

cur.next.prev =cur.prevbreak

else:

cur=cur.nextdefsearch(self,item):"""查询节点是否存在"""cur= self.__head

whilecur:if cur.elem ==item:returnTrue

cur=cur.nextreturnFalsedefindex(self,item):"""查询节点是否存在"""cur= self.__headcount=0whilecur:if cur.elem ==item:returncount

cur=cur.next

count+= 1

return '{} is not in linklist'.format(item)defvalue(self,index):"""查找指定位置的值"""

ifself.is_empty():returnNoneelif index>self.length()-1:return 'linklist index out of range'cur= self.__headcount=0while count

count+= 1cur=cur.nextreturncur.elemif __name__ == '__main__':

dll=DoubleLinkList()print(dll.is_empty())print(dll.length())#print(dll)

dll.append(1)print(dll.is_empty())print(dll.length())

dll.append(2)

dll.add(8)

dll.append(3)

dll.append(4)

dll.append(5)

dll.append(6)#print(dll)

dll.insert(-1, 9) #9,8,123456

dll.travel()

dll.insert(3, 100) #9,8,1,100,23456

dll.travel()

dll.insert(10, 200) #9,8,1,100,23456,200

dll.travel()

dll.remove(9)

dll.travel()

dll.remove(100)

dll.travel()

dll.remove(200)

dll.travel()print(dll.value(0))print(dll.index(8))print(dll.search(4))

5.双链表

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/8

@Author: Zhang Yafei"""

classNode(object):"""节点"""

def __init__(self,elem):

self.elem=elem

self.next=NoneclassSingleCycleLinkList(object):"""单向循环链表"""

def __init__(self,node=None):

self.__head =nodeifnode:

node.next=nodedef __str__(self):if not self.__head:return 'None'

else:

cur= self.__headlist_str= ''

whilecur:

cur_str= '{}->'.format(cur.elem) if cur.next elsestr(cur.elem)

list_str+=cur_str

cur=cur.nextreturnlist_strdefis_empty(self):"""链表是否为空"""

return self.__head isNonedeflength(self):"""链表长度"""

#cur游标,用来移动遍历节点

ifself.is_empty():return0

cur= self.__head

#count记录数量

count = 1

while cur.next != self.__head: #cur.next == None

cur =cur.next

count+= 1

returncountdeftravel(self):"""遍历整个链表"""

ifself.is_empty():returncur= self.__head

while cur.next != self.__head:print(cur.elem,end=" ")

cur=cur.next#退出循环,cur指向尾节点,但尾节点的元素未打印

print(cur.elem)defadd(self,item):"""链表头部添加元素,头插法"""node=Node(item)ifself.is_empty():

self.__head =node

node.next=nodeelse:

cur= self.__head

while cur.next != self.__head:

cur=cur.next

node.next= self.__headself.__head =node#cur.next = node

cur.next = self.__head

defappend(self,item):"""链表尾部添加元素,尾插法"""node=Node(item)if self.is_empty():#链表判空

self.__head =node

node.next=nodeelse:

cur= self.__head

while cur.next != self.__head:

cur=cur.next

node.next=cur.next

cur.next=nodedef insert(self,pos,item): #insert(2,100)

"""指定位置添加元素

:param pos 从0开始"""

if pos<=0:

self.add(item)elif pos>(self.length()-1):

self.append(item)else:

node=Node(item)

pre= self.__headcount=0while count < pos-1:

pre=pre.next

count+= 1

#当循环退出后,pre指向pos-1位置

node.next =pre.next

pre.next=nodedefremove(self,item):"""删除节点"""

ifself.is_empty():returncur= self.__headprev=Nonewhile cur.next != self.__head:if cur.elem==item:#先判断此节点是否是头结点

if cur == self.__head:#头结点的情况

#找尾节点

rear = self.__head

while rear.next != self.__head:

rear=rear.next

self.__head =cur.next

rear.next= self.__head

else:#中间节点

prev.next =cur.nextreturn

else:

prev=cur

cur=cur.next#退出循环,cur指向尾节点

if cur.elem ==item:if cur == self.__head:#链表中只有一个节点

self.__head =Noneelse:#prev.next = cur.next

prev.next = self.__head

defsearch(self,item):"""查询节点是否存在"""

ifself.is_empty():returnFalse

cur= self.__head

while cur.next != self.__head:if cur.elem ==item:returnTrue

cur=cur.next#退出循环,cur指向尾节点

if cur.elem ==item:returnTruereturnFalsedefindex(self,item):"""查询节点是否存在"""

ifself.is_empty():returnNone

cur= self.__headcount=0while cur.next != self.__head:if cur.elem ==item:returncount

cur=cur.next

count+= 1

if cur.elem ==item:returncountraise ValueError('{} is not in linkCyclelist'.format(item))defvalue(self,index):"""查找指定位置的值"""

ifself.is_empty():raise AttributeError('LinkCycleList is None')elif index>self.length()-1:raise IndexError('linklist index out of range')

cur= self.__headcount=0while count

count+= 1cur=cur.nextreturncur.elemif __name__ == '__main__':

ll=SingleCycleLinkList()print(ll.is_empty())print(ll.length())#print(ll)

ll.append(1)print(ll.is_empty())print(ll.length())

ll.append(2)

ll.add(8)

ll.append(3)

ll.append(4)

ll.append(5)

ll.append(6)#print(ll)

ll.insert(-1,9) #9,8,123456

ll.travel()

ll.insert(3,100) #9,8,1,100,23456

ll.travel()

ll.insert(10,200) #9,8,1,100,23456,200

ll.travel()

ll.remove(9)

ll.travel()

ll.remove(100)

ll.travel()

ll.remove(200)

ll.travel()print(ll.value(0))print(ll.index(8))#help(SingleCycleLinkList)

6.单向循环链表

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

-*- coding: utf-8 -*-

"""@Datetime: 2018/11/8

@Author: Zhang Yafei"""

classNode(object):"""结点"""

def __init__(self,item):

self.elem=item

self.prev=None

self.next=NoneclassDoubleCycleLinkList(object):"""双链表"""

def __init__(self,node=None):#默认为None第一次创建空链表

self.__head = Node('HEAD')

self.__head.next =node

self.__head.prev =nodeif node is notNone:

node.next= self.__headnode.prev= self.__head

def __str__(self):

self.travel()return

defis_empty(self):"""链表是否为空"""

return self.__head.next isNonedeflength(self):"""链表长度"""

#cur游标,用来移动遍历节点

ifself.is_empty():return0

cur= self.__head.next#count记录数量

count =0while cur != self.__head: #cur.next == None

cur =cur.next

count+= 1

returncountdeftravel(self):"""遍历整个链表"""cur= self.__head.nextwhile cur != self.__head:print(cur.elem,end=" ")

cur=cur.nextprint('')defadd(self,item):"""链表头部添加元素,头插法"""node=Node(item)ifself.is_empty():#空链表

node.next = self.__headnode.prev= self.__headself.__head.next =node

self.__head.prev =nodeelse:#非空链表

node.next = self.__head.next

self.__head.next =node

node.prev= self.__headnode.next.prev=nodedefappend(self,item):"""链表尾部添加元素,尾插法"""node=Node(item)if self.is_empty():#链表判空

node.next = self.__headnode.prev= self.__headself.__head.next =node

self.__head.prev =nodeelse:

cur= self.__head

while cur.next != self.__head:

cur=cur.next

node.next=cur.next

node.prev=cur

cur.next=node

self.__head.prev =nodedef insert(self,pos,item): #insert(2,100)

"""指定位置添加元素

:param pos 从0开始"""

if pos<=0:

self.add(item)elif pos>(self.length()-1):

self.append(item)else:

cur= self.__head.next

count=0while count

cur=cur.next

count+= 1

#当循环退出后,pre指向pos-1位置

node =Node(item)

node.next=cur

node.prev=cur.prev

cur.prev.next=node

cur.prev=nodedefremove(self,item):"""删除节点"""

ifself.is_empty():returncur= self.__head.nextwhilecur:if cur.elem ==item:#先判断此节点是否是头结点

if cur == self.__head.next:

self.__head.next =cur.nextif cur.next == self.__head:#判断链表是否只有一个节点

self.__head.next =None

self.__head.prev =Noneelse:

cur.next.prev= self.__head

else:

cur.prev.next=cur.nextif cur.next != self.__head:#判断链表是否是尾节点

cur.next.prev =cur.prevelse:

self.__head.prev =cur.prevbreak

else:

cur=cur.nextdefsearch(self,item):"""查询节点是否存在"""

ifself.is_empty():returnFalse

cur= self.__head.nextwhilecur:if cur.elem ==item:returnTrue

cur=cur.nextreturnFalsedefindex(self,item):"""查询指定元素的索引"""cur= self.__head.next

count=0whilecur:if cur.elem ==item:returncount

cur=cur.next

count+= 1

return '{} is not in linklist'.format(item)defvalue(self,index):"""查找指定位置的值"""

ifself.is_empty():returnNoneelif index>self.length()-1:return 'linklist index out of range'cur= self.__head.next

count=0while count

count+= 1cur=cur.nextreturncur.elemif __name__ == '__main__':

dcl=DoubleCycleLinkList()print(dcl.is_empty())print(dcl.length())#print(dcl)

dcl.append(1)print(dcl.is_empty())print(dcl.length())

dcl.append(2)

dcl.add(8)

dcl.append(3)

dcl.append(4)

dcl.append(5)

dcl.append(6)#print(dcl)

dcl.insert(-1, 9) #9,8,123456

dcl.travel()

dcl.insert(3, 100) #9,8,1,100,23456

dcl.travel()

dcl.insert(10, 200) #9,8,1,100,23456,200

dcl.travel()

dcl.remove(9)

dcl.travel()

dcl.remove(100)

dcl.travel()

dcl.remove(200)

dcl.travel()print(dcl.value(0))print(dcl.index(5))print(dcl.search(4))

7.双向循环链表

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

classStack(object):"""栈"""

def __init__(self):

self.__list = [] #私有变量,不允许外部调用者对其进行操作

defpush(self,item):"""添加一个新的元素item到栈顶"""self.__list.append(item) #顺序表尾部插入时间复杂度O(1),头部插入O(n),故尾部方便

#self.__list.insert(0,item) #链表表尾部插入时间复杂度O(n),头部插入O(1),故链表用头插方便

defpop(self):"""弹出栈顶元素"""

return self.__list.pop()defpeek(self):"""返回栈顶元素"""

if self.__list:return self.__list[-1]returnNonedefis_empty(self):"""判断栈是否为空"""

return self.__list ==[]#return not self.__list #0,{},[],(),'',None在python中都是False,

defsize(self):"""返回栈的元素个数"""

return self.__list.__len__()if __name__ == '__main__':

s=Stack()

s.push(1)

s.push(2)

s.push(3)

s.push(4)print(s.pop())print(s.pop())print(s.pop())

8.栈的实现

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

classQueue(object):"""队列"""

def __init__(qelf):

qelf.__list =[]defenqueue(qelf,item):"""往队列添加一个item元素"""qelf.__list.append(item) #O(1) 入队频繁时,用队尾插入,队头删除

#qelf.__list.insert(0,item) #O(n),出队频繁时,队头插入,队尾删除

defdequeue(qelf):"""往队列头部删除一个元素"""

return qelf.__list.pop(0) #O(n)

#return qelf.__list.pop() #O(1) 当出队比较频繁时,用pop比较方便

defiq_empty(self):"""判断队是否为空"""

return qelf.__list ==[]defqize(self):"""返回队列的大小"""

return len(qelf.__list)if __name__ == '__main__':

q=Queue()

q.enqueue(1)

q.enqueue(2)

q.enqueue(3)

q.enqueue(4)print(q.dequeue())print(q.dequeue())print(q.dequeue())print(q.dequeue())

9.队列的实现

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

classDqueue(object):"""双端队列"""

def __init__(self):

self.__list =[]def __str__(self):

queue= list(map(str,self.__list))if not self.__list:return 'None'

else:return ' '.join(queue)defadd_front(self,item):"""往队列头部插入元素"""self.__list.insert(0,item)defadd_rear(self,item):"""往队列尾部插入元素"""self.__list.append(item)defpop_front(self):"""队列头部删除元素"""self.__list.pop(0)defpop_rear(self):"""队列尾部删除元素"""self.__list.pop()defis_empty(self):"""判断队列是否为空"""

return not self.__list

defsize(self):"""返回队列的大小"""

return len(self.__list)if __name__ == '__main__':

dqueue=Dqueue()print(dqueue)

dqueue.add_front(1)print(dqueue)

dqueue.add_front(2)print(dqueue)

dqueue.add_front(3)print(dqueue)

dqueue.add_rear(4)print(dqueue)

dqueue.add_rear(5)print(dqueue)

dqueue.add_rear(6)print(dqueue)

dqueue.pop_front()print(dqueue)

dqueue.pop_rear()print(dqueue)

dqueue.pop_front()print(dqueue)

dqueue.pop_rear()print(dqueue)

dqueue.pop_front()print(dqueue)

dqueue.pop_rear()print(dqueue)

10.双端队列

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

defbubble_sort(alist):"""冒泡排序,每一次循环找出最大值"""n=len(alist)for i in range(n-1):

count=0for j in range(n-i-1):if alist[j] > alist[j+1]:

alist[j],alist[j+1] = alist[j+1],alist[j]

count+= 1

if notcount:return

defbubble_sort2(alist):"""冒泡排序,每一次循环找出最小值"""n=len(alist)for i in range(n-1,0,-1):for j inrange(i):if alist[j] > alist[j+1]:

alist[j],alist[j+1] = alist[j+1],alist[j]if __name__ == '__main__':

li= [54,26,93,17,77,31,44,55,20]print(li)

bubble_sort(li)#bubble_sort2(li)

print(li)

11.冒泡排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

importtimedefselect_sort1(alist):

start=time.clock()for i inrange(0,len(alist)):

min_v=min(alist[i:len(alist)])

j=alist.index(min_v)

alist[i],alist[j]=alist[j],alist[i]

use_time= time.clock()-startprint(use_time)defselect_sort(alist):

start=time.clock()

n=len(alist)for j in range(n-1): #j:0~n-2

min_index =jfor i in range(j+1,n):if alist[min_index] >alist[i]:

min_index=i

alist[j],alist[min_index]=alist[min_index],alist[j]

use_time= time.clock()-startprint(use_time)if __name__ == '__main__':

li= [54,226,93,17,77,31,44,55,20]print(li)

select_sort(li)#select_sort1(li)

print(li)

12.简单选择排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

from timeit importTimer#alist = [54, 226, 93, 17, 77, 31, 44, 55, 20]#alist1 = [54, 226, 93, 17, 77, 31, 44, 55, 20]

definsert_sort(alist):"""插入排序"""

#从第二个位置,即下标为1的元素开始向前插入

for i in range(1,len(alist)):for j in range(i,0,-1):#从第i个元素开始向前比较,如果小于前一个,则交换,否则终止循环

if alist[j]

alist[j-1],alist[j] = alist[j],alist[j-1]else:break

definsert_sort1(alist1):"""插入排序"""

#从右边的无序序列中

for j in range(1,len(alist1)):#i代表内层循环起始值

i =j#执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确的位置中

while i >0:if alist1[i]

alist1[i],alist1[i-1] = alist1[i-1],alist1[i]

i-= 1

else:break

if __name__ == '__main__':

li= [54, 226, 93, 17, 77, 31, 44, 55, 20]print(li)#insert_sort(li)

insert_sort1(li)print(li)#for_time = Timer('insert_sort()','from __main__ import insert_sort')

#while_time = Timer("insert_sort1()","from __main__ import insert_sort1")

#print('for_time',for_time.timeit(1000))

#print('while_time',while_time.timeit(1000))

13.插入排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/10

@Author: Zhang Yafei"""

defshell_sort(alist):"""希尔排序"""gap= len(alist) // 2

#gap变化到0之前,插入算法执行的次数

while gap >0 :#插入算法,与普通插入算法的区别就是gap步长

for i inrange(gap,len(alist)):#i=[gap,gap+1,gap+2,...]

j =iwhile j >0:if alist[j] < alist[j-gap]:

alist[j],alist[j-gap] = alist[j-gap],alist[j]

j-=gapelse:breakgap//= 2

if __name__ == '__main__':

li= [54, 226, 93, 17, 77, 31, 44, 55, 20]print(li)

shell_sort(li)print(li)

14.希尔排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/11

@Author: Zhang Yafei"""

defquick_sort(alist,first,last):"""快速排序"""

if first >=last:returnmid_value=alist[first]

low=first

high=last#游标从右往左一直走,知道遇到比当前mid_value小的元素,将该元素赋值给low所指的位置

while low

while low < high and alist[high] >=mid_value:

high-= 1alist[low]=alist[high]while low

low+= 1alist[high]=alist[low]#从循环退出,low=high

alist[low] =mid_value#对low左边的列表执行快速排序

quick_sort(alist,first,low-1)#对low右边的列表排序

quick_sort(alist,low+1,last)if __name__ == '__main__':

li= [54, 226, 93, 17, 77, 31, 44, 55, 20]print(li)

quick_sort(li,0,len(li)-1)print(li)

15.快速排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/11

@Author: Zhang Yafei"""

defmerge_sort(alist):"""归并排序"""n=len(alist)if n<=1:returnalist

mid= n//2left_li=merge_sort(alist[:mid])

right_li=merge_sort(alist[mid:])

left_pointer,right_pointer=0,0

result=[]while left_pointer < len(left_li) and right_pointer

result.append(left_li[left_pointer])

left_pointer+= 1

else:

result.append(right_li[right_pointer])

right_pointer+= 1result+=left_li[left_pointer:]

result+=right_li[right_pointer:]returnresultif __name__ == '__main__':

li= [54, 226, 93, 17, 77, 31, 44, 55, 20]print(li)

sorted_list=merge_sort(li)print(li)print(sorted_list)

16.归并排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/11

@Author: Zhang Yafei"""

defbinary_search(alist,item):"""二分查找"""n=len(alist)if n >0:

mid= n//2

if alist[mid] ==item:returnTrueelif item

first=0

last= n-1

while first <=last:

mid= (first + last) // 2

if alist[mid] ==item:returnTrueelif item

last= mid - 1

else:

first= mid + 1

returnFalseif __name__ == '__main__':

li= [17, 20, 31, 44, 54, 55, 77, 93, 226]print(binary_search(li,31))print(binary_search_2(li,31))

17.二分查找

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2018/11/11

@Author: Zhang Yafei"""

classNode(object):"""树节点"""

def __init__(self, item=None):

self.elem=item

self.lchild=None

self.rchild=NoneclassTree(object):"""二叉树"""

def __init__(self):

self.root=Nonedefadd(self, item):

node=Node(item)if self.root isNone:

self.root=Node(item)returnqueue=[self.root]whilequeue:

cur_node=queue.pop(0)if cur_node.lchild isNone:

cur_node.lchild=nodereturn

else:

queue.append(cur_node.lchild)if cur_node.rchild isNone:

cur_node.rchild=nodereturn

else:

queue.append(cur_node.rchild)defbreadth_travel(self):"""广度遍历"""

if notself.root:returnqueue=[self.root]whilequeue:

cur_node=queue.pop(0)print(cur_node.elem,end=' ')ifcur_node.lchild:

queue.append(cur_node.lchild)ifcur_node.rchild:

queue.append(cur_node.rchild)defpreorder(self, node):"""先序遍历"""

if notnode:return

print(node.elem, end=' ')

self.preorder(node.lchild)

self.preorder(node.rchild)definorder(self,node):"""中序遍历"""

if notnode:returnself.inorder(node.lchild)print(node.elem,end=' ')

self.inorder(node.rchild)defpostorder(self,node):"""后序遍历"""

if notnode:returnself.postorder(node.lchild)

self.postorder(node.rchild)print(node.elem,end=' ')if __name__ == '__main__':

tree=Tree()

tree.add(0)

tree.add(1)

tree.add(2)

tree.add(3)

tree.add(4)

tree.add(5)

tree.add(6)

tree.add(7)

tree.add(8)

tree.add(9)

tree.breadth_travel()print('')

tree.preorder(tree.root)print('')

tree.inorder(tree.root)print('')

tree.postorder(tree.root)print('')

18.二叉树的广度、深度优先及先、中、后序遍历

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei

桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。

每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是

鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间

桶排序以下列程序进行:

1. 设置一个定量的数组当作空桶子。

2. 寻访序列,并且把项目一个一个放到对应的桶子去。

3. 对每个不是空的桶子进行排序。

4. 从不是空的桶子里把项目再放回原来的序列中。"""

defbucket_sort2(array):#1.创建n个空桶

n =len(array)

new_list= [[] for _ inrange(n)]#2.把arr[i] 插入到bucket[n*array[i]]

for data inarray:

index= int(data *n)

new_list[index].append(data)#3.桶内排序

for i inrange(n):

new_list[i].sort()#4.产生新的排序后的列表

index =0for i inrange(n):for j inrange(len(new_list[i])):

array[index]=new_list[i][j]

index+= 1

returnarraydefbucket_sort(nums):#选择一个最大的数

max_num =max(nums)#创建一个元素全是0的列表, 当做桶

bucket = [0] * (max_num + 1)#把所有元素放入桶中, 即把对应元素个数加一

for i innums:

bucket[i]+= 1

#存储排序好的元素

sort_nums =[]#取出桶中的元素

for j inrange(len(bucket)):if bucket[j] !=0:for y inrange(bucket[j]):

sort_nums.append(j)returnsort_numsif __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]

data2= [0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434]

data3=data2.copy()

sort_data=bucket_sort(data)

sort_data2=bucket_sort2(data2)print(data)print(sort_data)print(data3)print(sort_data2)

19.桶排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei"""

defswap(data, root, last):

data[root], data[last]=data[last], data[root]defadjust_heap(data, par_node, high):"""调整父节点 与孩子大小, 制作大顶堆

:param data:

:param par_node:

:param high:

:return:"""new_par_node=par_node

j= 2 * par_node + 1 #取根节点的左孩子, 如果只有一个孩子 high就是左孩子,如果有两个孩子 high 就是右孩子

while j <= high: #如果 j = high 说明没有右孩子,high就是左孩子

if j < high and data[j] < data[j + 1]: #如果这儿不判断 j < high 可能超出索引

#一个根节点下,如果有两个孩子,将 j 指向值大的那个孩子

j += 1

if data[j] > data[new_par_node]: #如果子节点值大于父节点,就互相交换

data[new_par_node], data[j] =data[j], data[new_par_node]

new_par_node= j #将当前节点,作为父节点,查找他的子树

j = j * 2 + 1

else:#因为调整是从上到下,所以下面的所有子树肯定是排序好了的,

#如果调整的父节点依然比下面最大的子节点大,就直接打断循环,堆已经调整好了的

break

#索引计算: 0 -->1 --->....#父节点 i 左子节点:偶数:2i +1 右子节点:基数:2i +2 注意:当用长度表示最后一个叶子节点时 记得 -1

#从第一个非叶子节点(即最后一个父节点)开始,即 list_.length//2 -1(len(list_)//2 - 1)#开始循环到 root 索引为:0 的第一个根节点, 将所有的根-叶子 调整好,成为一个 大顶堆

defheap_sort(lst):"""根据列表长度,找到最后一个非叶子节点,开始循化到 root 根节点,制作 大顶堆

:param lst: 将列表传入

:return:"""length=len(lst)

last= length - 1 #最后一个元素的 索引

last_par_node = length // 2 - 1

while last_par_node >=0:

adjust_heap(lst, last_par_node, length- 1)

last_par_node-= 1 #每调整好一个节点,从后往前移动一个节点

while last >0:#swap(lst, 0, last)

lst[0], lst[last] =lst[last], lst[0]#调整堆少让 adjust 处理最后已经排好序的数,就不处理了

adjust_heap(lst, 0, last - 1)

last-= 1

return lst #将列表返回

if __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]print(data)

heap_sort(data)print(data)

20.堆排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei"""

defcycle_sort(array):"""圈排序(不稳定排序)

默认升序

计数排序是另开辟空间存放排序结果,圈排序是不开辟空间,直接进行组内交换"""ans= 0 #记录发生交换的次数,不用在意,无关紧要,可删

#外层循环处理列表中的每一个圈,一次遍历出现一个圈

for cycleStart in range(0, len(array) - 1):

item= array[cycleStart] #取出待排序的元素,item一直记录一圈的元素

#找到item应该放的位置,跟计数排序相似,统计列表中有多少个元素比item小

pos = cycleStart #记录位置

for i in range(cycleStart + 1, len(array)):if array[i]

pos+= 1

#item也存在圈但这个圈只有它自己,表示item已经归位,不用改变

if pos ==cycleStart:continue #跳过本次循环继续下次循环

#这四行代码是处理列表中相同的元素

while item == array[pos]: #如果相同,就直接放在pos的后一个位置

pos += 1array[pos], item= item, array[pos] #item最终归位,并把item赋新值

ans += 1

#处理新的item

while pos != cycleStart: #pos=cycleStart就代表又回到了起点,表示已有元素归到

#cycleStart位置上,一圈处理完毕

#以下代码跟上面思路一样

pos =cycleStartfor i in range(cycleStart + 1, len(array)):if array[i]

pos+= 1

while item ==array[pos]:

pos+= 1array[pos], item=item, array[pos]

ans+= 1

if __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]print(data)

cycle_sort(data)print(data)

21.圈排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei"""

defcomb_sort(the_list):

the_len=len(the_list)if the_len <2:#0和1

print("无需排序")returnthe_listelse:

i= int(the_len/1.3)while i >= 1:for j inrange(the_len):if i + j >=the_len:

i= int(i/1.3)break

else:if the_list[j] >= the_list[j+i]:

the_list[j], the_list[j+i] = the_list[j+i], the_list[j]if __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]print(data)

comb_sort(data)print(data)

22.梳排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei"""

importmathdef radix_sort(the_list, radix=10):"""基数排序

:param the_list:

:param radix:

:return:"""i=int(math.ceil(math.log(max(the_list), radix)))

bucket= [[] for i inrange(radix)]for i in range(1, i + 1): #i次循环

for val inthe_list:

bucket[int(val% (radix ** i) / (radix ** (i - 1)))].append(val) #析取整数第K位数字 (从低到高)

print(f'{i}: {bucket}')del the_list[:] #把列表清空但列表还在,效果同the_list=[]一样

for each inbucket:

the_list.extend(each)#桶合并

bucket = [[] for _ inrange(radix)]if __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]print('排序前:', data)

radix_sort(data,2)print('排序后:', data)

23.基数排序

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/4/10

@Author: Zhang Yafei"""

importrandomdefmonkey_sort_test(num_list):"""猴子排序,思想是:每次都随机打乱数组,直到有序为止"""

whileTrue:

i= 1

while i

if data[i-1]

i+= 1

else:break

if i ==len(data):breakrandom.shuffle(num_list)if __name__ == '__main__':

data= [54, 26, 93, 17, 77, 31, 44, 55, 20]print('排序前:', data)

monkey_sort_test(data)print('排序后:', data)

24.猴子排序

扩展

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/1/8

@Author: Zhang Yafei"""

importredisclassFifoQueue(object):def __init__(self):"""先进先出队列:利用redis中的列表,双端队列改为先进先出队列"""self.server= redis.Redis(host='127.0.0.1', port=6379)defpush(self, request):"""Push a request"""self.server.lpush('USERS', request)def pop(self, timeout=0):"""Pop a request"""data= self.server.rpop('USERS')returndataif __name__ == '__main__':

q=FifoQueue()

q.push(11)

q.push(22)

q.push(33)print(q.pop())print(q.pop())print(q.pop())

1.基于redis实现先进先出队列

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#-*- coding: utf-8 -*-

"""@Datetime: 2019/1/8

@Author: Zhang Yafei"""

importredisclassLifoQueue(object):"""Per-spider LIFO queue."""

def __init__(self):

self.server= redis.Redis(host='127.0.0.1', port=6379)defpush(self, request):"""Push a request"""self.server.lpush("USERS", request)def pop(self, timeout=0):"""Pop a request"""data= self.server.lpop('USERS')returndataif __name__ == '__main__':

q=LifoQueue()

q.push(11)

q.push(22)

q.push(33)print(q.pop())print(q.pop())print(q.pop())

2.基于redis实现后进先出栈

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

-*- coding: utf-8 -*-

"""@Datetime: 2019/1/8

@Author: Zhang Yafei"""

importredisclassPriorityQueue(object):"""Per-spider priority queue abstraction using redis' sorted set"""

def __init__(self):

self.server= redis.Redis(host='127.0.0.1', port=6379)defpush(self, request,score):"""Push a request"""

#data = self._encode_request(request)

#score = -request.priority

#We don't use zadd method as the order of arguments change depending on

#whether the class is Redis or StrictRedis, and the option of using

#kwargs only accepts strings, not bytes.

self.server.execute_command('ZADD', 'xxxxxx', score, request)def pop(self, timeout=0):"""Pop a request

timeout not support in this queue class"""

#use atomic range/remove using multi/exec

pipe =self.server.pipeline()

pipe.multi()

pipe.zrange('xxxxxx', 0, 0).zremrangebyrank('xxxxxx', 0, 0)

results, count=pipe.execute()ifresults:returnresults[0]if __name__ == '__main__':

q=PriorityQueue()#q.push('alex',99) # 广度优先:分值小的优先

#q.push('oldboy',56)

#q.push('eric',77)

q.push('alex',-99) #深度优先:分值大的优先

q.push('oldboy',-56)

q.push('eric',-77)

v1=q.pop()print(v1)

v2=q.pop()print(v2)

v3=q.pop()print(v3)

3.基于redis实现优先级队列

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值