首页 物联网

算法工程师必知:七大排序算法原理与实战避坑

分类:物联网
字数: (0817)
阅读: (2386)
内容摘要:算法工程师必知:七大排序算法原理与实战避坑,

在日常的后端开发中,我们经常会遇到各种各样的排序需求。例如,在电商系统中,我们需要根据商品的价格、销量、评价等指标对商品进行排序;在新闻资讯系统中,我们需要根据新闻的发布时间、点击量等指标对新闻进行排序。本文将深入剖析 七大排序算法的基本原理,并结合实际案例,分享一些实战中的避坑经验。

冒泡排序(Bubble Sort)

原理

冒泡排序是最简单直观的排序算法之一。它重复地遍历要排序的列表,比较每对相邻的元素,如果它们的顺序错误就交换它们。重复进行直到不再需要交换,也就是说该列表已经排序完成。之所以叫做冒泡排序,是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

代码示例(Python)

def bubble_sort(arr):
 n = len(arr)
 for i in range(n):
 for j in range(0, n-i-1):
 if arr[j] > arr[j+1] :
 arr[j], arr[j+1] = arr[j+1], arr[j]
 return arr

arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bubble_sort(arr)
print(sorted_arr) # Output: [11, 12, 22, 25, 34, 64, 90]

避坑经验

冒泡排序的时间复杂度为 O(n^2),在数据量较大时效率较低。在实际项目中,应避免使用冒泡排序来处理大规模数据。

选择排序(Selection Sort)

原理

选择排序是一种简单直观的排序算法。它的工作原理是首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

算法工程师必知:七大排序算法原理与实战避坑

代码示例(Java)

public class SelectionSort {
 public static void selectionSort(int[] arr) {
 int n = arr.length;
 for (int i = 0; i < n - 1; i++) {
 int min_idx = i;
 for (int j = i + 1; j < n; j++) {
 if (arr[j] < arr[min_idx]) {
 min_idx = j;
 }
 }
 int temp = arr[min_idx];
 arr[min_idx] = arr[i];
 arr[i] = temp;
 }
 }

 public static void main(String[] args) {
 int[] arr = {64, 34, 25, 12, 22, 11, 90};
 selectionSort(arr);
 for (int i = 0; i < arr.length; i++) {
 System.out.print(arr[i] + " "); // Output: 11 12 22 25 34 64 90 
 }
 }
}

避坑经验

选择排序的时间复杂度也为 O(n^2),性能不如其他一些高级排序算法。虽然它比冒泡排序在某些情况下稍快,但仍然不适合处理大规模数据。

插入排序(Insertion Sort)

原理

插入排序的工作方式是构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

代码示例(C++)

#include <iostream>
#include <vector>

void insertionSort(std::vector<int>& arr) {
 int n = arr.size();
 for (int i = 1; i < n; i++) {
 int key = arr[i];
 int j = i - 1;
 while (j >= 0 && arr[j] > key) {
 arr[j + 1] = arr[j];
 j = j - 1;
 }
 arr[j + 1] = key;
 }
}

int main() {
 std::vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
 insertionSort(arr);
 for (int i = 0; i < arr.size(); i++) {
 std::cout << arr[i] << " "; // Output: 11 12 22 25 34 64 90 
 }
 std::cout << std::endl;
 return 0;
}

避坑经验

插入排序在数据基本有序的情况下,性能表现很好,时间复杂度接近 O(n)。但是,在数据完全无序的情况下,时间复杂度仍然是 O(n^2)。

算法工程师必知:七大排序算法原理与实战避坑

归并排序(Merge Sort)

原理

归并排序是一种分而治之的算法。它将原始数组分解为更小的子数组,直到每个子数组只包含一个元素。然后,它将这些子数组以排序的方式合并,直到得到完整的排序数组。

代码示例 (JavaScript)

function mergeSort(arr) {
 if (arr.length <= 1) {
 return arr;
 }

 const middle = Math.floor(arr.length / 2);
 const left = arr.slice(0, middle);
 const right = arr.slice(middle);

 return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
 let result = [];
 let leftIndex = 0;
 let rightIndex = 0;

 while (leftIndex < left.length && rightIndex < right.length) {
 if (left[leftIndex] < right[rightIndex]) {
 result.push(left[leftIndex]);
 leftIndex++;
 } else {
 result.push(right[rightIndex]);
 rightIndex++;
 }
 }

 return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}

const arr = [64, 34, 25, 12, 22, 11, 90];
const sortedArr = mergeSort(arr);
console.log(sortedArr); // Output: [11, 12, 22, 25, 34, 64, 90]

避坑经验

归并排序的时间复杂度为 O(n log n),是一种稳定的排序算法。但是,归并排序需要额外的空间来存储临时数组,空间复杂度为 O(n)。如果对内存占用有严格要求,需要慎重考虑。

快速排序(Quick Sort)

原理

快速排序也是一种分而治之的算法。它选择一个“基准”元素,将数组划分为两个子数组:小于基准的元素和大于基准的元素。然后,递归地对这两个子数组进行排序。

算法工程师必知:七大排序算法原理与实战避坑

代码示例 (Go)

package main

import "fmt"

func quickSort(arr []int) []int {
 if len(arr) < 2 {
 return arr
 }

 pivot := arr[0]
 var less []int
 var greater []int

 for _, x := range arr[1:] {
 if x <= pivot {
 less = append(less, x)
 } else {
 greater = append(greater, x)
 }
 }

 less = quickSort(less)
 greater = quickSort(greater)

 return append(append(less, pivot), greater...)
}

func main() {
 arr := []int{64, 34, 25, 12, 22, 11, 90}
 sortedArr := quickSort(arr)
 fmt.Println(sortedArr) // Output: [11 12 22 25 34 64 90]
}

避坑经验

快速排序的平均时间复杂度为 O(n log n),但在最坏情况下(例如,数组已经排序),时间复杂度会退化为 O(n^2)。为了避免最坏情况,通常采用随机选择基准元素的方法。此外,快速排序是一种不稳定的排序算法。

堆排序(Heap Sort)

原理

堆排序是利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

代码示例 (PHP)

<?php
function heapSort(array &$arr)
{
 $n = count($arr);

 // Build max heap
 for ($i = floor($n / 2) - 1; $i >= 0; $i--) {
 heapify($arr, $n, $i);
 }

 // One by one extract an element from heap
 for ($i = $n - 1; $i > 0; $i--) {
 // Move current root to end
 $temp = $arr[0];
 $arr[0] = $arr[$i];
 $arr[$i] = $temp;

 // call max heapify on the reduced heap
 heapify($arr, $i, 0);
 }
}

function heapify(array &$arr, int $n, int $i)
{
 $largest = $i; // Initialize largest as root
 $left = 2 * $i + 1;
 $right = 2 * $i + 2;

 // If left child is larger than root
 if ($left < $n && $arr[$left] > $arr[$largest]) {
 $largest = $left;
 }

 // If right child is larger than largest so far
 if ($right < $n && $arr[$right] > $arr[$largest]) {
 $largest = $right;
 }

 // If largest is not root
 if ($largest != $i) {
 $temp = $arr[$i];
 $arr[$i] = $arr[$largest];
 $arr[$largest] = $temp;

 // Recursively heapify the affected sub-tree
 heapify($arr, $n, $largest);
 }
}

$arr = array(64, 34, 25, 12, 22, 11, 90);
heapSort($arr);
print_r($arr); // Output: Array ( [0] => 11 [1] => 12 [2] => 22 [3] => 25 [4] => 34 [5] => 64 [6] => 90 )

?>

避坑经验

堆排序的时间复杂度为 O(n log n),是一种稳定的排序算法。堆排序的空间复杂度为 O(1)。

算法工程师必知:七大排序算法原理与实战避坑

计数排序(Counting Sort)

原理

计数排序是一种非基于比较的排序算法。它通过统计数组中每个元素出现的次数,然后根据元素的出现次数,将元素放到正确的位置上。计数排序适用于已知数据范围且范围较小的情况。

代码示例 (C#)

using System;
using System.Linq;

public class CountingSort
{
 public static int[] countingSort(int[] arr)
 {
 int maxVal = arr.Max();
 int minVal = arr.Min();
 int range = maxVal - minVal + 1;

 int[] count = new int[range];
 int[] output = new int[arr.Length];

 for (int i = 0; i < arr.Length; i++)
 {
 count[arr[i] - minVal]++;
 }

 for (int i = 1; i < range; i++)
 {
 count[i] += count[i - 1];
 }

 for (int i = arr.Length - 1; i >= 0; i--)
 {
 output[count[arr[i] - minVal] - 1] = arr[i];
 count[arr[i] - minVal]--;
 }

 return output;
 }

 public static void Main(string[] args)
 {
 int[] arr = { 64, 34, 25, 12, 22, 11, 90 };
 int[] sortedArr = countingSort(arr);
 Console.WriteLine(string.Join(", ", sortedArr)); // Output: 11, 12, 22, 25, 34, 64, 90
 }
}

避坑经验

计数排序的时间复杂度为 O(n+k),其中 k 是数据的范围。如果数据的范围很大,则计数排序的空间复杂度也会很高。计数排序只适用于整数排序,不能用于浮点数或字符串排序。在实际项目部署时,例如使用 Jenkins 自动部署,需要考虑服务器的内存资源限制,避免因内存溢出导致部署失败。可以使用宝塔面板等工具监控服务器资源。

总结

本文详细介绍了七大排序算法的基本原理、代码实现以及实战避坑经验。在实际应用中,我们需要根据具体的需求和数据特点,选择合适的排序算法。例如,如果数据量较小,可以选择插入排序或选择排序;如果数据量较大,可以选择归并排序或快速排序;如果数据范围已知且较小,可以选择计数排序。此外,还需要考虑到排序算法的稳定性、空间复杂度等因素。例如,在电商系统中,我们需要根据商品的价格进行排序,如果价格相同,则需要按照商品的发布时间进行排序,这时就需要选择一种稳定的排序算法。在选择排序算法时,还需要考虑到服务器的 CPU 和内存资源限制。例如,在高并发的场景下,需要选择一种时间复杂度较低的排序算法,以避免因排序算法的性能瓶颈导致服务器响应时间过长。同时,可以使用 Nginx 进行反向代理和负载均衡,提高系统的并发连接数和吞吐量。

算法工程师必知:七大排序算法原理与实战避坑

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea4.store/blog/575276.SHTML

本文最后 发布于2026-04-21 18:06:03,已经过了6天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 草莓味少女 1 天前
    堆排序的实现原理还是有点难理解,有没有更形象的比喻?
  • 拖延症晚期 3 天前
    快速排序那块,随机选择基准元素确实很重要,之前没注意,踩了不少坑。
  • 佛系青年 19 小时前
    感谢大佬分享,代码示例很实用,正好最近在用Go写排序算法,可以参考一下。