排序算法作为计算机科学领域最基础的算法模块,其掌握程度直接决定了程序员的代码质量与工程效率。无论是优化数据库查询、构建高效索引,还是处理海量数据流,深入理解排序原理与实现逻辑都是绕不开的必修课。
基于此,博主系统整理了十大经典排序算法的Python实现方案,涵盖:
-
冒泡排序(教学级入门算法)
-
快速排序(面试高频考点)
-
选择排序(直观但低效)
-
堆排序(原地排序王者)
-
插入排序(简单场景利器)
-
希尔排序(插入排序升级版)
-
归并排序(分治思想典范)
-
计数排序(线性时间奇迹)
-
基数排序(字符串/整数专用)
-
桶排序(分布均匀数据首选)
希望对大家有所帮助,如有疑问或者需要改进的地方可以联系博主。
01 冒泡排序
冒泡排序(Bubble Sort): 一个经典的排序算法,因在算法运行中,极值会像水底的气泡一样逐渐冒出来,因此而得名。
算法原理:
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
'''冒泡排序'''
def Bubble_Sort(arr):
for i in range(1, len(arr)):
for j in range(0, len(arr)-i):
if arr[j] > arr[j+1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
arr = [29, 63, 41, 5, 62, 66, 57, 34, 94, 22]
result = Bubble_Sort(arr)
print('result list: ', result)
# result list: [5, 22, 29, 34, 41, 57, 62, 63, 66, 94]
这里插播一条粉丝福利,如果你正在学习Python或者有计划学习Python,想要突破自我,对未来十分迷茫的,可以点击这里获取最新的Python学习资料和学习路线规划(免费分享,记得关注)
02 快速排序
快速排序(Quicksort):通过一趟排序将要排序的数据分割成独立的两部分,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列,是对冒泡排序算法的一种改进。
算法原理:
-
首先设定一个分界值,通过该分界值将数组分成左右两部分。
-
将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
-
然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
-
重复上述过程,直到左、右两个部分各数据排序完成。
'''快速排序'''
def Quick_Sort(arr):
# 递归入口及出口
if len(arr) >= 2:
# 选取基准值,也可以选取第一个或最后一个元素
mid = arr[len(arr) // 2]
# 定义基准值左右两侧的列表
left, right = [], []
# 从原始数组中移除基准值
arr.remove(mid)
for num in arr:
if num >= mid:
right.append(num)
else:
left.append(num)
return Quick_Sort(left) + [mid] + Quick_Sort(right)
else:
return arr
arr = [27, 70, 34, 65, 9, 22, 47, 68, 21, 18]
result = Quick_Sort(arr)
print('result list: ', result)
# result list: [9, 18, 21, 22, 27, 34, 47, 65, 68, 70]
03 选择排序
选择排序(Selection sort):是一种简单直观的排序算法。无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。
算法原理:
-
在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
-
从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
-
以此类推,直到所有元素均排序完毕。
'''选择排序'''
def Selection_Sort(arr):
for i in range(len(arr) - 1):
# 记录最小数的索引
minIndex = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[minIndex]:
minIndex = j
# i 不是最小数时,将 i 和最小数进行交换
if i != minIndex:
arr[i], arr[minIndex] = arr[minIndex], arr[i]
return arr
arr = [5, 10, 76, 55, 13, 79, 49, 51, 65, 30]
result = Selection_Sort(arr)
print('result list: ', result)
# result list: [5, 10, 13, 30, 49, 51, 55, 65, 76, 79]
04 堆排序
堆排序(Heap sort):是指利用堆这种数据结构所设计的一种排序算法,堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。
算法原理:
-
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
-
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。
'''堆排序'''
def Heapify(arr, n, i):
largest = i
# 左右节点分块
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[i] < arr[left]:
largest = left
if right < n and arr[largest] < arr[right]:
largest = right
if largest != i:
# 大小值交换
arr[i], arr[largest] = arr[largest], arr[i]
# 递归
Heapify(arr, n, largest)
def Heap_Sort(arr):
nlen = len(arr)
for i in range(nlen, -1, -1):
# 调整节点
Heapify(arr, nlen, i)
for i in range(nlen - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
# 调整节点
Heapify(arr, i, 0)
return arr
arr = [26, 53, 83, 86, 5, 46, 72, 21, 4, 75]
result = Heap_Sort(arr)
print('result list: ', result)
# result list: [4, 5, 21, 26, 46, 53, 72, 75, 83, 86]
05 插入排序
插入排序(Insertion Sort):一般也被称为直接插入排序,是一种最简单直观的排序算法。
算法原理:
-
创建一个堆 H[0……n-1];
-
把堆首(最大值)和堆尾互换;
-
把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
-
重复步骤 2,直到堆的尺寸为 1。
'''插入排序'''
def Insertion_Sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
return arr
arr = [31, 80, 42, 47, 35, 26, 10, 5, 51, 53]
result = Insertion_Sort(arr)
print('result list: ', result)
# result list: [5, 10, 26, 31, 35, 42, 47, 51, 53, 80]
06 希尔排序
希尔排序(Shell Sort): 是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。
算法原理:
-
取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中
-
对各组内的元素进行直接插入排序, 这一趟排序完成之后,每一个组的元素都是有序的
-
减小gap的值,并重复执行上述的分组和排序
-
重复上述操作,当gap=1时,排序结束
'''希尔排序'''
def Shell_Sort(arr):
# 设定步长,注意类型
step = int(len(arr) / 2)
while step > 0:
for i in range(step, len(arr)):
# 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置
while i >= step and arr[i - step] > arr[i]:
arr[i], arr[i - step] = arr[i - step], arr[i]
i -= step
step = int(step / 2)
return arr
arr = [29, 63, 41, 5, 62, 66, 57, 34, 94, 22]
result = Shell_Sort(arr)
print('result list: ', result)
# result list: [5, 22, 29, 34, 41, 57, 62, 63, 66, 94]
07 归并排序
归并排序(Merge Sort):是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列。
算法原理:
-
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
-
设定两个索引,最初索引位置分别为两个已经排序序列的起始位置
-
比较两个索引所指向的元素,选择相对小的元素放入到合并空间,并移动索引到下一位置
-
重复上一步骤直到某一索引超出序列尾
-
将另一序列剩下的所有元素直接复制到合并序列尾
'''归并排序'''
def Merge(left, right):
arr = []
i = j = 0
while j < len(left) and i < len(right):
if left[j] < right[i]:
arr.append(left[j])
j += 1
else:
arr.append(right[i])
i += 1
if j == len(left):
# right遍历完
for k in right[i:]:
arr.append(k)
else:
# left遍历完
for k in left[j:]:
arr.append(k)
return arr
defMerge_Sort(arr):
# 递归结束条件
if len(arr) <= 1:
return arr
# 二分
middle = len(arr) // 2
left = Merge_Sort(arr[:middle])
right = Merge_Sort(arr[middle:])
# 合并
return Merge(left, right)
arr = [27, 70, 34, 65, 9, 22, 47, 68, 21, 18]
result = Merge_Sort(arr)
print('result list: ', result)
# result list: [9, 18, 21, 22, 27, 34, 47, 65, 68, 70]
08 计数排序
计数排序(Count sort):是一个非基于比较的排序算法,它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。
算法原理:
-
找出待排序的数组中最大和最小的元素
-
统计数组中每个值为i的元素出现的次数,存入数组C的第i项
-
对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
-
反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
'''计数排序'''
def Count_Sort(arr):
max_num = max(arr)
min_num = min(arr)
count_num = max_num - min_num + 1
count_arr = [0for i in range(count_num)]
res = [0for i in range(len(arr))]
# 统计数字出现的次数
for i in arr:
count_arr[i - min_num] += 1
# 统计前面有几个比自己小的数
for j in range(1, count_num):
count_arr[j] = count_arr[j] + count_arr[j - 1]
# 遍历重组
for k in range(len(arr)):
res[count_arr[arr[k] - min_num] - 1] = arr[k]
count_arr[arr[k] - min_num] -= 1
return res
arr = [5, 10, 76, 55, 13, 79, 5, 49, 51, 65, 30, 5]
result = Count_Sort(arr)
print('result list: ', result)
# result list: [5, 5, 5, 10, 13, 30, 49, 51, 55, 65, 76, 79]
09 基数排序
基数排序(radix sort):是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
算法原理(以LSD为例):
-
根据个位数的数值,遍历列表将它们分配至编号0到9的桶子中
-
将这些桶子中的数值重新串接起来
-
根据十位数的数值,遍历列表将它们分配至编号0到9的桶子中
再将这些桶子中的数值重新串接起来
'''基数排序'''
def Radix_Sort(arr):
max_num = max(arr)
place = 0
while10 ** place <= max_num:
# 创建桶
buckets = [[] for _ in range(10)]
# 分桶
for item in arr:
pos = item // 10 ** place % 10
buckets[pos].append(item)
j = 0
for k in range(10):
for num in buckets[k]:
arr[j] = num
j += 1
place += 1
return arr
arr = [31, 80, 42, 47, 35, 26, 10, 5, 51, 53]
result = Radix_Sort(arr)
print('result list: ', result)
# result list: [5, 10, 26, 31, 35, 42, 47, 51, 53, 80]
10 桶排序
桶排序 (Bucket sort)或所谓的箱排序:划分多个范围相同的桶区间,每个桶自排序,最后合并,桶排序可以看作是计数排序的扩展。
算法原理:
-
计算有限桶的数量
-
逐个桶内部排序
-
遍历每个桶,进行合并
'''桶排序'''
def Bucket_Sort(arr):
num = max(arr)
# 列表置零
pre_lst = [0] * num
result = []
for data in arr:
pre_lst[data - 1] += 1
i = 0
while i < len(pre_lst): # 遍历生成的列表,从小到大
j = 0
while j < pre_lst[i]:
result.append(i + 1)
j += 1
i += 1
return result
arr = [26, 53, 83, 86, 5, 46, 5, 72, 21, 4, 75]
result = Bucket_Sort(arr)
print('result list: ', result)
# result list: [4, 5, 5, 21, 26, 46, 53, 72, 75, 83, 86]
全套Python学习资料分享:
一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
三、python入门资料大全
四、python进阶资料大全
五、python爬虫专栏
六、入门学习视频全套
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
七、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
八、python最新面试题
获取资料:扫描下方CSDN官方二维码获娶↓↓↓↓↓