1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| ''' 简单排序统一接下来的格式 def X_Sort( ElementType A[], int N ) 默认从小到大的整数排序。
只讨论基于 比较 的排序。 只讨论内部排序。假定内存空间无限大,一次性在内存中解决。
稳定性:任意两个相等的数据,排序前后的相对位置不发生改变。
没有一种排序是任何情况下都表现最好的。
'''
''' 冒泡排序算法: 步骤一: 让一个指针从上到下,依次比较两个相邻的泡泡。 如果大小不对,就交换两个泡泡的位置。 补充说明: 第一个循环(也就是第一趟冒泡)完毕时(指针从头走到 N-1位置), 此时最大的值已经找到,但是前面的N-1个位置的排序不确定。 步骤二: 在前面 N-1 个数组中 ,重复步骤一,找出第二大的数。 ... 不断重复,直到前面没定顺序的数组中只剩2个数,(足够完成最后一次交换)。 # 其实这个比较的区间就是原数组去头去尾的。 (其实我们在最小堆那节已经用过类似的思想了。) '''
def Bubble_Sort(A): for p in range(len(A)-1,0,-1): flag = 0 for i in range(p): if A[i] > A[i+1]: Swap(A,i) flag = 1 if flag == 0: return '冒泡排序第一遍冒泡就发现顺序已经没问题了。' def Swap(A,i): temp = A[i] A[i] = A[i+1] A[i+1] = temp
''' 插入排序算法: 类似于打牌里的 "插牌"。 假定手里本来就有一张牌,是数组的第一张牌, 从数组抓第二张牌, 和手中第一张牌比大小,决定是否交换位置, 从手里抓第三张牌,和前一张牌比大小,看看是否交换位置,...再看看和第一张牌是否要交换。 ... 直到抓完N-1张牌。 '''
def Insert_Sort(A):
for p in range(1, len(A)): temp = A[p] preIndex = p-1 current = p while A[preIndex] > temp and preIndex >= 0 : A[current] = A[preIndex] current = preIndex preIndex = current - 1 A[current] = temp
if __name__ == '__main__': a = [1,5,6,2,4,3,8,9,7] Bubble_Sort(a) print(a) b = [1,2,3,4,5,6,7,8,9] print('\n',Bubble_Sort(b)) print(b,'\n') c = [3,1,9,8,28,36,44,35,0,100] Insert_Sort(c) print(c) ''' 时间复杂度下界讲解/ "逆序对"inversion:下标i < j,但是 A[i] > A[j],则(i,j)是一对逆序对。 {34,8,64,51,32,21} 中有多少逆序对呢? I = 9 个。 无论是冒泡还是插入排序,交换次数都是9次,消去了9个逆序对。 插入排序 T(N,I) = O(N+I) 。 如果序列基本有序,则插入排序简单且高效。
定理: N个不同元素组成的序列,平均有 N(N-1)/4个 逆序对。 定理: 任何仅以交换相邻两个元素来排序的算法,其平均时间复杂度为 Ω(N**2)。 Ω 是时间复杂度下界。 # 最好的情况下T 和平均时间复杂度下界不是一个意思。 根据以上分析,要提高算法效率,需要一次交换消除尽可能多的逆序对。 所以我们在接下来的尝试中,跳着交换相隔较远的2个元素。
'''
|