刷题总结2:排序算法
Posted amberwang2018
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题总结2:排序算法相关的知识,希望对你有一定的参考价值。
一、选择排序
选择排序是每次从未排序的部分选出一个最小的数字,放在已排序部分的最后,即每次选出最小的、第二小的,以此类推。当然,也可以每次从未排序的地方选出最大的数字,放在已排序部分的最前面,即每次选出最大的、第二大的,以此类推。
时间复杂度O(n^2)。
优点是交换次数最少。
代码:
def select_sort(nums): n = len(nums) for i in range(n): min = i for j in range(i+1,n): if nums[j]<nums[min]: min = j nums[i],nums[min] = nums[min],nums[i] return nums nums = [3,4,8,2,1] print(select_sort(nums))
二、插入排序(熟悉)
插入排序是每次将一个数字(主元)【i序列】插入到一个有序的数组【j序列】里,成为一个长度更长的有序数组,有限次操作后,数组整体有序。
时间复杂度O(n^2)。
优点是在几乎有序的数组和短数组上表现很好,为此,在小区间执行排序任务时可以使用插入排序。
代码:
def insert_sort(nums): n = len(nums) for i in range(1,n): pivot = nums[i] j = i-1 while j>=0 and nums[j] > pivot: nums[j+1] = nums[j] j -= 1 nums[j+1] = pivot return nums nums = [3,4,8,2,1] print(insert_sort(nums))
三、归并排序(重点)
归并排序是借助额外空间,将两个有序数组合并,得到更长的有序数组。额外空间是用来存放合并后数组,然后将该数组再放回大数组里。
以下代码为《算法导论》里的代码,它开辟了两个额外空间存放数组。
def merge(A,l,m,r): n1 = m-l+1 n2 = r-m #创建临时数组 L = [0]*n1 R = [0]*n2 #拷贝到临时数组 for i in range(n1): L[i] = A[l+i] for j in range(n2): R[j] = A[m+1+j] #归并临时数组到A[l,r] i,j,k=0,0,l while i<n1 and j<n2: if L[i]<=R[j]: A[k] = L[i] i += 1 else: A[k] = R[j] j += 1 k += 1 #拷贝L、R剩余元素 while i<n1: A[k]=L[i] i += 1 k += 1 while j<n2: A[k]=R[j] j += 1 k += 1 def mergesort(A,l,r): if r>l: m = l+ (r-l)//2 mergesort(A,l,m) mergesort(A,m+1,r) merge(A,l,m,r) #测试实例 A=[5,2,4,7,1,3,2,6] mergesort(A,0,len(A)-1) print(A)
也可以每次不用开辟新临时数组,而只用一个。每次开辟新临时数组空间复杂度为nlogn。
def merge(A,l,m,r,temp): i,j = l,m+1 while i<=m and j<=r: if A[i]<=A[j]: temp.append(A[i]) i += 1 else: temp.append(A[j]) j+=1 while i<=m: temp.append(A[i]) i += 1 while j<=r: temp.append(A[j]) j += 1 for i in range(len(temp)): A[l+i] = temp[i] temp.clear() def mergesort(A,l,r,temp): if r>l: m = l+(r-l)//2 mergesort(A,l,m,temp) mergesort(A,m+1,r,temp) merge(A,l,m,r,temp) A=[5,2,4,7,1,3,2,6] mergesort(A,0,len(A)-1,[]) print(A)
四、快速排序(重点)
快速排序是每一次都排好一个元素,这个元素就待在了它最终该待的地方,然后递归地处理它左边和右边的部分,直至有序。思想也是分治的思想,但与归并排序不同,采用的是分割的方法,所以没有“合”的过程。
代码为随机化分割:
import random def partition(A,p,r): pivot = A[r] #主元 i = p-1 #初始化起始序号 for j in range(p,r): if A[j] <= pivot: i += 1 A[i],A[j] = A[j],A[i] A[r],A[i+1] = A[i+1],A[r] return i+1 def RandomizePartition(A,p,r): x = random.randint(p,r) A[x],A[r] = A[r],A[x] return partition(A,p,r) def quicksort(A,p,r): if p<r: q = RandomizePartition(A,p,r) quicksort(A,p,q) quicksort(A,q+1,r) return A A = [2,8,7,1,3,5,6,4] quicksort(A,0,len(A)-1) print(A)
每次随机化选择主元,这样可以避免出现有序或逆序的待排序数组时时间复杂度为O(n^2)的情况。
五、堆排序(重要)
堆排序是利用堆这种数据结构而设计的一种排序算法,它的时间复杂度为O(nlogn)。它的主要思想是:将待排序序列构造成一个最大堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样就会得到n个元素的次小值。以此类推,就能得到一个有序序列了。
代码如下:
#维护一个最大堆 def heapify(arr, n, i): largest = i l = 2 * i + 1 # left = 2*i + 1 r = 2 * i + 2 # right = 2*i + 2 if l < n and arr[i] < arr[l]: largest = l if r < n and arr[largest] < arr[r]: largest = r if largest != i: arr[i], arr[largest] = arr[largest], arr[i] # 交换 heapify(arr, n, largest) #堆排序 def heapSort(arr): n = len(arr) # Build a maxheap. for i in range(n, -1, -1): heapify(arr, n, i) # 一个个交换元素 for i in range(n - 1, 0, -1): arr[i], arr[0] = arr[0], arr[i] # 交换 heapify(arr, i, 0) arr = [12, 11, 13, 5, 6, 7] heapSort(arr) print(arr)
堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。
以上是关于刷题总结2:排序算法的主要内容,如果未能解决你的问题,请参考以下文章