1. 选择排序
- 选择排序顾名思义就是每次都从剩下的元素中选择一个最小的放在待排序元素的第一位。算法中第一个for循环是为了遍历一遍元素,第二个for循环是为了找出第一个for循环的index之后最小的元素并将其和index+1的元素交换。
代码如下
def select_sort(origin_items):
A = origin_items[:] #使用切片赋值后改变A的元素origin_items中的元素不会改变。此时是
#两个不同的列表
for i in range(len(A) - 1):
min_index = i
for j in range(i + 1, len(A)):
if A[min_index] > A[j]:
min_index = j
A[i], A[min_index] = A[min_index], A[i]
return A
if __name__ == '__main__':
A = [5, 3, 6, 5, 2, 7, 1, 99, 5]
B = select_sort(A)
print(B)
运行结果:
2. 归并排序(分治法)
- 归并排序是先将待排序元素用merge_sort函数用’//2’的方法分割成最小的单元,然后使用merge函数 对其中的元素进行顺序归并。
代码如下
def merge_sort(item, left, right):
if left < right:
mid = (left+right) // 2
merge_sort(item, left, mid)
merge_sort(item, mid+1, right)
position(item, left, mid, right)
return item
def position(item, left, mid, right):
tmp = []
i = left
j = mid + 1
while i<= mid and j <= right:
if item[i] < item[j]:
tmp.append(item[i])
i+= 1
else:
tmp.append(item[j])
j += 1
while i<= mid:
tmp.append(item[i])
i += 1
while j <= right:
tmp.append(item[j])
j += 1
item[left: right+1] = tmp
if __name__ == '__main__':
A = [5, 2, 3, 6, 8, 1, 0, 99, 2]
A = merge_sort(A, 0, len(A)-1)
print(A)
运行结果:
3. 快速排序
- 快速排序就是取一个中轴(这里选的元素是切片中的第一个元素),使用position函数将待排序元素左边的元素都小于等于中轴,右边的元素都大于中轴,使用_quick_sort调用partition并递归切片(所以也是分治法的思想)。总体就是将待排序元素先按1/2、1/4、1/8。。。切片,再排序使左边都小于右边,最终使整体元素有序。
代码如下
def quick_sort(A):
items = A[:]
_quick_sort(items, 0, len(items)-1)
return items
def _quick_sort(item, left, right):
if left < right:
k = position(item, left, right)
quick_sort(item, left, k-1)
quick_sort(item, k+1, right)
return item
## 这个快排是将最后一个元素当作基准,并且不移动基准直到最后
# def position(item, left, right):
# i = left - 1
# for j in range(left, right):
# if item[j] < item[right]:
# i += 1
# item[i], item[j] = item[j], item[i]
# i += 1
# item[i], item[right] = item[right], item[i]
# return i
## 这个快排是以每一次排序的第一个元素作为基准,将基准拿出来,用填坑的方式交换元素
def position(item, left, right):
tmp = item[left]
while left < right:
while left < right and item[right] >= tmp:
# 这个是降序
# while left < right and item[right] <= tmp:
right -= 1
item[left] = item[right]
while left < right and item[left] <= tmp:
# 这个是降序
# while left < right and item[left] >= tmp:
left += 1
item[right] = item[left]
item[left] = tmp
return left
if __name__ == '__main__':
A = [5, 2, 3, 6, 8, 1, 0, 99, 2]
A = quick_sort(A)
print(A)
运行结果:
4. 堆排序
堆排序就是使用列表的形式来表示一个完全二叉树,通过sift函数调整这个数,使得最大的数或者最小的数放在子树的根节点,然后将这个节点放到树的待排序的最后,循环就得到了有序
import random
def heap_sort(item):
n = len(item)
# 从最后一个有孩子节点的根节点开始循环调用调整函数,使所有的父节点都大于孩子节点,调整完后根节点就是最大的数,然后依次出数
# 这个过程就是构造大根堆(构造小根堆在调整函数里改两个符号即可)
for i in range(n//2-1, -1, -1):
sift(item, i, n-1)
# 将根节点出数,将最后一个节点放到根节点并开始一次调整,得到剩余堆里最大的元素
for i in range(n-1, -1, -1):
# 将根节点也就是最大的节点和最后一个节点换位置,这样不用再开辟一个新列表存储有序元素,是升序
item[0], item[i] = item[i], item[0]
sift(item, 0, i-1)
return item
def sift(item, low, high):
i = low
# j是i的左孩子(如果有的话)
j = 2 * i +1
tmp = item[i]
while j <= high:
# 如果i有右孩子并且右孩子比左孩子的值大,就让j指向右孩子
if j < high and item[j] < item[j+1]:
# 构建小根堆(只需要改两个符号即可)
# if j < high and item[j] > item[j+1]:
j += 1
# 如果孩子的值比父节点大就把孩子节点上升到父节点,最初的父节点在tmp里放着
if tmp < item[j]:
# 构建小根堆
# if tmp > item[j]:
item[i] = item[j]
# 把刚刚较大的孩子节点当成新的父节点并重新开始循环
i = j
# j就是新的父节点的左孩子
j = 2 * i + 1
else:
break
# 将最开始的根节点放到相应的父节点(或叶子节点)
item[i] = tmp
if __name__ == '__main__':
A = []
for i in range(100):
A.append(random.randint(0, 1000))
print(heap_sort(A))
运行结果:
- 比较:
from time import time
import random
import copy
import sys
sys.setrecursionlimit(10000000)
def bubble(A):
for i in range(len(A)-1):
for j in range(len(A)-i-1):
if A[j] > A[j+1]:
A[j], A[j+1] = A[j+1], A[j]
return A
def select_sort(A):
for i in range(len(A)-1):
for j in range(i, len(A)):
if A[j] < A[i]:
A[i], A[j] = A[j], A[i]
return A
# 这里换了另一种写法
def merge_sort(A):
if len(A) < 2:
return A[:]
mid = len(A) // 2
left = merge_sort(A[:mid])
right = merge_sort(A[mid:])
return merge(left, right)
def merge(item1, item2):
index1, index2 = 0, 0
item = []
while index1 < len(item1) and index2 < len(item2):
if item1[index1] < item2[index2]:
item.append(item1[index1])
index1 += 1
else:
item.append(item2[index2])
index2 += 1
item += item1[index1:]
item += item2[index2:]
return item
def quick_sort(A):
item = A[:]
_quick_sort(item, 0, len(item)-1)
return item
def _quick_sort(item, start, end):
if start < end:
k = position(item, start, end)
_quick_sort(item, start, k-1)
_quick_sort(item, k+1, end)
# 这里换了另一种写法
def position(item, start, end):
i = start - 1
for j in range(start, end):
if item[j] <= item[end]:
i += 1
item[i], item[j] = item[j], item[i]
i += 1
item[i], item[end] = item[end], item[i]
return i
if __name__ == '__main__':
A = [i for i in range(10000)]
random.shuffle(A)
B = copy.deepcopy(A)
C = copy.deepcopy(A)
D = copy.deepcopy(A)
E = copy.deepcopy(A)
print('待排序元素个数: %d' % len(A))
start1 = time()
A = select_sort(A) #选择排序
end1 = time()
merge_sort(B) #归并排序
end2 = time()
quick_sort(C) #快速排序
end3 = time()
D.sort()
end4 = time()
G = sorted(F)
end5 = time()
E = bubble(E)
end6 = time()
print('选择排序的时间为:%.18f' % (end1 - start1))
print('归并排序的时间为:%.18f' % (end2 - end1))
print('快速排序的时间为:%.18f' % (end3 - end2))
print('sort排序的时间为:%.18f' % (end4 - end3))
print('sorted排序的时间为:%.18f' % (end5 - end4))
print('冒泡排序的时间为:%.18f' % (end6 - end5))
print('运行总时间为:%.18f' % (end6 - start1))
运行结果:
由图可知快速排序速度最快(sort是改进的归并排序和插入排序的组合)
A.sort() A自身排序
B = sorted(A) 将A的有序返回给B,A不变