1、算法概念
在计算机科学中,算法是一个解决特定问题或执行特定任务的有序步骤的有限序列。算法是对一系列输入数据进行处理,产生期望输出结果的一种有效方法。它是解决问题的一种清晰而精确的描述,可以被实现为计算机程序。
算法必须满足以下关键特性:
有限性(Finiteness): 算法的执行必须在有限的步骤内终止,不会永无止境地执行下去。
确定性(Determinism): 对于给定的输入,算法的每一步都有确切的定义,不会产生模糊或不确定的结果。
输入(Input): 算法接受零个或多个输入,这些输入是算法在执行过程中处理的原始数据。
输出(Output): 算法产生至少一个输出,这是由输入经过一系列步骤计算得到的结果。
效率(Effectiveness): 算法必须在有限时间内执行,而且在解决问题上是有效的,不会消耗过多的资源。
2、时间复杂度和空间复杂度
3、排序算法
3.1 冒泡排序
3.1.1 解释
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
冒泡排序的时间复杂度为O(n^2),其中n是数组的大小。尽管冒泡排序在时间复杂度上相对较高,但是它实现简单直观,对于小规模的数据集仍然是一种有效的排序方法。此外,冒泡排序还具有稳定性,即相等元素的相对顺序不会改变。
3.1.2 python代码
def bubble_sort(arr): n = len(arr) # 外层循环控制比较的轮数 for i in range(n): # 标记是否在本轮比较中发生交换 swapped = False # 内层循环执行相邻元素的比较和交换 for j in range(n - 1 - i): if arr[j] > arr[j + 1]: arr[j], arr[j + 1] = arr[j + 1], arr[j] print("ll",arr) swapped = True # 如果本轮比较中没有发生交换,则表示数组已经有序,跳出循环 if not swapped: break return arr # 测试 arr = [64, 34, 25, 12, 22, 11, 90] sorted_arr = bubble_sort(arr) print("排序后的数组:", sorted_arr)
3.1.3 结果
C:\Users\Thinkpad\AppData\Local\Programs\Python\Python39\python.exe C:/Users/Thinkpad/Desktop/python的数据结构/冒泡排序.py ll [34, 64, 25, 12, 22, 11, 90] ll [34, 25, 64, 12, 22, 11, 90] ll [34, 25, 12, 64, 22, 11, 90] ll [34, 25, 12, 22, 64, 11, 90] ll [34, 25, 12, 22, 11, 64, 90] ll [25, 34, 12, 22, 11, 64, 90] ll [25, 12, 34, 22, 11, 64, 90] ll [25, 12, 22, 34, 11, 64, 90] ll [25, 12, 22, 11, 34, 64, 90] ll [12, 25, 22, 11, 34, 64, 90] ll [12, 22, 25, 11, 34, 64, 90] ll [12, 22, 11, 25, 34, 64, 90] ll [12, 11, 22, 25, 34, 64, 90] ll [11, 12, 22, 25, 34, 64, 90] 排序后的数组: [11, 12, 22, 25, 34, 64, 90] Process finished with exit code 0
3.1.4 参考文献Python 冒泡排序 | 菜鸟教程 (runoob.com)
以上对数据排序在菜鸟都有
4、数据结构
4.1 定义
在Python中,常见的数据结构定义包括以下几种:
- 列表(List):列表是Python中最常用的数据结构之一,用于存储一组有序的元素。列表使用方括号
[]
来定义,其中的元素可以是任意数据类型,并且可以动态增加、删除或修改。my_list = [1, 2, 3, 'apple', 'banana']
- 元组(Tuple):元组与列表类似,不同之处在于元组使用圆括号
()
来定义,一旦创建就不能被修改(即元组是不可变的)。my_tuple = (1, 2, 3, 'apple', 'banana')
- 字典(Dictionary):字典是无序的键值对集合,用大括号
{}
来定义,可以通过键来访问对应的值。字典的键必须是唯一的,但值可以重复。my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}
- 集合(Set):集合是一种无序的、不重复的数据集合,用大括号
{}
来定义,可以进行集合运算(如并集、交集、差集等)。my_set = {1, 2, 3, 4, 5}
- 字符串(String):字符串是由字符组成的有序序列,可以用单引号
''
、双引号""
或三引号''' '''
来定义。my_string = "Hello, Python!"
这些是Python中常见的数据结构定义方式,代表的是我们的数据应该怎么定义组织
4.2 二叉树
4.2.1 二叉树基本概念
二叉树(Binary Tree):二叉树是一种树形数据结构,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树的节点通常由一个存储元素值的数据域、一个指向左子节点的指针和一个指向右子节点的指针组成。如果某个节点没有子节点,则相应的指针可以为空。
根节点(Root Node):树中的顶层节点称为根节点。在二叉树中,根节点是整个树的起始节点,它没有父节点。
父节点(Parent Node):每个节点除了根节点外,都有一个父节点,父节点是指向当前节点的直接上级节点。
子节点(Child Node):每个节点可能有零个、一个或两个子节点。子节点是当前节点的直接下级节点。
叶子节点(Leaf Node):没有子节点的节点称为叶子节点,也叫终端节点。
内部节点(Internal Node):除了叶子节点外的其他节点都称为内部节点。内部节点既有父节点也有子节点。
深度(Depth):节点的深度是指从根节点到该节点的唯一路径的长度。根节点的深度为0,依次往下递增。
高度(Height):节点的高度是指从该节点到一个叶子节点的最长路径的长度。叶子节点的高度为0,依次往上递增。
子树(Subtree):在二叉树中,每个节点都可以作为子树的根节点,该节点下的所有子节点和它们的子节点组成了一个子树。
左子树和右子树(Left Subtree and Right Subtree):每个节点都有一个左子节点和一个右子节点,它们分别称为左子树和右子树。
4.3 二叉树代码
class Node(object):
"""树节点"""
def __init__(self, item):
self.item = item
self.left_child = None
self.right_child = None
class BinaryTree(object):
"""二叉树"""
def __init__(self):
self.root = None
def is_empty(self):
"""判断二叉树是否为空"""
return self.root is None
def add(self, item):
"""添加树节点"""
node = Node(item)
if self.root is None:
self.root = node
return
temp = [self.root]
# print(temp)
while temp:
current_node = temp.pop(0) #移除列表最后一个元素
if current_node.left_child:
temp.append(current_node.left_child)
else:
current_node.left_child = node
return
if current_node.right_child:
temp.append(current_node.right_child)
else:
current_node.right_child = node
return
'''
广度优先遍历(层次遍历)
从树的root开始,从上到下从从左到右遍历整个树的节点
'''
def breadth_traversal(self):
"""广度遍历"""
if self.root is None:
return
temp = [self.root]
while temp:
current_node = temp.pop(0)
print(current_node.item, end=' ')
if current_node.left_child:
temp.append(current_node.left_child)
if current_node.right_child:
temp.append(current_node.right_child)
print()
'''
深度优先遍历
对于一颗二叉树,深度优先搜索(Depth First Search)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
那么深度遍历有重要的三种方法。这三种方式常被用于访问树的节点,它们之间的不同在于访问每个节点的次序不同。这三种遍历分别叫做
先序遍历(preorder),中序遍历(inorder)和后序遍历(postorder)。我们来给出它们的详细定义,然后举例看看它们的应用。
先序遍历
在先序遍历中,我们先访问根节点,然后递归使用先序遍历访问左子树,再递归使用先序遍历访问右子树
先序遍历 在先序遍历中,我们先访问根节点,然后递归使用先序遍历访问左子树,再递归使用先序遍历访问右子树
顺序如右:根节点->左子树->右子树
'''
def preorder_traversal(self, node):
"""先序遍历"""
if node is None:
return
print(node.item, end=' ')
self.preorder_traversal(node.left_child)
self.preorder_traversal(node.right_child)
"""
中序遍历 在中序遍历中,我们递归使用中序遍历访问左子树,然后访问根节点,最后再递归使用中序遍历访问右子树
顺序如右:左子树->根节点->右子树
"""
def inorder_traversal(self, node):
"""中序遍历"""
if node is None:
return
self.inorder_traversal(node.left_child)
print(node.item, end=' ')
self.inorder_traversal(node.right_child)
"""
后序遍历 在后序遍历中,我们先递归使用后序遍历访问左子树和右子树,最后访问根节点
顺序如右:左子树->右子树->根节点
代码实现:
"""
def postorder_traversal(self, node):
"""后序遍历"""
if node is None:
return
self.postorder_traversal(node.left_child)
self.postorder_traversal(node.right_child)
print(node.item, end=' ')
if __name__ == '__main__':
tree = BinaryTree()
print(tree.is_empty())
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)
print(tree.is_empty())
print("广度遍历")
tree.breadth_traversal()
print("先序遍历")
tree.preorder_traversal(tree.root)
print("\n中序遍历")
tree.inorder_traversal(tree.root)
print("\n后序遍历")
tree.postorder_traversal(tree.root)
4.3.1 运行结果
C:\Users\Thinkpad\AppData\Local\Programs\Python\Python39\python.exe C:/Users/Thinkpad/Desktop/python的数据结构/二叉树.py
True
False
广度遍历
0 1 2 3 4 5 6 7 8 9
先序遍历
0 1 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 2 0
Process finished with exit code 0