数据结构之旅——搜索、排序和复杂度分析(Python实现)(四)
上一节讲了三个时间复杂度均为O(n2 )的排序算法,这一节我们讲几个时间复杂度降低了很多的更为快捷的排序算法。
一、堆排序
算法策略:先建立一个最大堆,在建立最大堆的过程中需要不断调整元素的位置。最大堆建立后,顶端元素必定是最大的元素,把该最大元素与最末尾元素位置置换,最大元素就出现在列表末端。重复此过程,直到排序。
代码实现:
import copy def heapSort(lyst): def heap_adjust(parent): child = 2 * parent + 1 # left child while child < len(heap): if child + 1 < len(heap): if heap[child + 1] > heap[child]: child += 1 # right child if heap[parent] >= heap[child]: break heap[parent], heap[child] = heap[child], heap[parent] parent, child = child, 2 * child + 1 heap, lyst = copy.copy(lyst), [] for i in range(len(heap) // 2, -1, -1): heap_adjust(i) while len(heap) != 0: heap[0], heap[-1] = heap[-1], heap[0] lyst.insert(0, heap.pop()) heap_adjust(0) return lyst
时间复杂度:O(nlog₂n)
缺点:比下面两种快速的排序方法慢,但比上一节的几种排序方法快。
二、归并排序
算法策略:归并排序是一种典型的分治思想,把一个无序列表一分为二,对每个子序列再一分为二,继续下去,直到无法再进行划分为止。然后,就开始合并的过程,对每个子序列和另外一个子序列的元素进行比较,依次把小元素放入结果序列中进行合并,最终完成归并排序。
代码实现:
def merge(lyst, low, mid, high): tmp = [] i = low j = mid +1 while i <= mid and j <= high: if lyst[i] <= lyst[j]: tmp.append(lyst[i]) i += 1 else: tmp.append(lyst[j]) j += 1 while i <= mid: tmp.append(lyst[i]) i += 1 while j <= high: tmp.append(lyst[j]) j += 1 lyst[low:high+1] = tmp def mergeSort(lyst, low, high): if low < high: mid = (low + high) // 2 mergeSort(lyst, low, mid) mergeSort(lyst, mid+1, high) merge(lyst, low, mid, high)
时间复杂度:O(nlogn)
缺点:需要额外的内存开销
三、快速排序
算法策略:首先在列表中取一项,这一项又叫做基准点,然后将列表中的项分区,比基准点小的都放在基准点左边,比基准点大的都放基准点右边,对于由于基准点分割而成的两个子列表重复之前的步骤,每次遇到少于 2个项的一个子列表,就结束分割过程。
代码实现:
def quickSort(lyst): if lyst == []: return [] else: point = lyst[0] p_min = quickSort([l for l in lyst[1:] if l < point]) p_max = quickSort([m for m in lyst[1:] if m >= point]) return p_min + [point] + p_max
时间复杂度:O(nlogn) 最坏时间复杂度为 O(n2)
缺点:极端情况下排序效率低
这三个排序方法在一般情况下的速度快慢为:快排>归并排>堆排