在之前的讲座中,我讨论了Python中的排序。在今天的讲座中,我们将更深入地探讨这个话题。
在之前的课上,我展示了一些最简单排序算法的代码,选择排序。
以下是精选分类中主要思想的概要。
下面是该算法的实现。为方便起见,我将算法结构化为两个函数。函数sort()实现了完整的排序算法,而函数findSmallest()作为辅助函数来帮助sort()完成其工作。
def findSmallest(list,start,end): smallest = list [start] where esmallest = start for i in range(start+1,end):如果list [i] < smallest: smallest = list [i] where esmallest = i return where esmallest def sort(list): for i in range(0,len(list)): where = findSmallest(list,i,len(list)) temp = list [i] list [i] = list [where] list [where] = temp data = [12,23,51,14,25,67,33,46,60,89] sort(data) for x in data: print(x)
为了让我们在编写更复杂的循环时有更多的练习,这里是第二种排序算法,插入排序。
这是插入排序的主要思想大纲。
这是插入排序的代码。
defsort (list): for i in range(1,len(list)): j = i while j > 0 and list [j] < list [j]: temp = list [j] list [j] = list [j-1] list [j-1] = temp j- = 1 data = [12,23,51,14,25,67,33,46,60,89] sort(data) for x in data: print(x)
更强大和高效的排序算法使用一种称为递归的策略。这种策略处理排序这样的问题,将列表分解为多个部分,分别对每个部分进行排序,然后将这些部分组合在一起。
下面是归并排序的代码。
def合并(倾斜的,i, j, k):第一次=[船向一边倾斜的[n] n的范围(i, j + 1)]第二=[船向一边倾斜的[n] n的范围(j + 1, k)] n = 0 m = 0 p =我虽然n < len(第一个)和m < len(二):如果第一个[n] <第二[m]:船向一边倾斜的[p] =第一[n] n + = 1:船向一边倾斜的第二[m] [p] = m + = 1 p + = 1, n < len(第一):船向一边倾斜的[p] =第一[n] n + = 1 p + = 1 m < len(二):船向一边倾斜的第二[m] [p] = m + = 1 p + = 1 def(倾斜的,i, j):如果j >我:sort(list,i,mid) = (i + j)//2 sort(list,i,mid,j) sort(list,i,mid,j) data = [12, 23, 51, 14, 25, 67, 33, 46, 60, 89] sort(data,0,len(data)) for x in data: print(x)
快速排序算法也使用递归来完成它的工作。该算法从一个分区步骤开始,该步骤选择列表中的一个项目作为枢轴值,然后将列表重新组织为小于枢轴、枢轴和大于枢轴的项目。然后我们递归地对主节点两边的列表进行排序。
def分区(倾斜的,i, j): k = i - 1主=船向一边倾斜的(j - 1) n范围(i, j - 1):如果船向一边倾斜的[n] < =主:k + = 1 temp =船向一边倾斜的[k]倾斜的[k] =船向一边倾斜的[n]倾斜的[n] = temp倾斜的[j - 1] =船向一边倾斜的[k + 1]倾斜的(k + 1) =主返回k + 1 def(倾斜的,i, j):如果j >我:k =分区(倾斜的,i, j)排序(倾斜的,我,k)排序(倾斜的,k + 1, j)数据=[51 12日,23日,14日,25日,67年,33岁,46岁,60岁,89]类(数据、0 len(数据))的x数据:打印(x)
在互联网上有许多网站,您可以找到演示基本算法操作的动画,例如这四种排序算法。其中一个站点是www.hackerearth.com,它提供了许多排序算法的可视化,包括我在这里展示的四个排序算法。
我上面展示的四种排序算法可分为两大类:基本算法和递归算法。基本算法是基本的,因为它们依赖于易于理解和编码的思想。递归算法在某种程度上不那么明显,但最终具有比基本算法更好的性能。
为了说明算法之间的性能差异,我将设置一个演示。在这个演示中,我们将使用排序算法对相同的数字列表进行排序,并对每个算法进行排序。这将给我们关于算法的相对效率的即时反馈。
为了给各种相互竞争的排序算法提供一个可供排序的通用数字列表,我将从编写一个生成随机整数长列表的简单程序开始。程序将这些整数保存到一个文件中,以便排序程序从中读取。
Import random nums = [random.randint(1,100000) for _ in range(20000)] pickle。转储(num、开放(“nums.p”,“世界银行”))
保存数字的程序使用了Python pickle库,它提供了一种简单方便的方法来将二进制数据从Python程序转储到二进制文件中。
下面是从文件中读取数字并对它们进行两次排序的程序,一次使用插入排序,第二次使用快速排序。
import pickle import time def insert (list):使用插入排序将list按升序排序。”“我的范围(1,len(倾斜的)):j =我虽然> 0和倾斜的[j] <船向一边倾斜的[j - 1]: temp =船向一边倾斜的[j]倾斜的[j] =船向一边倾斜的(j - 1)船向一边倾斜的(j - 1) = temp j - = 1 def分区(倾斜的,i, j): k = i - 1主=船向一边倾斜的(j - 1) n范围(i, j - 1):如果船向一边倾斜的[n] < =主:k + = 1 temp =船向一边倾斜的[k]倾斜的[k] =船向一边倾斜的[n]倾斜的[n] = temp倾斜的[j - 1] =船向一边倾斜的[k + 1]倾斜的(k + 1) =主返回k + 1 def快速排序(倾斜的,i, j):如果j >我:k =分区(倾斜的,i, j)快速排序(倾斜的,我,k)快速排序(倾斜的,k + 1, j) num =泡菜。加载(open) ('nums。p', 'rb')) now = time.time() insert (nums) later = time.time() print(' insert sort took ',later - now,' seconds.') nums = pickle。加载(open) ('nums。p', 'rb')) now = time.time() quicksort(nums,0,len(nums)) later = time.time() print(' quicksort took ',later - now,' seconds.')
这个程序显示了两种算法的速度之间的巨大差异。对于包含20000个随机整数的列表,插入排序需要19.8秒来排序列表,而快速排序只需要0.04秒。随着列表长度的增加,这种差异变得更加明显。插入排序所需的时间与列表长度的平方成正比,因此列表长度翻倍会使排序时间增加4倍。另一方面,快速排序,花费的时间与n log n成正比排序一个有n个元素的列表。列表长度翻倍只会使排序时间增加2倍多一点。
在这个任务中,我们将把插入排序和快速排序算法结合起来,使快速排序更加高效。快速排序的一个不太理想的方面是,快速排序将要排序的列表细分为大小为1的列表。在此基础上的改进是使用混合策略。在混合策略中,我们修改了快速排序,这样当它遇到大小小于某个预设截止值的子列表时,它使用插入排序对子列表进行排序,而不是继续递归地将子列表细分为越来越小的列表。
实现这个版本的快速排序,并使其在遇到大小小于10的子列表时转换为使用插入排序。将这个修改版本的QuickSort与原始版本在一个大的数字列表上进行比较,并让您的程序证明修改版本更快。