快速排序由C. A. R. Hoare在1960年提出,是对冒泡排序算法的一种改进,它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
(1)算法思路:
① 从数列中挑出一个元素,称为 “基准”;
② 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
③ 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
defpartition(numList, left, right): standard = numList[left] while left<right : while left<right and standard<=numList[right] : right -= 1 if left<right and standard>numList[right] : numList[left] = numList[right] left += 1 while left<right and standard>=numList[left] : left += 1 if left<right and standard<numList[left] : numList[right] = numList[left] right -= 1 numList[left] = standard return left
① 设array一个需要排序的数组,最初时的未排序序列unsortedArray为整个数组array。
② 首先从前向后扫描整个未排序序列,在未排序序列中找到最小元素,与该序列的首元素进行交换。每次遍历后,未排序序列中的最小元素将被移动到已排序序列末尾,并且已确定位置的数据不需要再参与排序,这样一来就缩小了未排序序列unsortedArray。
③ 重复步骤②,直到所有元素均排序完毕。
(2)算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
from random import randint
defselectSort(numList): # 简单选择排序 for i inrange(len(numList)-1): index = i # 指向待排序序列中最小元素的下标 for j inrange(i+1, len(numList)): if numList[index]>numList[j]: index = j numList[index], numList[i] = numList[i], numList[index] return numList
if __name__=="__main__": numList = [randint(0, 100) for i inrange(10)] print("简单选择排序前:", numList) numList = selectSort(numList) print("简单选择排序后:", numList)
① 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
② 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
③ 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
① 从第一个元素开始,该元素可以认为已经被排序;
② 取出下一个元素,在已经排序的元素序列中从后向前扫描;
③ 如果该已排序元素大于新元素,将该元素移到下一位置;
④ 重复步骤③,直到找到已排序的元素小于或者等于新元素的位置;
⑤ 将新元素插入到该位置后;
⑥ 重复步骤②~⑤,直到排序完成。
(2)算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from random import randint
definsertSort(numList): # 直接插入排序 for no inrange(1, len(numList)): index = no - 1# 指向当前插入点 num = numList[no] # 当前待插入的元素 while index>=0and numList[index]>num : numList[index+1] = numList[index] index -= 1 numList[index+1] = num return numList
if __name__=="__main__": numList = [randint(0, 100) for i inrange(10)] print("直接插入排序前:", numList) numList = insertSort(numList) # 直接插入排序 print("直接插入排序后:", numList)
① 设现有一个数组a需要排序,从第一个元素开始,该元素可以认为已经被排序;
② 将待插入区域的首元素下标为 left,末元素下标记为 right,mid = (left+right)/2;取出下一个元素next,比较 next 和 a[mid] 的大小;
③ 如果 next 大于 a[mid],选择 a[mid+1] 到 a[right] 为新的插入区域(即令 left = mid+1 );否则选择a[left]到a[m-1]为新的插入区域(即令 right = mid-1 );
④ 重复步骤③,直至 left > right 为止,接着将 right 位置之后所有元素向后移一位,并将新元素next插入 a[high+1];
⑤ 重复步骤②③④,直到排序完成。
definsertSort(numList): # 折半插入排序 for no inrange(len(numList)): num = numList[no] # 当前待插入的元素 # left、right代表已排序的序列的首、尾元素下标 left, right = 0, no-1 # 找到插入点的下标 while left<=right: mid = (left + right) // 2 if numList[mid]>num : right = mid - 1 else: left = mid + 1 # 插入数据 index = no - 1 while index>=left: numList[index+1] = numList[index] index -= 1 numList[index+1] = num return numList
if __name__=="__main__": numList = [randint(0, 100) for i inrange(10)] print("折半插入排序前:", numList) numList = insertSort(numList) # 折半插入排序 print("折半插入排序后:", numList)
① 设现有一个待排序数组,将数组均分成左部子数组left和右部子数组right。如果子数组内部数据是无序的,则对子数组递归进行二分,直至分解出的小组只有一个元素,此时认为该小组内部有序。
② 合并两个有序子数组,比较两个子数组的最前面的数,谁小就先取谁,该数组的指针往后移一位。
③ 重复步骤②,直至一个数组为空,然后把另一个数组的剩余部分复制过来即可。
④ 重复步骤②③,直至所有子数组归并成一个数组。
defMerge(left, right): # 归并序列 result = [] i, j = 0, 0 while i<len(left) and j<len(right) : if left[i]<right[j] : result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 if i<len(left): result.extend(left[i : ]) if j<len(right): result.extend(right[j : ]) return result
defmergeSort(numList): # 二路归并排序 iflen(numList)<=1: return numList size = (len(numList)) // 2 left = mergeSort(numList[:size]) right = mergeSort(numList[size:]) result = Merge(left, right) return result
if __name__=="__main__": numList = [randint(0, 100) for i inrange(10)] print("二路归并排序前:", numList) numList = mergeSort(numList) # 二路归并排序 print("二路归并排序后:", numList)
计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的时间复杂度(Ο(n+k),其中k是待排序整数的范围)是低于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当O(k) > O(n*log(n))的时候其效率反而不如基于比较的排序。
(1)算法思路:
① 找出待排序的数组中最大和最小的元素;
② 统计数组中介于最值之间的每个值的元素出现的次数;
③ 依据统计的出现次数将数值反向填充目标数组。
definsertionSort(array): # 直接插入排序 for no inrange(1, len(array)): cur = no - 1# 指向当前插入点 num = array[no] # 当前待插入的元素 while cur >= 0and array[cur] > num: array[cur+1] = array[cur] cur -= 1 array[cur+1] = num return array
defbucketSort(numList): # (1) 设置桶的数量(默认为5): iflen(numList) == 0: returnNone bucketNum = 5iflen(numList) > 5elselen(numList) bucketList = [[] for i inrange(bucketNum)] # (2) 找出数组numList中的最值,设置好桶内间隔: maxium, minium = max(numList), min(numList) gap = (maxium - minium)//bucketNum + 1# 桶内数字的间隔 # (3) 将数字装入桶中: for num in numList: index = (num - minium)//gap # 获取num所属桶的编号 bucketList[index].append(num) # (4) 为每个桶里面的数字进行排序: cur = 0 for bucket in bucketList: bucket = insertionSort(bucket) # 插入排序 for num in bucket: numList[cur] = num cur += 1 return numList
if __name__ == "__main__": numList = [randint(-100, 100) for i inrange(10)] print("桶排序前:", numList) numList = bucketSort(numList) # 桶排序 print("桶排序后:", numList)