排序算法
一、时间复杂度为O(n^2)的排序算法
1、选择排序
def select_sort(li):
for i in range(len(li) - 1):
min_loc = i
for j in range(i, len(li) - 1):
if li[j] < li[min_loc]:
min_loc = j`
if min_loc != i:
li[i], li[min_loc] = li[min_loc], li[i]
return li
2、冒泡排序
def bubble_sort(li):
for i in range(len(li) - 1):
for j in range(len(li) - 1 - i):
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1], li[j]
return li
3、插入排序
def insert_sort(li):
for i in range(1, len(li)):
j = i - 1 # 代表有序区数的下标
tmp = li[i] # 出来的数
while j >= 0 and tmp < li[j]:
li[j + 1] = li[j]
j -= 1
li[j + 1] = tmp
return li
二、时间复杂度为O(nlogn)的排序算法
1、快排
①选出一个临时的数,使得在该数左边的都比它小,右边的都比它大
②两个指针,一个向左走一个向右走,条件是left<right
③在该数右边找到比他小的数放到左边;在该数左边找到比它大的数放到右边(while循环)
④循环结束之后在这个数左边的数都小于它,右边的数都大于它
⑤最后找到mid,left-mid递归,mid+1,right递归
def partition(li, left, right):
tmp = li[left]
while left < right:
while left < right and tmp <= li[right]:
right -= 1
li[left] = li[right]
while left < right and tmp >= li[left]:
left += 1
li[right] = li[left]
li[left] = tmp
return left
def quick_sort(li, left, right):
if left < right:
mid = partition(li, left, right)
quick_sort(li, 0, mid)
quick_sort(li, mid + 1, right)
return li
2、归并
①首先merge函数将数组分为left-mid,以及mid+1-right的部分
②建立一个新的列表,两个指针分别对上面两部分进行拆分
③比较li【i】和li【j】 更小的部分,加入到列表中
④如果左右两部分的长度不一致,总会有一边被先加到临时列表中,最后在把没有比较完的元素加入临时列表
⑤先定义mid,递归左边,递归右边,左右两边合并
def merge(li, left, mid, right):
i = left
j = mid + 1
ltmp = []
while i <= mid and j <= right:
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
while i <= mid:
ltmp.append(li[i])
i += 1
while j <= right:
ltmp.append(li[j])
j += 1
li[left:right+1]=ltmp # 写回到原列表中
def merge_sort(li, left, right):
if left < right:
mid = (left + right) // 2
merge_sort(li, left, mid)
merge_sort(li, mid + 1, right)
merge(li, left, mid, right)
3、堆排序
def sift(li, low, high):
i = low
j = 2 * i + 1
tmp = li[low]
while j <= high:
if j + 1 <= high and li[j] < li[j + 1]:
j += 1
if li[j] > tmp:
li[i] = li[j]
i = j
j = 2 * i + 1
else:
li[i] = tmp
break
else:
li[i] = tmp
def dui_sort(li):
n = len(li)
# 建堆----大根堆(父节点大于每一个孩子节点)
for i in range((n - 2) // 2, -1, -1):
sift(li, i, n - 1) # 建堆时自底向顶
for i in range(n - 1, -1, -1):
li[0], li[i] = li[i], li[0]
sift(li, 0, i-1) # 出数时的调整自顶向下
return li
4、堆排序实现前topK的问题
维护一个k大小的大根堆,建堆-和剩下的元素比较-出数
def sift(li, low, high):
i = low
j = 2 * i + 1
tmp = li[low]
while j <= high:
if j + 1 <= high and li[j] > li[j + 1]:
j += 1
if li[j] < tmp:
li[i] = li[j]
i = j
j = 2 * i + 1
else:
li[i] = tmp
break
else:
li[i] = tmp
def topK(li, k):
heap = li[:k]
# 建堆---小根堆
for i in range((k - 1) // 2, -1, -1)
sift(heap, i, k - 1)
for num in li[k:]:
if num > heap[0]: # heap[0]是大数里最小的数
heap[0] = num
sift(heap, 0, k - 1)
# 出数
for i in range(k - 1, -1, -1):
heap[0], heap[i] = heap[i], heap[0]
sift(heap, 0, i - 1)
return heap
5、桶排序
注释: 分桶----在桶内排序,因为使用appen,每次进来一个元素就和前面的元素比较一次,遇到比它小的数就停掉
def bucket_sort(li,n=10,max_num=1000):
bucket = [[] for i in range(n)]
for num in li:
i = min(num // (max_num // n), n-1)
bucket[i].append(num)
# 一边插入一边排序,所以是从最后一个和前面的比较,遇到比它小的数就结束
for j in range(len(bucket[i])-1,0,-1):
if bucket[i][j] < bucket[i][j-1]:
bucket[i][j],bucket[i][j-1] = bucket[i][j-1],bucket[i][j]
else:
break
buc = []
for val in bucket:
buc.extend(val)
return buc
6、基数排序
def radix_sort(li):
max_num = max(li)
it = 0
while 10 ** it <= max_num:
bucket = [[] for _ in range(10)] # 建桶必须写循环里边,每次循环桶会被清空
for num in li:
i = (num // 10 ** it) % 10
bucket[i].append(num)
li.clear()
for j in bucket:
li.extend(j)
it += 1
return li