一、稳定排序与不稳定排序
相等的元素排序之后相对位置不变就是稳定排序,反之就是不稳定排序。
二、主要排序算法
1、冒泡排序
思想:遍历列表里的每个元素,每趟遍历的元素都与后面的元素进行比较,
如果大于下一个元素就交换位置,如果小于下一个元素就不交换,最终都找到最大的放在列表最后,遍历的趟数就是列表长度减1。
# 最小比较次数 C = n - 1
# 最小交换移动次数 M = 0
# 时间复杂度为 O(n)
# 最大比较次数 C = n*(n-1)/2
# 最大交换移动次数 M = 3n*(n-1)/2
# 时间复杂度为 O(n**2)
# 总的平均时间复杂度为O(n**2)
代码:
def bubble_sort(l):
for i in range(len(l)-1):
for j in range(0, len(l)-i-1):
if l[j] > l[j+1]:
l[j], l[j+1] = l[j+1], l[j]
print(l)
import random
l = random.sample(range(1, 100), 20)
print(l)
bubble_sort(l)
2、直接插入排序
思想: # 把列表看成是有序列表和无序列表的组合,刚开始有序列表是第一个元素,然后从第二个元素开始遍历列表,即遍历无序列表,让无序列表中的每一个元素都跟有序列表的元素进行比较
# 所以第一个for循环就是遍历无序列表,第二个for循环就是倒序遍历有序列表,然无序列表的元素与有序列表的元素进行比较,如果小于有序列表的元素就交换位置,反之就退出有序列表
的比较循环,进行下一个无序列表元素与有序列表的的比较循环
代码:
1 import random 2 3 l = random.sample(range(1, 101), 20) 4 print(l) 5 6 for i in range(0, len(l)-1): 7 for j in range(i+1, 0, -1): 8 if l[j] < l[j-1]: 9 l[j], l[j-1] = l[j-1], l[j] 10 else: 11 break 12 print(l)
3、希尔排序
思想:按照一定的步长把列表分组,然后每组列表再按照插入排序算法排序,步长就是列表的长度整除2,直到步长小于1结束分组。
代码:
1 import random 2 3 l = random.sample(range(1, 101), 20) 4 print(l) 5 d = len(l)//2 # 步长 6 while d >= 1: 7 for i in range(d): # 分了d组新列表 8 # 每个新列表使用直接插入法排序 9 for j in range(i, ((len(l)//d)-1)*d, d): # 遍历新列表(无序列表),最后一个元素不用遍历 10 for k in range(j+d, i, -d): # 遍历有序列表,依次比较 11 if l[k] < l[k-d]: # 从小到大排序 12 l[k], l[k-d] = l[k-d], l[k] 13 else: 14 break 15 d = d // 2 16 print(l)
4、选择排序
思想:# 把整个列表看成是有序列表和无序列表的组合,刚开始有序列表为空,每次从无序列表中选出最小的值放在有序列表末尾,有序列元素增加一个无序就减少一个
# 具体的交换就是遍历列表len(l)-1趟,没趟都选出最小的值然后与无序列表的第一个元素交换
代码:
1 import random 2 l = random.sample(range(1, 100), 20) 3 print(l) 4 5 for i in range(len(l)-1): 6 min = i 7 for j in range(i+1, len(l)): 8 if l[j] < l[min]: 9 min = j 10 l[i], l[min] = l[min], l[i] 11 print(l)
5、基数排序
思想:
# 外边的while循环就是遍历最大元素的位数,先从各位开始比较,然后遍历数组,把对应位数的值放在对应值编号的桶里,即由字典包含的列表,
# 字典的键就是从0到9,列表就相当于桶用来放位数值与键相同的元素,元素遍历结束后就把字典所有的值都相加成一个大列表,
# 然后再重复循环,整个循环顺序:个--->十--->百---->.....,直到位数最高的元素的位数循环完了就结束
代码:
1 import random 2 3 arr = random.sample(range(1, 2000), 10) 4 print(arr) 5 6 d = 0 7 while True: 8 tag = 0 9 bucket = {0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], 8:[], 9:[]} 10 for i in arr: 11 k = i // 10 ** d 12 tag += k 13 bucket[k % 10].append(i) 14 if tag == 0: 15 print(arr) 16 break 17 arr = [] 18 for v in bucket.values(): 19 arr += v 20 d += 1 21 22 # 外边的while循环就是遍历最大元素的位数,先从各位开始比较,然后遍历数组,把对应位数的值放在对应值编号的桶里,即由字典包含的列表, 23 # 字典的键就是从0到9,列表就相当于桶用来放位数值与键相同的元素,元素遍历结束后就把字典所有的值都相加成一个大列表, 24 # 然后再重复循环,整个循环顺序:个--->十--->百---->.....,直到位数最高的元素的位数循环完了就结束
6、快速排序
思想:
# 每一趟都选出一个基准值,一般选取第一个为基准值,然后相当于把基准值的位置挖个坑,用两个指针分别从最开始与最末尾移动
# 先从最右开始,高位指针指到的值与基准值比较,如果大指针就往下走,如果比基准值小,就与坑的位置交换,高位指针此时就指到坑的位置
# 然后低位指针从最左边开始,低位指针指到的值与基准值比较,如果比基准值小就,就继续往下一个走,如果比基准值大就与坑的位置交换,低位指针就指到坑的位置
# 重复上述步骤,如果低位指针与高位指针位置重合,就终止此次趟比较,返回低位指针的位置,并把基准值赋值给低位指针
# 然后按照低位指针的位置分割为两个新列表,低位指针位置的值不在两个列表之内
# 每个列表重复上述步骤进行排序,此处使用的是递归实现
# 最终终止条件是低位指针大于等于高位指针
代码:
1 import random 2 3 arr = random.sample(range(1, 101), 10) 4 print(arr) 5 6 7 def yitang(low, high): 8 basevalue = arr[low] 9 while low < high: 10 while arr[high] >= basevalue and low < high: 11 high -= 1 12 arr[low] = arr[high] 13 while arr[low] <= basevalue and low < high: 14 low += 1 15 arr[high] = arr[low] 16 arr[low] = basevalue 17 return low 18 19 20 def fast_sort(low, high): 21 if low < high: 22 mid = yitang(low, high) 23 fast_sort(low, mid-1) 24 fast_sort(mid+1, high) 25 26 27 fast_sort(0, len(arr)-1) 28 print(arr) 29 30 # 每一趟都选出一个基准值,一般选取第一个为基准值,然后相当于把基准值的位置挖个坑,用两个指针分别从最开始与最末尾移动 31 # 先从最右开始,高位指针指到的值与基准值比较,如果大指针就往下走,如果比基准值小,就与坑的位置交换,高位指针此时就指到坑的位置 32 # 然后低位指针从最左边开始,低位指针指到的值与基准值比较,如果比基准值小就,就继续往下一个走,如果比基准值大就与坑的位置交换,低位指针就指到坑的位置 33 # 重复上述步骤,如果低位指针与高位指针位置重合,就终止此次趟比较,返回低位指针的位置,并把基准值赋值给低位指针 34 # 然后按照低位指针的位置分割为两个新列表,低位指针位置的值不在两个列表之内 35 # 每个列表重复上述步骤进行排序,此处使用的是递归实现 36 # 最终终止条件是低位指针大于等于高位指针
7、归并排序
代码:
1 import random 2 3 arr = random.sample(range(1, 101), 20) 4 print(arr) 5 6 7 def mergeSort(arr): 8 if len(arr) <= 1: 9 return arr 10 num = int(len(arr) // 2) 11 left = mergeSort(arr[:num]) 12 right = mergeSort(arr[num:]) 13 return merge(left, right) 14 15 16 def merge(left, right): 17 l, r = 0, 0 18 result = [] 19 while l < len(left) and r < len(right): 20 if left[l] < right[r]: 21 result.append(left[l]) 22 l += 1 23 else: 24 result.append(right[r]) 25 r += 1 26 result += left[l:] 27 result += right[r:] 28 return result 29 30 31 print(mergeSort(arr)) 32 print(arr)
8、堆排序
代码:
1 import random 2 3 4 def big_endian(arr, start, end): 5 root = start 6 while True: 7 child = root * 2 + 1 8 if child > end: 9 break 10 if child + 1 <= end and arr[child] < arr[child + 1]: 11 child += 1 12 if arr[root] < arr[child]: 13 arr[root], arr[child] = arr[child], arr[root] 14 root = child 15 else: 16 break 17 18 19 def head_sort(arr): 20 first = len(arr) // 2 - 1 21 for start in range(first, -1, -1): 22 big_endian(arr, start, len(arr)-1) 23 for end in range(len(arr) - 1, 0, -1): 24 arr[0], arr[end] = arr[end], arr[0] 25 big_endian(arr, 0, end - 1) 26 return arr 27 28 29 def main(): 30 arr = random.sample(range(1, 200), 10) 31 print(arr) 32 print(head_sort(arr)) 33 34 35 if __name__ == '__main__': 36 main()