【超全面!Python10种面试排序方法总结】

low B三人组NB 三人组其他排序
冒泡排序快速排序希尔排序
选择排序堆排序计数排序
插入排序归并排序基数排序

一、冒泡排序

  • 列表每两个相邻的数,如果前面比后面大,则交换这两个数
  • 一趟排序完成后,则无序区减少一个数,有序区增加一个数
  • 关键点:趟、无序区范围
def bubble_sort(li):
    for i in range(len(li)-1):
        exchange = False
        for j in range(len(li)-i-1):
            if li[j] > li[j+1]:
                li[j], li[j+1] = li[j+1], li[j]
                exchange = True
        if not exchange:
            return li

# 测试样例
import random
li = [i for i in range(10)]
random.shuffle(li)
print(li)
bubble_sort(li)
print(li)

'''result
[7, 5, 1, 6, 9, 0, 2, 3, 8, 4]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
'''

二、选择排序

  • 从列表中选择一个最小的,放到新的列表,该过程循环n次
# 非原地排序,需重新开辟新数组
def select_sort_simple(li):
	li_new = []
	for i in range(len(li)):
		for val in li:
			min_val = min(li)
			li_new.append(min_val)
			li.remove(min_val)
	return li_new
  • 对上述方法优化,采用原地排序,因此遍历 n-1 次即可
  • 一趟排序记录最小的数,放到第一个位置
  • 在一趟排序记录无序区最小的数,放到第二个位置, …
  • 关键点:有序区、无序区、无序区最小数的位置
def select_sort(li):
	for i in range(len(li)-1):
		min_col = i
		for j in range(i+1, len(i):
			if li[j] < li[min_col]:
				min_col = j
		li[i], li[min_col] = li[min_col], li[i]
	return li

三、插入排序

  • 初始时手里(有序区)只有一张牌
  • 每次(从无序区)摸一张牌,插入到手里已有手牌的正确位置
def insert_sort(li):
	for i in range(1, len(i)):
		tmp = li[i]
		j = i -1
		while li[j] > tmp and j >= 0:
			li[j+1] = li[j]
			j -= 1
		li[j+1] = tmp
	return li

四、快速排序

def partition(li, left, right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            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, left, mid-1)
        quick_sort(li, mid+1, right)

五、堆排序

  1. 建立堆(最大堆)
  2. 得到堆顶元素,为最大元素
  3. 去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序
  4. 堆顶元素为第二大元素
  5. 重复步骤3,直至堆变空
  • 从父亲找孩子:i = low,j = 2*i+1
  • 从孩子找父亲:j = high,i = (j-1) // 2
def sift(li, low, high):
	i = low
	j = 2*i+1
	tmp = li[low]
	while j <= high:
		if j+1 <= high and li[j+1] > li[j]:
			j = j+1
		if li[j] > tmp:
			li[i] = li[j]
			i = j
			j = 2*i+1
		else:
			break
	li[i] = tmp

def heap_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)

使用内置模块heapq实现堆排序

  • 常用函数:
    1. heapify(x): 建最小堆
    2. heappush(heap, item)
    3. heappop(heap): 每次弹出最小元素
import heapq
import random

li = list(range(10))
random.shuffle(li)
print('无序列表', li)

heapq.heapify(li) # 建堆

new_li = []
for i in range(len(li)):
	min_value = heapq.heappop(li) # 每次弹出最小元素
	new_li.append(min_val)

六、归并排序

  • 分解:将列表越分越小,直至分成一个元素
  • 终止条件:一个元素是有序的
  • 合并:将两个有序列表归并,列表越来越大
def merge(li, low, mid, high):
	i = low
	j = mid+1
	ltmp = []
	while i <= mid and j <= high:
		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 <= mid:
		ltmp.append(li[j])
		j += 1
	li[low:high+1] = ltmp

def merge_sort(li, low, high):
	if low < high:
		mid = (low + high) // 2
		merge_sort(li, low, mid)
		merge_sort(li, mid+1, high)
		merge(li, low, mid, high)

七、希尔排序

  • 首先取一个整数d1 = n/2,将元素分为d1个组,每组相邻元素之间距离为d1,在各组内进行插入排序。
  • 取第二个整数d2 = d1/2,重复上述分组排序过程,直到d1=1,即:所有元素在同一组内进行直接插入排序。
  • 希尔排序每趟并不使某些元素有序,而是整体数据越来越接近有序;最后一趟排序使得所有数据有序。
def insert_sort_gap(li, gap):
	for i in range(gap, len(li)):
		tmp = li[i]
		j = i -gap
		while j >= 0 and li[j] > tmp:
			li[j+gap] = li[j]
			j -= gap
		li[j+gap] = tmp

def shell_sort(li):
	d = len(li) // 2
	while d >= 1:
		insert_sort_gap(li, d)
		d //= 2

八、计数排序

  • 对列表进行排序,已知列表中的数范围都在0-100之间,设计复杂度为O(n)的算法。
def count_sort(li, max_count=100):
	count = [0 for _ in range(max_count+1)]
	for val in li:
		count[val] += 1
	li.clear()
	for ind, val in enumerate(count):
		for i in range(val):
			li.append(ind)

九、桶排序

  • 桶排序的表现取决于数据的分布。也就是需要对不同数据排序时采取不同的分桶策略。
  • 平均情况时间复杂度: O(n+k)
  • 最坏情况时间复杂度: O(n2k)
  • 空间复杂度:O(nk)
def bucket_sort(li, n=5, max_num=10):
	buckets = [[] for _ in range(n)]
	for var in li:
		i = min(var//(max_num//n), n-1)
		buckets[i].append(var)
		for j in range(len(buckets[i])-1, 0, -1):
			if buckets[i][j] < buckets[i][j-1]:
				buckets[i][j], buckets[i][j-1] = buckets[i][j-1], buckets[i][j]
			else:
				break
	sorted_li = []
	for buc in buckets:
		sorted_li.extend(buc)
	return sorted_li

十、基数排序

  • 多关键字排序
  • 时间复杂度:O(kn)
  • 空间复杂度:O(k+n)
  • k表示数字位数
def radix_sort(li):
	max_num = max(li)
	it = 0
	while it**10 <= max_num:
		buckets = [[] for i in range(10)]
		for var in li:
			digit = (var//10**it)%10
			buckets[digit].append(var)
		li.clear()
		for buc in buckets:
			li.extend(buc)
		it += 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值