目录
- 冒泡排序 Bubble Sort
- 选择排序 Selection Sort
- 插入排序 Insert Sort
- 希尔排序 Shell Sort
- 归并排序 Merge Sort
- 快速排序 Quick Sort
- 堆排序 Heap Sort
- 计数排序 Count Sort
- 桶排序 Bucket Sort
- 基数排序 Radix Sort
- 相关资料
冒泡排序
基本实现
依次比较相邻两个元素的大小
def bubbleSort(l):
n = len(l)-1
for i in range(n):
for j in range(0, n-i):
if l[j] > l[j+1]:
l[j], l[j+1] = l[j+1], l[j]
return l
优化
原始的冒泡排序算法有一个问题,比如原始的数列是[2, 1, 3, 4, 5, 6],即使在遍历一次之后就已经排序完成,程序仍会继续执行,所以我们加入一个flag参数来判断是否是已经排序完成。
def bubbleSort(l):
n = len(l)-1
for i in range(n):
flag = False
for j in range(0, n-i):
if l[j] > l[j+1]:
l[j], l[j+1] = l[j+1], l[j]
flag = True
if not flag:
return l
return l
选择排序
基本实现
将队列分为两部分,前一部分是已经排序好的部分,每一次从未排序好的部分取出最小值插入已排序序列的末尾
def selectionSort(l):
n = len(l)
for i in range(n):
min_index = i
for j in range(i+1, n):
if l[j] < l[min_index]:
min_index = j
if i != min_index:
l[i], l[min_index] = l[min_index], l[i]
return l
优化
每一次遍历确定一个最小值和一个最大值,进行双向选择排序
另外加入一个小的优化,当某一轮选出的最大最小值相等时,排序完成
def selectionSort(l):
n = len(l)
for i in range(n//2):
min_index = i
max_index = -i-1
for j in range(i+1, n-1-i):
if l[j] < l[min_index]:
min_index = j
if l[j] > l[max_index]:
max_index = j
# 判断这一轮选出的最大最小值是否相等
if l[min_index] == l[max_index]:
break
if i != min_index:
l[i], l[min_index] = l[min_index], l[i]
if -i-1 != max_index:
l[-i-1], l[max_index] = l[max_index], l[-i-1]
print(l)
return l
插入排序
基本实现
将数列分为两部分,前一部分为一排序数列,后一部分为未排序数列,每次从未排列数列中取出第一个数按顺序插入已排序数列
def insertSort(l):
n = len(l)
for i in range(n):
j = i-1
num = l[i]
while j>=0 and l[j]>num:
l[j+1] = l[j]
j -= 1
l[j+1] = num
return l
优化
在执行插入操作时,搜索部分使用二分法查找
def insertSort(l):
n = len(l)
for i in range(n):
num = l[i]
right = i-1
left = 0
while left<=right:
mid = (left+right)//2
if l[mid] == num:
left = mid
break
elif l[mid] > num:
right = mid-1
else:
left = mid+1
for s in range(i-1, left-1, -1):
l[s+1] = l[s]
l[left] = num
print(l)
return l
希尔排序
基本实现
def shellSort(l):
n = len(l)
gap = n//2
while gap > 0:
for i in range(gap, n):
while i>=gap and l[i] < l[i-gap]:
l[i], l[i-gap] = l[i-gap], l[i]
i -= gap
gap = gap//2
return l
归并排序
基本实现
def merge(s1, s2, s):
i = j = 0
while i+j<len(s):
if j==len(s2) or (i<len(s1) and s1[i]<s2[j]):
s[i+j] = s1[i]
i += 1
else:
s[i+j] = s2[j]
j += 1
def mergeSort(s):
n = len(s)
if n<=1:
return
mid = n//2
s1 = s[0:mid]
s2 = s[mid:n]
mergeSort(s1)
mergeSort(s2)
merge(s1, s2, s)
return s
快速排序
基本实现
def quickSort(s):
if len(s)<=1:
return
# select a random number as pivot
p = s[0]
left = []
right = []
mid = []
while s:
if s[-1] == p:
mid.append(s.pop())
elif s[-1] <= p:
left.append(s.pop())
else:
right.append(s.pop())
quickSort(left)
quickSort(right)
s.extend(left)
s.extend(mid)
s.extend(right)
return s
堆排序
基本实现
通过将列表构建为堆,每次选出最大的值
def max_heapify(heap, heapsize, root):
left = 2*root + 1
right = left + 1
largest = root
if left<heapsize and heap[left]>heap[largest]:
largest = left
if right<heapsize and heap[right]>heap[largest]:
largest = right
if largest != root:
heap[root], heap[largest] = heap[largest], heap[root]
max_heapify(heap, heapsize, largest)
def build_max_heap(heap):
heapsize = len(heap)
for i in range((heapsize-2)//2, -1, -1):
max_heapify(heap, heapsize, i)
def heapSort(s):
build_max_heap(s)
for i in range(len(s)-1, -1, -1):
s[0], s[i] = s[i], s[0]
max_heapify(s, i, 0)
return s
max_heapify(heap, heapsize, root)
函数用来调节父节点与字节点的位置并递归来始终保持大根堆结构
build_max_heap(heap)
函数用来构建大根堆
计数排序
基本实现
选出数列中最大值和最小值,创建一个长度为 最大值-最小值+1 的数列用来计数,遍历原队列,将各个数据的出现次数存储在计数数列中
def countSort(s):
max_num = max(s)
min_num = min(s)
count = [0 for i in range(max_num-min_num+1)]
for i in s:
count[i-min_num] += 1
s.clear()
for index, num in enumerate(count):
for i in range(num):
s.append(min_num+index)
return s
桶排序
基本实现
桶排序的基本思路为,先设置若干个空桶,并给每一个桶设定所存储的范围,依次遍历数列中的每一个元素,将每个元素插入对应范围的桶内,插入时使用插入排序,确保每个桶内元素排列是有序的,最后依次将各个不为空的桶组合就是排列好的有序数列
关于桶个数的选择并没有明确答案,我在网上看到的一种说法是在占用空间允许的情况下,桶的个数越多越好,具体如何有待考证
def insert(arr, num):
arr.append(num)
i = len(arr)-2
while i>=0:
if num<arr[i]:
arr[i+1] = arr[i]
i -= 1
else:
break
arr[i+1] = num
return arr
def bucketSort(s):
# choose the number of buckets
buckets = 5
arr = [[] for i in range(buckets)]
max_num = max(s)
min_num = min(s)
size = (max_num-min_num+1)//buckets + 1
for i in s:
index = (i-min_num)//size
insert(arr[index], i)
s.clear()
print(arr)
for j in arr:
if len(j) != 0:
s.extend(j)
return s
基数排序
基本实现
基数排序的思路为,从个位开始依次对各个位数上的数字进行排序
def radixSort(s):
i = 0
while i<len(str(max(s))):
buckets = [[] for s in range(10)]
for num in s:
last_num = (num//(10**i)) % 10
buckets[last_num].append(num)
s.clear()
for j in buckets:
s.extend(j)
i += 1
return s
在我写完之后发现一个很明显的问题,以上算法无法处理有负数的情况,我第一反应是将正负数分开排序,但是我在网上找到了一个很妙的解决方案,将所有的元素统一加上一个数字,都变成正数。
def radixSort(s):
add_num = abs(min(s))
for i in range(len(s)):
s[i] += add_num
i = 0
while i<len(str(max(s))):
buckets = [[] for s in range(10)]
for num in s:
last_num = (num//(10**i)) % 10
buckets[last_num].append(num)
s.clear()
for j in buckets:
s.extend(j)
i += 1
for i in range(len(s)):
s[i] -= add_num
return s
相关资料
以上所使用的图片均来自《5分钟学算法》的文章: