当前位置: 首页 > news >正文

【Python 算法零基础 4.排序 ⑪ 十大排序算法总结】

目录

一、选择排序回顾

二、冒泡排序回顾

三、插入排序回顾

四、计数排序回顾

五、归并排序回顾

六、快速排序回顾

七、桶排序回顾

八、基数排序

九、堆排序

十、希尔排序

 十一、十大排序算法对比

十二、各算法详解与应用场景 

1. 选择排序(Selection Sort)

2. 冒泡排序(Bubble Sort)

3. 插入排序(Insertion Sort)

4. 计数排序(Counting Sort)

5. 归并排序(Merge Sort)

6. 快速排序(Quick Sort)

7. 桶排序(Bucket Sort)

8. 基数排序(Radix Sort)

9. 堆排序(Heap Sort)

10. 希尔排序(Shell Sort)

十三、各大排序算法的决策指南

1.数据规模

2.数据特性

3.稳定性需求

4.空间限制

5.特殊场景:


料青山略输我峥嵘,判江河亦低我磅礴

                                                        —— 25.6.6

一、选择排序回顾

① 遍历数组:从索引 0 到 n-1n 为数组长度)。

② 每轮确定最小值:假设当前索引 i 为最小值索引 min_index。从 i+1 到 n-1 遍历,若找到更小元素,则更新 min_index

③ 交换元素:若 min_index ≠ i,则交换 arr[i] 与 arr[min_index]

'''
① 遍历数组:从索引 0 到 n-1(n 为数组长度)。② 每轮确定最小值:假设当前索引 i 为最小值索引 min_index。从 i+1 到 n-1 遍历,若找到更小元素,则更新 min_index。③ 交换元素:若 min_index ≠ i,则交换 arr[i] 与 arr[min_index]。
'''def selectionSort(arr: List[int]):n = len(arr)for i in range(n):min_index = ifor j in range(i+1, n):if arr[j] < arr[min_index]:min_index = jif min_index != i:arr[i], arr[min_index] = arr[min_index], arr[i]return arr

二、冒泡排序回顾

① 初始化:设数组长度为 n

② 外层循环:遍历 i 从 0 到 n-1(共 n 轮)。

③ 内层循环:对于每轮 i,遍历 j 从 0 到 n-i-2

④ 比较与交换:若 arr[j] > arr[j+1],则交换两者。

⑤ 结束条件:重复步骤 2-4,直到所有轮次完成。

'''
① 初始化:设数组长度为 n。② 外层循环:遍历 i 从 0 到 n-1(共 n 轮)。③ 内层循环:对于每轮 i,遍历 j 从 0 到 n-i-1。④ 比较与交换:若 arr[j] > arr[j+1],则交换两者。⑤ 结束条件:重复步骤 2-4,直到所有轮次完成。
'''
def bubbleSort(arr: List[int]):n = len(arr)for i in range(n):for j in range(n-i-1):if arr[j] > arr[j+1]:arr[j], arr[j+1] = arr[j+1], arr[j]return arr

三、插入排序回顾

① 遍历未排序元素:从索引 1 到 n-1

② 保存当前元素:将 arr[i] 存入 current

③ 元素后移:从已排序部分的末尾(索引 j = i-1)向前扫描,将比 current 大的元素后移。直到找到第一个不大于 current 的位置或扫描完所有元素。

④ 插入元素:将 current 放入 j+1 位置。

'''
① 遍历未排序元素:从索引 1 到 n-1。② 保存当前元素:将 arr[i] 存入 current。③ 元素后移:从已排序部分的末尾(索引 j = i-1)向前扫描,将比 current 大的元素后移。直到找到第一个不大于 current 的位置或扫描完所有元素。④ 插入元素:将 current 放入 j+1 位置。
'''
def insertSort(arr: List[int]):n = len(arr)for i in range(n):current = arr[i]j = i - 1while current < arr[j] and j >0:arr[j+1] = arr[j]j -= 1arr[j + 1] = currentreturn arr

四、计数排序回顾

① 初始化:设数组长度为 n,元素最大值为 r。创建长度为 r+1 的计数数组 count,初始值全为 0。

② 统计元素频率:遍历原数组 arr,对每个元素 x,将 count[x] 加 1。

③ 重构有序数组:初始化索引 index = 0。遍历计数数组 count,索引 v 从 0 到 r,若 count[v] > 0,则将 v 填入原数组 arr[index],并将 index 加 1。count[v] - 1,重复此步骤直到 count[v] 为 0。

④ 结束条件:当计数数组遍历完成时,排序结束。

'''
输入全为非负整数,且所有元素 ≤ r① 初始化:设数组长度为 n,元素最大值为 r。创建长度为 r+1 的计数数组 count,初始值全为 0。② 统计元素频率:遍历原数组 arr,对每个元素 x,将 count[x] 加 1。③ 重构有序数组:初始化索引 index = 0。遍历计数数组 count,索引 v 从 0 到 r,
若 count[v] > 0,则将 v 填入原数组 arr[index],并将 index 加 1。
count[v] - 1,重复此步骤直到 count[v] 为 0。④ 结束条件:当计数数组遍历完成时,排序结束。
'''def countingSort(arr: List[int], r: int):# count = [0] * len(r + 1)count = [0 for i in range(r + 1)]for x in arr:count[x] += 1index = 0for v in range(r + 1):while count[v] > 0:arr[index] = vindex += 1count[v] -= 1return arr

五、归并排序回顾

Ⅰ、递归分解列表

① 终止条件:若链表为空或只有一个节点(head is None 或 head.next is None),直接返回头节点。

② 快慢指针找中点:初始化 slow 和 fast 指针,slow 指向头节点,fast 指向头节点的下一个节点。fast 每次移动两步,slow 每次移动一步。当 fast 到达末尾时,slow 恰好指向链表的中间节点。

③ 分割链表:将链表从中点断开,head2 指向 slow.next(后半部分的头节点)。将 slow.next 置为 None,切断前半部分与后半部分的连接。

④ 递归排序子链表:对前半部分(head)和后半部分(head2)分别递归调用 mergesort 函数。

Ⅱ、合并两个有序列表

① 创建虚拟头节点:创建一个值为 -1 的虚拟节点 zero,用于简化边界处理。使用 current 指针指向 zero,用于构建合并后的链表。

② 比较并合并节点:遍历两个子链表 head1 和 head2,比较当前节点的值:若 head1.val <= head2.val,将 head1 接入合并链表,并移动 head1 指针。否则,将 head2 接入合并链表,并移动 head2 指针。每次接入节点后,移动 current 指针到新接入的节点。

③ 处理剩余节点:当其中一个子链表遍历完后,将另一个子链表的剩余部分直接接入合并链表的末尾。

④ 返回合并后的链表:虚拟节点 zero 的下一个节点即为合并后的有序链表的头节点。

'''
Ⅰ、递归分解列表① 终止条件:若链表为空或只有一个节点(head is None 或 head.next is None),直接返回头节点。② 快慢指针找中点:初始化 slow 和 fast 指针,slow 指向头节点,fast 指向头节点的下一个节点。fast 每次移动两步,slow 每次移动一步。当 fast 到达末尾时,slow 恰好指向链表的中间节点。③ 分割链表:将链表从中点断开,head2 指向 slow.next(后半部分的头节点)。将 slow.next 置为 None,切断前半部分与后半部分的连接。④ 递归排序子链表:对前半部分(head)和后半部分(head2)分别递归调用 mergesort 函数。Ⅱ、合并两个有序列表① 创建虚拟头节点:创建一个值为 -1 的虚拟节点 zero,用于简化边界处理。使用 current 指针指向 zero,用于构建合并后的链表。② 比较并合并节点:遍历两个子链表 head1 和 head2,比较当前节点的值:若 head1.val <= head2.val,将 head1 接入合并链表,并移动 head1 指针。否则,将 head2 接入合并链表,并移动 head2 指针。每次接入节点后,移动 current 指针到新接入的节点。③ 处理剩余节点:当其中一个子链表遍历完后,将另一个子链表的剩余部分直接接入合并链表的末尾。④ 返回合并后的链表:虚拟节点 zero 的下一个节点即为合并后的有序链表的头节点。
'''
def mergesort(self, head: ListNode):if head is None or head.next is None:return headslow, fast = head, head.nextwhile fast and fast.next:slow = slow.nextfast = fast.next.nexthead2 = slow.nextslow.next = Nonereturn self.merge(self.mergesort(head), self.mergesort(head2))def merge(self, head1: ListNode, head2: ListNode):zero = ListNode(-1)current = zerowhile head1 and head2:if head1.val <= head2.val:current.next = head1head1 = head1.nextelse:current.next = head2head2 = head2.nextcurrent = current.nextcurrent.next = head1 if head1 else head2return zero.next

六、快速排序回顾

Ⅰ、分区函数 Partition

① 随机选择基准元素:根据左右边界下标随机选择基准元素(选择的是元素并非下标),将基准元素赋值变量进行后续比较

② 交换基准元素:将基准元素移动到最左边,将基准元素存储在变量中,

③ 分区操作:对于基准元素右边的元素,找到第一个小于基准元素的值,移动到最左边;对于基准元素左边的元素,找到第一个大于基准元素的值,移动到最右边

④ 返回基准元素的最终位置:循环执行完毕后,基准元素左边的值都小于它,基准元素右边的值都大于它

Ⅱ、递归快速排序函数

① 定义递归终止条件:当左索引小于右索引时,结束递归

② 分区操作: 执行第一次分区操作,找到基准元素

③ 递归调用分区函数:将基准元素的左边、右边部分分别传入递归函数进行排序

'''
Ⅰ、分区函数 Partition① 随机选择基准元素:根据左右边界下标随机选择基准元素(选择的是元素并非下标),将基准元素赋值变量进行后续比较② 交换基准元素:将基准元素移动到最左边,将基准元素存储在变量中,③ 分区操作:对于基准元素右边的元素,找到第一个小于基准元素的值,移动到最左边;对于基准元素左边的元素,找到第一个大于基准元素的值,移动到最右边④ 返回基准元素的最终位置:循环执行完毕后,基准元素左边的值都小于它,基准元素右边的值都大于它Ⅱ、递归排序函数① 定义递归终止条件:当左索引小于右索引时,结束递归② 分区操作: 执行第一次分区操作,找到基准元素③ 递归调用分区函数:将基准元素的左边、右边部分分别传入递归函数进行排序
'''def Partition(arr, left, right):idx = random.randint(left, right)arr[left], arr[idx] = arr[idx], arr[left]l = leftr = rightx = arr[l]while l < r:while l < r and x < arr[r]:r -= 1if l < r:arr[l], arr[r] = arr[r], arr[l]l += 1while l < r and x > arr[l]:l += 1if l < r:arr[l], arr[r] = arr[r], arr[l]r -= 1return ldef quickSort(arr, l, r):if l >= r:returnnode = self.quickSort(l, r)self.quickSort(arr, l, node-1)self.quickSort(arr, node+1, r)return arr

七、桶排序回顾

① 初始化桶和频率数组: 创建字符长度+1的桶bucket,索引 i 表示频率为 i 的字符列表;长度为max的频率数组count,用于记录每个字符的出现次数

② 统计字符频率:通过 ord(char) 获取字符的ASCII码,作为频率数组的索引

③ 将字符按照频率放入桶中:遍历频率数组,将每个字符以频率作为索引放入数组中

④ 返回桶数组:返回桶数组,其中每个桶包含对应频率的字符列表

def bucketSort(arr, max_val):  # 移除 max_val 表示字符编码最大值(如 256)n = len(arr)# 初始化桶:索引范围 [0, max_val-1]bucket = [[] for _ in range(max_val)]# 分布:按字符编码放入桶for char in arr:bucket[ord(char)].append(char)  # 索引 = 字符编码值# 合并桶(索引升序即字符升序)sorted_arr = []for b in bucket:sorted_arr.extend(b)  # 每个桶内元素已按插入顺序排列return sorted_arr  # 返回排序后的一维数组

八、基数排序

① 初始化参数和辅助数组:设置最大元素数MAX_N为 50000,最大位数MAX_T为 8,进制BASE为 10;计算并存储基数的各次幂(如 10⁰, 10¹, ..., 10⁷)到数组PowOfBase

② 预处理数组元素:为每个元素加上BASE^(MAX_T-1)(即 10⁷),确保所有元素变为正数;这一步是为了处理可能的负数输入,将其转换为正数进行排序

③ 按位进行多轮排序:从最低有效位(个位)开始,逐位进行处理(共进行MAX_T轮)

        分配阶段:将元素分配到对应的桶(0-9)中对每个元素,计算当前位上的数字(通过整除和取模运算)

        收集阶段:按桶的顺序(0 到 9)依次收集元素;将收集的元素依次放回原数组,覆盖原有的顺序

④ 恢复原始数值:排序完成后,从每个元素中减去BASE^(MAX_T-1)(即 10⁷);恢复元素的原始值,完成排序过程

'''
基数排序① 初始化参数和辅助数组:设置最大元素数MAX_N为 50000,最大位数MAX_T为 8,进制BASE为 10;计算并存储基数的各次幂(如 10⁰, 10¹, ..., 10⁷)到数组PowOfBase中② 预处理数组元素:为每个元素加上BASE^(MAX_T-1)(即 10⁷),确保所有元素变为正数;这一步是为了处理可能的负数输入,将其转换为正数进行排序③ 按位进行多轮排序:从最低有效位(个位)开始,逐位进行处理(共进行MAX_T轮)分配阶段:将元素分配到对应的桶(0-9)中对每个元素,计算当前位上的数字(通过整除和取模运算)收集阶段:按桶的顺序(0 到 9)依次收集元素;将收集的元素依次放回原数组,覆盖原有的顺序④ 恢复原始数值:排序完成后,从每个元素中减去BASE^(MAX_T-1)(即 10⁷);恢复元素的原始值,完成排序过程
'''MAX_N = 50000    # 最多的元素数MAX_T = 8        # 元素的最大位数BASE = 10        # 定义数字的进制def RedixSort(self, arr):n = len(arr)PowOfBase = [1 for i in range(self.MAX_T)]    # 代表BASE的多少次方for i in range(1, self.MAX_T):PowOfBase[i] = PowOfBase[i - 1] * self.BASEfor i in range(n):arr[i] += PowOfBase[self.MAX_T - 1]pos = 0 while pos < self.MAX_T:RedixBucket = [ [] for i in range(self.BASE)]for i in range(n):rdx = arr[i] // PowOfBase[pos] % self.BASERedixBucket[rdx].append( arr[i] )top = 0for i in range(self.BASE):for rb in RedixBucket[i]:arr[top] = rbtop += 1pos += 1for i in range(n):arr[i] -= PowOfBase[self.MAX_T - 1]return arr

九、堆排序

 堆排序

辅助函数(节点关系):

leftSon(idx)返回节点idx的左子节点索引(2*idx + 1)。

rightSon(idx)返回节点idx的右子节点索引(2*idx + 2)。

parent(idx)返回节点idx的父节点索引((idx-1)//2)。

better(a, b)比较函数,默认返回a > b,用于定义最大堆的比较规则。

Heapify 函数:

Ⅰ、计算子节点索引

leftSon(curr) 和 rightSon(curr) 分别计算当前节点的左右子节点索引。

optId 初始化为当前节点索引,用于记录最大值的位置。

Ⅱ、找出最大值索引

比较当前节点与左右子节点的值:如果左子节点存在且值更大,则更新 optId 为左子节点索引。同理,对右子节点进行相同比较。better 函数默认实现为 a > b,确保构建最大堆。

Ⅲ、交换并递归调整

如果最大值不在当前节点(curr != optId),则交换当前节点与最大值节点。

递归调用 Heapify 处理被交换的子节点,确保其所有子树仍满足堆性质。

sortArray 函数

构建最大堆:从最后一个非叶子节点(n//2 -1)开始,向上逐个调用Heapify,确保整个数组成为最大堆。

循环过程:将堆顶元素(最大值)与当前未排序部分的最后一个元素交换;减少堆的大小(size = i),将最大值排除在后续调整范围外;调用 Heapify(0) 重新调整剩余元素为最大堆。

效果:每次循环将当前最大值移至数组末尾,最终形成升序排列。

def leftSon(idx):return 2 * idx + 1def rightSon(idx):return 2 * idx + 2def parent(idx):return (idx - 1) // 2def better(a, b):return a > b class Solution:def Heapify(self, heap, size, curr):leftSonId = leftSon(curr)rightSonId = rightSon(curr)optId = currif leftSonId < size and better(heap[leftSonId], heap[optId]):optId = leftSonIdif rightSonId < size and better(heap[rightSonId], heap[optId]):optId = rightSonIdif curr != optId:heap[curr], heap[optId] = heap[optId], heap[curr]self.Heapify(heap, size, optId)def sortArray(self, nums: List[int]) -> List[int]:n = len(nums)for i in range(n // 2, -1, -1):self.Heapify(nums, n, i)for i in range(n-1, -1, -1):nums[0], nums[i] = nums[i], nums[0]self.Heapify(nums, i, 0)return nums

十、希尔排序

 ① 希尔排序

Ⅰ、初始化间隔(增量)

        首先计算初始间隔 gap,通常取数组长度的一半(gap = n // 2)。这个间隔决定了子序列的划分方式,后续会逐步缩小。

Ⅱ、分组与插入排序

        外层循环(间隔控制):当 gap > 0 时,执行循环体。每次循环结束后将间隔缩小一半(gap = gap // 2)。

        中层循环(遍历每个子序列):从 gap 开始遍历到数组末尾,每个元素 arr[i] 属于不同的子序列。

        内层循环(子序列插入排序):保存当前元素 arr[i] 到临时变量 temp。在当前子序列中(间隔为 gap),从后往前比较元素。如果前一个元素 arr[j - gap] 大于 temp,则将其向后移动 gap 个位置。重复上述比较和移动操作,直到找到正确的插入位置,然后将 temp 插入该位置。

Ⅲ、缩小间隔

        每次完成当前间隔的所有子序列排序后,将间隔缩小一半(例如,从 gap = 4 到 gap = 2,再到 gap = 1)。当间隔最终缩小到 1 时,整个数组被视为一个子序列,此时执行的就是标准的插入排序,但由于前面的分组排序已经使数组接近有序,插入排序的效率会更高。

Ⅳ、终止条件

        当间隔 gap 减小到 0 时,排序完成,返回排序后的数组。

② 排序数组 

        调用希尔排序函数,传入列表(数组)nums

class Solution:def shell_sort(self, arr):n = len(arr)gap = n // 2  # 初始间隔while gap > 0:# 对每个间隔分组进行插入排序for i in range(gap, n):# 保存当前元素,作为待插入的值temp = arr[i]j = i# 在间隔为gap的分组内,从后往前找到插入位置while j >= gap and arr[j - gap] > temp:arr[j] = arr[j - gap]  # 元素后移j -= gaparr[j] = temp  # 插入正确位置gap = gap // 2  # 缩小间隔return arrdef sortArray(self, nums: List[int]) -> List[int]:return self.shell_sort(nums)

 十一、十大排序算法对比

算法时间复杂度空间复杂度稳定性数据规模数据特性典型应用场景
选择排序O(n²)O(1)不稳定小规模任意顺序教学示例、简单场景(如嵌入式设备)
冒泡排序O(n²)O(1)稳定小规模近乎有序轻量级数据处理、教学演示
插入排序O(n²)O(1)稳定小规模近乎有序或少量元素链表排序、实时数据插入场景
计数排序O(n+k)O(n+k)稳定中等规模数值范围小(k 已知)整数排序(如高考分数统计)
归并排序O(n log n)O(n)稳定大规模任意顺序,需稳定性外排序、分布式系统(如 Hadoop)
快速排序O(n log n)O(log n)不稳定大规模任意顺序通用排序(如编程语言内置 sort 函数)
桶排序O(n + k)O(n+k)稳定大规模均匀分布、浮点数据海量数据排序(如日志分析)
基数排序O(d(n + k))O(n + k)稳定大规模多关键字、固定长度数据字符串排序(如姓名按拼音排序)
堆排序O(n log n)O(1)不稳定大规模任意顺序,需原地排序内存受限场景(如嵌入式系统)
希尔排序O(n log²n) - O(n²)O(1)不稳定中等规模中等逆序度数据库索引排序、文件系统排序

十二、各算法详解与应用场景 

1. 选择排序(Selection Sort)

  • 核心思想:每次从未排序部分选择最小值,与未排序部分的第一个元素交换。
  • 优点:实现简单,原地排序。
  • 缺点:时间复杂度高,不适用于大规模数据。
  • 应用场景
    • 教学场景或简单程序(如玩具项目)。
    • 内存严格受限且数据量极小(如几百个元素)。

2. 冒泡排序(Bubble Sort)

  • 核心思想:相邻元素两两比较,逆序时交换,将最大值逐步 “冒泡” 到末尾。
  • 优点:稳定排序,实现简单。
  • 缺点:平均效率低,仅适用于小规模数据。
  • 优化:引入标志位提前终止(如鸡尾酒排序)。
  • 应用场景
    • 教育演示(理解排序逻辑)。
    • 小规模、近乎有序的数据(如已排序数据的微小更新)。

3. 插入排序(Insertion Sort)

  • 核心思想:将元素逐个插入已排序部分的合适位置,类似打牌时整理手牌。
  • 优点:稳定排序,对近乎有序的数据效率高(O (n) 时间)。
  • 缺点:大规模逆序数据下效率低。
  • 变种:希尔排序(分组插入优化)。
  • 应用场景
    • 链表排序(无需随机访问,插入操作高效)。
    • 实时数据处理(如传感器数据逐个插入排序)。

4. 计数排序(Counting Sort)

  • 核心思想:统计每个值的出现次数,按顺序重建数组。
  • 前提:数据范围有限(k 已知),通常为非负整数。
  • 优点:线性时间复杂度,稳定排序。
  • 缺点:空间复杂度高(需额外数组存储计数)。
  • 应用场景
    • 整数排序(如 100 以内的学生成绩排序)。
    • 数据压缩前的预处理(如统计字符频率)。

5. 归并排序(Merge Sort)

  • 核心思想:分治策略,递归分割数组,合并时排序。
  • 优点:稳定排序,时间复杂度稳定为 O (n log n)。
  • 缺点:需要 O (n) 额外空间(无法原地排序)。
  • 变种:自然归并排序(利用已排序子序列)。
  • 应用场景
    • 外排序(处理无法一次性加载到内存的数据)。
    • 需要稳定性的场景(如排序含有相同键的记录)。

6. 快速排序(Quick Sort)

  • 核心思想:分治策略,选择枢轴元素,将数组划分为两部分递归排序。
  • 优点:平均时间复杂度低,原地排序(空间复杂度 O (log n))。
  • 缺点:最坏情况 O (n²)(可通过随机枢轴或三数取中法优化)。
  • 应用场景
    • 通用排序(如 Python 的sorted()、C++ 的std::sort)。
    • 大规模数据排序(如数据库查询结果排序)。

7. 桶排序(Bucket Sort)

  • 核心思想:将数据分配到有限数量的桶中,每个桶内单独排序,再合并结果。
  • 前提:数据分布均匀,桶的数量合理。
  • 优点:线性时间复杂度(若桶内排序为 O (1))。
  • 缺点:对非均匀分布数据效率低。
  • 应用场景
    • 浮点数据排序(如 [0,1) 区间的随机数)。
    • 海量数据并行处理(如 MapReduce 中的排序阶段)。

8. 基数排序(Radix Sort)

  • 核心思想:按数字的每一位(如个位、十位)依次排序,从最低位到最高位。
  • 前提:数据有固定长度(如字符串、固定位数的整数)。
  • 优点:稳定排序,适用于多关键字排序。
  • 缺点:依赖数据进制(通常为 10 进制或 256 进制)。
  • 应用场景
    • 字符串排序(如按字典序排序姓名)。
    • 整数排序(如身份证号码、邮政编码)。

9. 堆排序(Heap Sort)

  • 核心思想:利用最大堆或最小堆,每次将堆顶元素与末尾交换,调整堆结构。
  • 优点:原地排序(O (1) 空间),时间复杂度稳定为 O (n log n)。
  • 缺点:不稳定排序,缓存性能较差(非连续访问数组)。
  • 应用场景
    • 内存受限环境(如嵌入式设备、实时系统)。
    • 需要在线处理数据(如动态维护 Top-K 元素)。

10. 希尔排序(Shell Sort)

  • 核心思想:分组插入排序,增量序列逐步缩小至 1,最终用插入排序收尾。
  • 优点:比插入排序更快,适用于中等规模数据。
  • 缺点:时间复杂度依赖增量序列,稳定性差。
  • 优化:使用 Sedgewick 序列或 Hibbard 序列提升效率。
  • 应用场景
    • 中等规模数组(如几千到几万元素)。
    • 数据库索引排序(如 B + 树节点内部排序)。

十三、各大排序算法的决策指南

1.数据规模

小规模(n<1000):选择插入排序、冒泡排序或选择排序(实现简单)。

大规模(n≥1000):优先快速排序、归并排序或堆排序。

2.数据特性

近乎有序:插入排序或冒泡排序(优化后效率高)。

整数 / 字符串:计数排序、基数排序(利用数据特性降维复杂度)。

分布均匀:桶排序(线性时间复杂度)。

3.稳定性需求

需要稳定排序:归并排序、基数排序、冒泡排序。

无需稳定排序:快速排序、堆排序、希尔排序。

4.空间限制

内存紧张:堆排序(O (1) 空间)、希尔排序(O (1) 空间)。

空间充足:归并排序(O (n) 空间)、计数排序(O (n+k) 空间)。

5.特殊场景

实时数据:插入排序(动态插入)。

并行处理:桶排序(可分布式实现)。

外存数据:归并排序(分块处理)。

十大排序算法各有优劣,实际应用中需根据数据规模、特性、稳定性要求及环境限制综合选择。例如:

        日常编程首选快速排序(高效、通用)。

        嵌入式系统优先堆排序(省内存)。

        教学或简单场景使用插入 / 冒泡排序(易理解)。

        大数据场景考虑桶排序、基数排序或分布式归并排序。

相关文章:

  • 浏览器工作原理01 [#]Chrome架构:仅仅打开了1个页面,为什么有4个进程
  • 汽车的安全性能测试:试验台铁地板的重要性
  • Unity3D仿星露谷物语开发60之定制角色其他部位
  • 【题解-洛谷】P3370 【模板】字符串哈希
  • Docker + Nginx + Logrotate 日志管理与轮换实践
  • YUM仓库编译出现`conflicting requests`问题解决方案
  • Linux系统安装Docker
  • Python 构建法律DeepSeek RAG
  • YOLO训练保持原有识别能力
  • Spring 团队详解:AOT 缓存实践、JSpecify 空指针安全与支持策略升级
  • 宝塔think PHP8 安装使用FFmpeg 视频上传
  • 数据结构之常用排序算法(冒泡、选择等)
  • 以STM32H7微控制器为例,简要说明stm32h7xx_it.c的作用
  • 主流 AI IDE 之一的 Cursor 介绍
  • mysql+keepalived
  • C#中的CLR属性、依赖属性与附加属性
  • 《零基础读懂新能源汽车》—— 新能源汽车充电革命:从逆变器原理到800V超充实战,一篇全掌握!
  • Python训练营打卡Day46(2025.6.6)
  • 【React】React 18 并发特性
  • 我爱学算法之—— 前缀和(中)
  • 城乡与住房建设厅网站/网络推广方式方法
  • 网站建设的整体流程/百度快速收录提交工具
  • 宁波网站推广外包服务/百度seo白皮书
  • 营销网站建设流程/奶茶店推广软文500字
  • 网站的360度全景图片怎么做/热点事件
  • 做一个网站的计划书/潍坊做网站公司