比较排序

一.问题描述

输入:n个数的一个序列<a1,a2,...,an>

输出:输入序列的一个从小到大的排序<a1',a2',...,an'>

 

二.比较排序

1.在排序的最终结果中,各元素的次序依赖于它们之间的比较

2.快速排序,归并排序,插入排序,堆排序都是比较排序,

3.堆排序和归并排序都是渐近最优的比较排序算法(运行时间上界为O(nlgn))

4.比较排序可以被抽象为一棵决策树,它是一棵完全二叉树,它可以表示在给定输入规模的情况下,某一特定排序算法对所有元素的比较操作

4.最坏情况

 

三.插入排序

1.简述:对于数组A[1...n]进行排序,对于第j个数,假设前j-1个数已排序好,看成常量,把第j个数依次与第j-1,j-2...0个数进行比较,如果遇到比他小的,插入到对应位置,比他大的数全部依次向后位移一位。按照循环,依次将原序列第1...n个数进行插入排序

 1 A=[5,2,4,6,1,3]
 2 def Insertion_Sort(A):
 3     #把第j个元素插入到【0,j-1】中,从第0个元素开始
 4     for j in range(1,len(A)):
 5         key=A[j]
 6         i=j-1
 7         #i从(j-1)到 0,i向前进1,直到要插入元素比前面的元素大
 8         # 从第j-1个元素和要插入的元素比较到,从第0个元素和要插入的元素比较
 9         while i>=0 and A[i]>key:
10             A[i+1]=A[i]
11             i=i-1
12             A[i+1]=key
13     return A
14 
15 print(Insertion_Sort(A))
16 ------------------------------------
17 [1, 2, 3, 4, 5, 6]
插入排序

2.分析:

(1)最坏情况运行时间:输入逆序序列进行排序,

T(n)= 

 

四.归并排序

步骤:

1.如果n=1,则已排序好

2.递归地对A【1...n/2】和A【n/2...n】进行排序(n/2向上取整)

3.把排好序的两个表进行归并

归并步骤需要T(n)=θ(n)(也被称为线性时间)

 故总的时间:

即:

用递归树求解

所以最坏时间规模:T(n)=θ(n lgn)(在充分大规模下(30)比n2大)

 1 #分治法-并归排序
 2 
 3 def merge(A,p,q,r):
 4     #排序A中【p,q】,和【q+1,r】
 5     n1=q-p+1
 6     n2=r-q
 7     L=[]
 8     R=[]
 9     for i in range(n1):
10         L.append(A[p+i])
11     for j in range(n2):
12         R.append(A[q+1+j])
13     L.append(float('inf'))
14     R.append(float('inf'))
15     i=0
16     j=0
17     for k in range(p,r+1):
18         if L[i]<=R[j]:
19             A[k]=L[i]
20             i=i+1
21         else:
22             A[k]=R[j]
23             j=j+1
24 
25 import math
26 def merge_sort(A,p,r):
27     #排序A【p,r】
28     if p < r:
29         q = math.floor((p+r)/2)#取整
30         merge_sort(A,p,q)
31         merge_sort(A,q+1,r)
32         merge(A,p,q,r)
33 
34 A=[5,2,4,7,1,3,2,6]
35 
36 merge_sort(A,0,len(A)-1)
37 
38 print(A)
39 ------------------------------------------------
40 [1, 2, 2, 3, 4, 5, 6, 7]
归并排序

 

五.快速排序

1.分治法:

(1)分:选取关键字把原数组分成两部分,而且一部分的值全大于另一部分的值

(2)治:递归处理两部分的排序

(3)合并:直接连接

2.特点:采用分治策略,原地排序,节省空间,改进性强,运行时间是线性时间

3.假设没有重复元素,

(1)最差情况:输入时顺序或逆序排好的(此时一部分没有元素,一部分是全部元素),

(2)最好情况:分的两部分的规模都不大于n/2

(3)平均情况和最好情况的时间复杂度是一样的

 1 #对A[p,r]进行快速排序
 2 def quicksort(A, p, r):
 3     if p < r:
 4         q = partition(A, p, r)#计算分块下标q
 5         quicksort(A, p, q - 1)#对前面进行快速排序
 6         quicksort(A, q + 1, r)#对后面进行快速排序
 7 
 8 #计算分块下标,
 9 def partition(A, p, r):
10     x = A[r]#主元
11     i = p - 1
12     for j in range(p, r):
13         #把每个元素和主元比较,
14         #如果比主元大或等于,不做操作
15         if A[j] < x:#如果比较的元素比主元小,
16             i += 1#把记录的最后一个比主元小的元素的坐标+1
17             A[i],A[j]=A[j],A[i]# 把当前的元素A【j】和A【i】交换
18     #通过A[r]改变A【i+1】
19     A[r] = A[i + 1]
20     A[i + 1] = x
21     return i + 1
22 
23 A=[2,8,7,1,3,5,6,4]
24 print(partition(A, 0, 7))
25 print(A)
26 quicksort(A,0,7)
27 print(A)
28 ----------------------------
29 3
30 [2, 1, 3, 4, 7, 5, 6, 8]
31 [1, 2, 3, 4, 5, 6, 7, 8]
快速排序

 4.随机化快速排序:随机选取主元

(1)运行时间不依赖于输入序列的顺序,

(2)无需对输入序列的分布做任何假设,

(3)没有一种特定的输入会引起最差的运行效率

(4)最差的情况由随机数产生器决定

 1 #计算分块下标,
 2 def partition(A, p, r):
 3     x = A[r]#主元
 4     i = p - 1
 5     for j in range(p, r):
 6         #把每个元素和主元比较,
 7         #如果比主元大或等于,不做操作
 8         if A[j] < x:#如果比较的元素比主元小,
 9             i += 1#把记录的最后一个比主元小的元素的坐标+1
10             A[i],A[j]=A[j],A[i]# 把当前的元素A【j】和A【i】交换
11     #通过A[r]改变A【i+1】
12     A[r] = A[i + 1]
13     A[i + 1] = x
14     return i + 1
15 
16 import random
17 
18 def randomized_quicksort(A, p, r):
19     if p < r:
20         q = randomized_partition(A, p, r)
21         randomized_quicksort(A, p, q - 1)
22         randomized_quicksort(A, q + 1, r)
23 
24 def randomized_partition(A, p, r):
25     i = random.randint(p, r)
26     A[i],A[r-1]=A[r-1],A[i]
27     return partition(A,p,r)
28 
29 A=[2,8,7,1,3,5,6,4]
30 print(randomized_partition(A, 0, 7))
31 print(A)
32 randomized_quicksort(A,0,7)
33 print(A)
34 -----------------------------------------
35 3
36 [2, 3, 1, 4, 8, 5, 7, 6]
37 [1, 2, 3, 4, 5, 6, 7, 8]
随机主元快速排序

 

六.

 

posted on 2018-07-25 20:23  温润有方  阅读(346)  评论(0编辑  收藏  举报