查找和排序是最基本的算法,在很多脚本中都会用到查找和排序。尽管 Python 提供的用于查找和排序的函数能够满足绝大多数需求,但还是有必要了解最基本的查找和排序算法,以便在有特殊需求的情况下,可以自己编写查找、排序脚本。
一、查找
基本的查找方法有顺序查找、二分查找和分块查找等。其中,顺序查找是最简单的查找方法,就是按照数据排列的顺序依次查找,直到找到所查找的数据为止(可查看数据表都未找到数据)。
二分查找是首先对要进行查找的数据进行排序,有按大小顺序排好的 9 个数字,如图-1所示。如果要进行查找数字 5,则首先与中间值 10 进行比较,5 小于 10,于是对序列的前半部分 1~9 进行查找。此时,中间值为 5,恰好为要找的数字,查找结束。
分块查找,是介于顺序查找和二分查找之间的一种查找方法。使用分块查找时,首先对查找表建立一个索引表,然后再进行分块查找。建立索引表时,首先对查找表进行分块,要求 "分块有序",即块内关键字不一定有序,但分块之间有大小顺序。索引表是抽取各块中的最大关键字及其起始位置构成的,如图-2 所示。
分块查找分两步进行,首先查找索引表,因为索引表是有序的,查找索引表时可以使用二分查找法进行。查找完索引表以后,就确定了要查找的数据所在的分块,然后在该分块中再进行顺序查找。
下面所示的 pyBinarySearch.py 脚本是对一个有序列表使用二分查找。
# -*- coding:UTF-8 -*-
# file: pyBinarySearch.py
def BinarySearch(l, key): # 二分查找
low = 0
high = len(l) - 1
i = 0
while low <= high:
i = i + 1
mid = (high + low) // 2
if l[mid] < key:
low = mid + 1
elif l[mid] > key:
high = mid - 1
else:
print('use %d time(s)' % i)
return mid
return -1
if __name__ == '__main__':
l = [1, 5, 6, 9, 10, 51, 62, 65, 70] # 构造列表
print(BinarySearch(l, 5)) # 在列表中查找
print(BinarySearch(l, 10))
print(BinarySearch(l, 65))
print(BinarySearch(l, 70))
运行脚本输出结果如下:
二、排序
对于查找来说,排序要复杂得多,排序的方法也较多,常用的排序方法有冒泡法排序、希尔排序、二叉树排序和快速排序等,其中,二叉树排序是比较有意思的一种排序方法,而且也便于操作。二叉树排序的过程主要是二叉树的建立和遍历的过程。例如,有一组数据 "3,5,7,20,43,2,15,30",则二叉树的建立过程如下。
- Step1:首先将第一个数据 3 放入根节点。
- Step2:将数据 5 与根节点中的数据 3 比较,由于 5 大于 3,因此应将 5 放入 3 的右子树中。
- Step3:将数据 7 与根节点中的数据 3 比较,由于 7 大于 3,因此应将 5 放入 3 的右子树中,由于 3 已经有右儿子 5,所以将 7 与 5 进行比较,因为 7 大于 5,所以应将 7 放入 5 的右子树中。
- Step4:将数据 20 与根节点中的数据 3 比较,由于 20 大于 3,因此应将 20 放入 3 的右子树中,重复比较,最终将 20 放入 7 的右子树中。
- Step5:将数据 43 与树中的节点值进行比较,最终将其放入 20 的右子树中。
- Step6:将数据 2 与根节点 3 进行比较,由于 2 小于 3,因此应将 2 放入 3 的左子树。
- Step7:同样的对数据 15 和 30 进行处理,最终形成如图-3 所示的树。
当树创建好后,对数进行中序遍历,得到的遍历结果就是对数据从小到大排序。如果要从大到小进行排序则可以先从右子树开始进行中序遍历。
下面所示的 pySort.py 脚本是采用二叉树排序的方式对数据进行排序。
# -*- coding:UTF-8 -*-
# file: pySort.py
class BTree: # 二叉树节点
def __init__(self, value): # 初始化函数
self.left = None # 左儿子
self.data = value # 节点值
self.right = None # 右儿子
def insertLeft(self, value): # 向左子树插入节点
self.left = BTree(value)
return self.left
def insertRight(self, value): # 向右子树插入节点
self.right = BTree(value)
return self.right
def show(self): # 输出节点数据
print(self.data)
def inorder(node): # 中序遍历
if node.data:
if node.left:
inorder(node.left)
node.show()
if node.right:
inorder(node.right)
def rinorder(node): # 中序遍历
if node.data:
if node.right:
rinorder(node.right)
node.show()
if node.left:
rinorder(node.left)
def insert(node, value): # 中序遍历,先遍历右子树
if value > node.data:
if node.right:
insert(node.right, value)
else:
node.insertRight(value)
else:
if node.left:
insert(node.left, value)
else:
node.insertLeft(value)
if __name__ == '__main__':
l = [3, 5, 7, 20, 43, 2, 15, 30]
Root = BTree(l[0]) # 根节点
node = Root
for i in range(1,len(l)):
insert(Root, l[i])
print('**************************')
print(' 从小到大')
print('**************************')
inorder(Root)
print('**************************')
print(' 从大到小')
print('**************************')
rinorder(Root)
运行 pySort.py 脚本后,输出如下所示的排序结果: