算法是一个循序渐进的过程,它定义了一组指令,以一定的顺序执行以获得所需的输出。算法通常独立于底层语言,即算法可以以多种编程语言实现。
从数据结构的角度看,以下是一些重要的算法类型:
* 搜索 搜索数据结构中的项目的算法
* 排序 按特定顺序对项目进行排序的算法
* 插入 算法将项目插入数据结构中
*更新 跟新数据结构中现有的项目算法
*删除 从数据结构中删除现有的项目的算法
算法的特点
并非所有的程序都可以称为算法,算法因该具有以下特征:
- 毫不含糊 算法应该是清晰明确。每个步骤(或阶段)及其输入/输出都应该清楚,并且必须仅导致一个含义
- 输入 算法应该有0个或更多明确定义的输入
- 输出 算法应该有一个或多个定义良好的输出,并且应该与所需的输出相匹配
- 有限性 算法必须在有限数量的步骤后终止
- 可行性 可用资源应该可行
- 独立 一个算法应该有一步一步的指示,它应该独立于任何编程代码
如何编写算法
编写算法没有明确的标准,相反,它依赖于问题和资源,从不编写算法来支持特定的编程代码
所有编程语言都共享项循环(do,for ,while),流控(if else)等基本代码构造。这些常用构造可用与编写算法
算法编程是一个过程,并在问题域定义之后执行。也就是说,应该知道问题领域,为此来设计一个解决方案
python算法的分析
算法的效率可以在执行之前和执行之后的两个不同阶段进行分析。
- 先验分析 这是一种算法的理论分析,通过假定所有其他因素(例如处理器速度)是单恒定的并且对实现没有影响来测量算法的效率
- 后验分析 这是堆算法的经验分析,所选择的算法是使用编程语言来实现。然后在目标计算机上执行。在此分析中,收集实际的统计数据,如运行时间和所需空间。
算法的复杂性
假设 X 是算法,n 是输入数据的大小,算法X 使用的时间和空间是决死那个 X 的效率的两个因素
时间因素 时间通过计算关键操作的数量来衡量,如排序算法中的比较
空间 因素 空间通过计算算法所需的最大存储空间来测量
算法 f(n) 的复杂性以算法 n 所需的运行时间和/或存储空间为输入数据的大小
空间复杂性
算法的空间复杂度表示该算法在其生命周期中所需的存储空间亮,算法所需的空间等于以下两个组件的总和
- 固定部分 是存储某些数据和变量所需的空间,与问题的大小无关。例如,使用的简单变量和常亮,程序大小等
- 变量部分 是变量所需的空间,其大小取决于问题的大小。例如,动态内存分配,递归堆栈空间等。
任何算法P 的空间复杂度S(p) 是 S(p) = C +SP(I) ,其中C是固定部分,S(I)是算法的变量部分,取决于实例特征I,请看下面的例子
时间复杂度(没彻底理解)
算法的时间复杂度表示算法运行完毕所需的时间量。时间要求可以定义为一个数值函数T(n),其中T(n)可以测量为步数,如果每部消耗的时间不变
例如,添加两个n
位整数需要n
个步骤。 因此,总计算时间是T(n)= c * n
,其中c
是加两位所用的时间。 在这里,观察到T(n)
随着输入尺寸的增加而线性增长。
python递归
递归允许函数自调用。修复代码的步骤会一次又一次的执行新值。还必须设置判断递归调用何时结束的标准
在下面的例子中,演示如何使用二进制搜索的递归方法。采用一个排序列表,并将其索引范围作为递归函数的输入
'''
使用python实现二进制搜索算法,如下所示。我们使用有序的项目表,并设计一个递归函数,
将起始索引和结束索引作为输入列表。然后二进制搜索数目自行调用,直到搜索到项目或在列表中结束
'''
def bsearch(list,idx0,idxn,val):
if (idxn<idx0):
return None
else:
#计算中间值的表达式
midval = idx0 +((idxn-idx0)//2)
#建立在以排序的基础上(计算的时候是以索引为标准的)
if list[midval] > val:
return bsearch(list,idx0,midval-1,val)
elif list[midval] < val:
return bsearch(list,midval+1,idxn,val)
else:
return midval
list = [8,11,24,56,88,131]
print(bsearch(list,0,5,24))
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
2
Process finished with exit code 0
python回溯(下面的代码理解了,但是我觉的他真正的内涵一定是没理解)
回溯是递归的一种形式,单它涉及选择任何可能性的唯一选择。我们从选择一个选项开始,并从中退出。如果达到一个状态,会得出这样的结论:这个特定的选项不能提供所需的解决方案。通过遍历每个可用选项来重复这些步骤,直到获得所需的解决方案
以下是查找给定字母集合的所有可能排列顺序的示例。当选择一对时,我们应该用回溯来验证是否已经创建了该确切的一对。如果尚未创建,则将该对添加到答案列表中,否则将被忽略。
def permute(list,s):
if list == 1:
return s
else:
return [
y+x
for y in permute(1,s)
for x in permute(list-1,s)
]
print(permute(1,['a','b','c']))
print(permute(2,['a','b','c']))
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
['a', 'b', 'c']
['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']
Process finished with exit code 0
python树遍历算法
遍历是访问树的所有节点的过程,也可以打印它们的值。 因为所有节点都通过边(链接)连接,所以始终从根(头)节点开始。 也就是说,我们不能随机访问树中的一个节点。 这里介绍三种方式来遍历一棵树 -
- 顺序遍历
- 前序遍历
- 后序遍历
按顺序遍历
在这种遍历方法中,首先访问左侧子树,然后访问根,然后访问右侧子树。 我们应该永远记住每个节点本身可能代表一个子树。
在下面的python程序中,使用Node
类为根节点以及左右节点创建占位符。 然后创建一个insert()
函数来将数据添加到树中。 最后,Inorder
遍历逻辑通过创建一个空列表,并首先添加添加根节点或父节点,然后左节点来实现。 最后添加左节点以完成Inorder
遍历。 请注意,对于每个子树重复此过程,直到遍历所有节点。
class Node:
def __init__(self,data):
self.left = None
self.data = data
self.right = None
def insert(self,data):
if self.data:
if data < self.data:
if self.left is None:
self.left=Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
# Print the Tree
def PrintTree(self):
if self.left:
self.left.PrintTree()
print(self.data)
if self.right:
self.right.PrintTree()
#Inorder traversal
#left -> Root -> Right
def inorderTraversal(self,root):
res=[]
if root:
res = self.inorderTraversal(root.left)
res.append(root.data)
res = res + self.inorderTraversal(root.right)
return res
root = Node(27)
root.insert(14)
root.insert(10)
root.insert(19)
root.insert(42)
print(root.inorderTraversal(root))
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
[10, 14, 19, 27, 42]
Process finished with exit code 0
前序遍历
在这种遍历方法中,首先访问更节点,然后访问左节点,最后访问右边的子树
在下面的python程序中,使用Node类为根节点以及左右节点创建占位符,然后创建一个insert()函数来将数据添加到树种,最后,前序遍历逻辑中国创建一个空列表并首先添加根节点,,然后添加左节点来实现。最后添加右节点以完成前序遍历。请注意,对每个子树重复此过程,直到遍历多有节点
class Node:
def __init__(self,data):
self.left = None
self.right = None
self.data = data
#Inser Node
def insert(self,data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
if data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
#Print the Tree
def PrintTree(self):
if self.left:
self.left.PrintTree()
print(self.data),
if self.right:
self.right.PrintTree()
#Preorder traversal
#root -> left -> right
def PreorderTraversal(self,root):
res = []
if root:
res.append(root.data)
res = res + self.PreorderTraversal(root.left)
res = res + self.PreorderTraversal(root.right)
return res
root = Node(27)
root.insert(14)
root.insert(35)
root.insert(10)
root.insert(19)
root.insert(31)
root.insert(42)
print(root.PreorderTraversal(root))
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
[27, 14, 10, 19, 35, 31, 42]
Process finished with exit code 0
后序遍历
这个遍历方法中,最后访问根节点。首先遍历左子树,然后遍历右子树,最后遍历根节点
在下面的python程序中,使用Node类作为根节点以及左右节点创建占位符,然后创建一个insert()函数来将数据添加到树中。最后,通过创建一个空列表并添加左节点,然后添加右节点来实现后续遍历逻。最后,添加根或父节点已完成后续遍历。请注意,对于每个子树重复此过程,直到遍历所有节点。
class Node:
def __init__(self,data):
self.left = None
self.data = data
self.right = None
def insert(self,data):
if self.data:
if data <self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
if data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
def PrintTree(self):
if self.left:
self.left.PrintTree()
print(self.data)
if self.right:
self.right.PrintTree()
#postorder traversal
#Left -> right -> root
def PostorderTraversal(self,root):
res = []
if root:
res = self.PostorderTraversal(root.left)
res = res +self.PostorderTraversal(root.right)
res.append(root.data)
return res
root = Node(27)
root.insert(14)
root.insert(35)
root.insert(10)
root.insert(19)
root.insert(31)
root.insert(42)
print(root.PostorderTraversal(root))
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
[10, 19, 14, 31, 42, 35, 27]
Process finished with exit code 0
python排序算法
排序是指以特定格式排列数据。排序算法指定按特定顺序排列数据的方式。最常见的排序是数字或字典顺序
排序的重要性在于,如果数据是以分类方式存储,数据收集可以优化到非常高的水平。排序也用于以更易读的格式表示数据。下面来看看python中实现排序的5中排序方式。
- 冒泡排序
- 合并排序
- 插入排序
- 希尔排序
- 选择排序
冒泡排序
他是一种基于比较的算法,其中每队相邻元素进行比较,如果元素不合适,元素将进行交换
def bubblesort(list):
for iter_num in range(len(list)-1,0,-1):#这是一种将每次最大的放在最后
for idx in range(iter_num):
if list[idx]>list[idx+1]:
list[idx],list[idx+1] = list[idx+1],list[idx]
list = [19,2,31,45,6,11,121,27]
#[2,19,31,45,6,11,121,27]
bubblesort(list)
print(list)
方式二
def bubble_sort(lists):
count=len(lists)
for i in range(0,count):
for j in range(i+1,count):
if lists[i]>lists[j]:
lists[i],lists[j]=lists[j],lists[i]
print(lists)
return lists
if __name__=="__main__":
lists=[3,2,1,5,4,3]
print(u'冒泡排序')
bubble_sorted=bubble_sort(lists)
print(bubble_sorted)
合并排序(没有彻底理解)
合并排序首先将数组分成相等的一半,然后以排序的方式组合他们
def merge_sort(unsorted_list):
if len(unsorted_list)<=1:
return unsorted_list
middle = len(unsorted_list)//2
left_list = unsorted_list[:middle] #[11,12,22]
right_list = unsorted_list[middle:] #[25,34,64,90]
left_list = merge_sort(left_list) #[11] [12,22]
right_list = merge_sort(right_list)#[25,34] [64,90]
return list(merge(left_list,right_list))
def merge(left_half,right_half):
res = []
while len(left_half) != 0 and len(right_half) != 0:
if left_half[0] < right_half[0]:
res.append(left_half[0])
left_half.remove(left_half[0])
else:
res.append(right_half[0])
right_half.remove(right_half[0])
if len(left_half) == 0:
res = res + right_half
else:
res = res + left_half
return res
unsorted_list = [64,34,25,12,22,11,90,87,88,89,91,92,98]
print(merge_sort(unsorted_list))
#运行结果:
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
[11, 12, 22, 25, 34, 64, 87, 88, 89, 90, 91, 92, 98]
Process finished with exit code 0
参考:https://blog.csdn.net/su_bao/article/details/81053871
插入排序
还有以下算法,稍后跟新
python搜索算法
将数据存储在不同的数据结构中时,搜索是非常基本的必需条件。 最简单的方法是遍历数据结构中的每个元素,并将其与要搜索的值进行匹配。 这就是所谓的线性搜索。 它效率低下,很少使用。下面创建一个程序演示如何实现一些高级搜索算法。
线性搜索
在这种类型的搜索中,逐个搜索所有项目。 每个项目都会被检查匹配,如果找到匹配项,那么返回该特定项目,否则搜索将继续到数据结构的末尾。
def linear_search(values,search_for):
search_at = 0 #完全遍历时的起始位置
search_res = False #是否找到的标志
while search_at <len(values) and search_res is False:
if values[search_at] == search_for:
search_res = True
else:
search_at = search_at + 1 #不相等则继续加1遍历
return search_res
l=[64,34,25,12,22,11,90]
print(linear_search(l,12))
print(linear_search(l,91))
插值搜索(没有彻底理解)
该搜索算法适用于所需值的探测位置。 为了使该算法正常工作,数据收集应该以排序形式并平均分布。 最初,探针位置是集合中最大项目的位置。如果匹配发生,则返回项目的索引。 如果中间项目大于项目,则再次在中间项目右侧的子数组中计算探针位置。 否则,该项目将在中间项目左侧的子数组中搜索。 这个过程在子数组上继续,直到子数组的大小减小零。
有一个特定的公式来计算下面的程序中指出的中间位置。参考以下代码的实现
def intpolsearch(values,x):
idx0 = 0
idxn = (len(values) -1)
while idx0 <= idxn and x>=values[idx0] and x <= values[idxn]:
#find the mid point
mid =idx0 + int(((float(idxn-idx0)/(values[idxn]-values[idx0]))*(x-values[idx0])))
#compare the value at mid point with search value
if values[mid] == x:
return "found "+str(x)+"at index "+str(mid)
if values[mid] < x:
idx0 = mid+1
return "search element not in the list"
l = [2, 6, 11, 19, 27, 31, 45, 121]
print(intpolsearch(l, 2))
#运行结果
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
found 2at index 0
Process finished with exit code 0
python图遍历算法
图在解决许多重要的数学难题中是非常有用的数据结构。 例如计算机网络拓扑或分析化学化合物的分子结构。 它们还用于城市交通或路线规划,甚至用于人类语言和语法。 所有这些应用程序都有遍历图的共同挑战,并确保图的所有节点都被访问。 有两种常见的已建立的方法来进行这种遍历,下面将对其进行描述。
深度优先遍历:
也称为深度优先搜索(DFS),该算法使用堆栈记住在任何迭代中发生死角时开始搜索的下一个顶点。 使用设置的数据类型在python中实现DFS图,因为它们提供了跟踪访问和未访问节点所需的功能。
'''
理解的关键在于看懂字典表示的图,为什么是一种深度优先
'''
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
self.gdict = gdict
#check for the visited and uncisited nodes
def dfs(graph,start,visited = None):
if visited is None:
visited = set()
visited.add(start)
print(start)
#核心代码
for next in graph[start] - visited:
dfs(graph,next,visited)
return visited
gdict = { "a" : set(["b","c"]),
"b" : set(["a", "d"]),
"c" : set(["a", "d"]),
"d" : set(["e"]),
"e" : set(["a"])
}
dfs(gdict, 'a')
#运行结果
F:\7-9练习代码\fuxi\venv\Scripts\python.exe F:/7-9练习代码/fuxi/shujujiegou.py
a
b
d
e
c
Process finished with exit code 0
广度优先遍历
也称为广度优先搜索(BFS),该算法使用队列记住当任何迭代中发生死角时,获取下一个顶点以开始搜索。
我们使用之前讨论的队列数据结构在python中实现BFS。 当继续访问相邻的未访问节点并继续将其添加到队列中。然后,开始只出现没有未访问节点的节点。 当没有下一个相邻节点被访问时,停止程序。
参考以下代码的实现 -
import collections
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
self.gdict = gdict
def bfs(graph, startnode):
# Track the visited and unvisited nodes using queue
seen, queue = set([startnode]), collections.deque([startnode])
while queue:
vertex = queue.popleft()
marked(vertex)
for node in graph[vertex]:
if node not in seen:
seen.add(node)
queue.append(node)
def marked(n):
print(n)
# The graph dictionary
gdict = { "a" : set(["b","c"]),
"b" : set(["a", "d"]),
"c" : set(["a", "d"]),
"d" : set(["e"]),
"e" : set(["a"])
}
bfs(gdict, "a")