C++ 七大排序算法完整讲解

前置说明

分类

  1. 简单排序:冒泡、选择、插入
  2. 进阶插入:希尔排序
  3. 分治排序:快速、归并
  4. 堆排序:基于堆

核心概念

  • 稳定排序:相等元素相对顺序不变(冒泡、插入、归并)
  • 不稳定:选择、希尔、快排、堆排

1. 冒泡排序 BubbleSort

原理

相邻元素两两比较,逆序则交换;每一轮把最大值 "浮" 到末尾。优化:标记本轮是否交换,无交换直接退出(有序提前终止)。

复制代码
#include <iostream>
#include <vector>
using namespace std;

void BubbleSort(vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n - 1; ++i) {
        bool swapped = false;
        // 每轮末尾i个已排好,不用比较
        for (int j = 0; j < n - 1 - i; ++j) {
            if (arr[j] > arr[j+1]) {
                swap(arr[j], arr[j+1]);
                swapped = true;
            }
        }
        if (!swapped) break; // 全程无交换,已有序
    }
}

// 测试
int main() {
    vector<int> a = {3,1,4,1,5,9,2,6};
    BubbleSort(a);
    for (int x : a) cout << x << " ";
    return 0;
}

时间复杂度:

  • 最好(完全有序):O(n),一次遍历无交换直接退出
  • 平均 / 最坏(完全逆序):O(n2)

2. 选择排序 SelectSort

原理

有序区无序区;每轮遍历无序区找到最小值,和无序区首元素交换。

复制代码
void selectSort(vector<int>& arr)
{
	int n = arr.size();
	for (int i = 0; i < n - 1; i++)
	{ 
		int min=i;
		for (int j = i; j < n; j++)
		{
			
			if (arr[j] < arr[min])
			{
				min = j;
				
			}
		}
		swap(arr[min], arr[i]);
} 

时间复杂度

无论有序 / 无序,最好 / 平均 / 最坏全是 O(n2);全程必须完整遍历找最小值。


3. 插入排序 InsertSort

原理

左侧是有序数组,依次取右侧元素向前插入到合适位置

复制代码
void insertSort(vector<int> &arr)
{
	int n = arr.size();
	for (int i = 1; i < n; i++)
	{
		int tmp = arr[i];
		int j;
		for (j = i - 1; j >= 0; j--)
		{
			if (arr[j] > tmp)
			{
				arr[j + 1] = arr[j];
			}
			else
				break;
		}
		arr[j+1] = tmp;
	}
}

时间复杂度

  • 最好(完全有序):O(n),仅比较不移动;
  • 平均 / 最坏(逆序):O(n2)。

4. 希尔排序 ShellSort(插入排序优化)

希尔排序是插入排序的优化版本

原理

分组插入排序,设置间隔 gap,每组单独插入排序;不断缩小 gap 至 1,退化为普通插入。

复制代码
void shellSort(vector<int>& arr) {
	int n = arr.size();
	for (int gap = n / 2; gap > 0; gap /= 2)
	{
		for (int i = gap; i < n; i++)
		{
			int tmp = arr[i];
			int j;
			for (j = i - gap; j >= 0; j-=gap)
			{
				if (arr[j] > tmp)
					arr[j + gap] = arr[j];
				else
					break;
			}
			arr[j+gap] = tmp;
		}
	}
}

时间复杂度

  • 最好:O(n);
  • 平均:O(n1.3)(二分增量序列);
  • 最坏:O(n2)。

5. 快速排序 QuickSort

快排详解(这里面讲解了快排的几种实现方法):

https://blog.csdn.net/w8848w/article/details/147365474?fromshare=blogdetail&sharetype=blogdetail&sharerId=147365474&sharerefer=PC&sharesource=w8848w&sharefrom=from_link

原理:分治

  1. 选基准 pivot
  2. 分区:小于 pivot 放左,大于放右
  3. 递归排序左右子区间

挖坑法:

复制代码
 void QS(vector<int>& arr, int left, int right)
{
	 if (left > right)
		 return;
	 int key = arr[left];
	 int begin = left, end = right;

	 while (left < right)
	 {
		 while (left < right && arr[right]>=key)
		 {
			 right--;
		 }
		 arr[left] = arr[right];
		 while (left < right &&arr[left]<=key)
		 {
			 left++;
		 }
		 arr[right] = arr[left];
	 }
	 arr[left] = key;
	 QS(arr,begin, left - 1);
	 QS(arr, left + 1, end);
}
 void QuickSort(vector<int> &arr)
 {
	 QS(arr, 0, arr.size() - 1);
 }

时间复杂度

  • 最好 / 平均(基准平分区间):O(nlogn);
  • 最坏(有序 / 逆序,基准取端点):O(n2)。

随机基准优化

复制代码
int partition_rand(vector<int>& arr, int l, int r) {
    int randIdx = l + rand() % (r - l + 1);
    swap(arr[randIdx], arr[r]);
    return partition(arr, l, r);
}

6. 归并排序 MergeSort(稳定 O (nlogn))

原理:分治

  1. 二分拆分数组直到单个元素
  2. 有序合并两个子数组,需要辅助数组

C++ 完整代码

复制代码
void _MergeSort(vector<int>& arr,vector<int> &vec,int left,int right)
{
	if (right == left)
		return;
	int mid = (left + right) / 2;
	_MergeSort(arr, vec, left, mid);
	_MergeSort(arr, vec, mid + 1, right);

	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;

	int i=left;
    //将两段有序序列归并成一段
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] <= arr[begin2])		
			vec[i++] = arr[begin1++];
		else
			vec[i++] = arr[begin2++];
	}
    //将剩下的数组添加到新数组尾部
	while (begin1 <= end1)
	{
		vec[i++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		vec[i++] = arr[begin2++];
	}
    //拷贝
	for (int i = left; i <=right; i++)
	{
		arr[i] = vec[i];
	}
}

void MergeSort(vector<int> &arr)
{
	int n = arr.size();
	vector<int> vec(n);
	_MergeSort(arr,vec,0,n-1);
	
}

时间复杂度

最好 / 平均 / 最坏稳定 O(nlogn),无退化风险


7. 堆排序 HeapSort

原理

数组模拟完全二叉树构建大顶堆;堆顶为最大值,交换到数组末尾缩小堆,反复下沉调整堆。

  • 父 i → 左孩子 2*i+1,右 2*i+2
  • 孩子 i → 父 (i-1)/2

C++ 代码

复制代码
// 下沉调整大顶堆
void heapify(vector<int>& arr, int n, int i) {
    int largest = i;
    int left = 2*i + 1;
    int right = 2*i + 2;
    if (left < n && arr[left] > arr[largest])
        largest = left;
    if (right < n && arr[right] > arr[largest])
        largest = right;
    if (largest != i) {
        swap(arr[i], arr[largest]);
        heapify(arr, n, largest);
    }
}

void HeapSort(vector<int>& arr) {
    int n = arr.size();
    // 1. 建大顶堆:从最后一个父节点向前遍历
    for (int i = n/2 - 1; i >= 0; --i)
        heapify(arr, n, i);
    // 2. 堆顶放末尾,调整堆
    for (int i = n - 1; i > 0; --i) {
        swap(arr[0], arr[i]);
        heapify(arr, i, 0);
    }
}

时间复杂度

最好 / 平均 / 最坏全部稳定 O(nlogn)

相关推荐
CodeStats2 小时前
《源纹天书》第一百六十一章至第一百六十五章:开源化宣言、元定义的力量、栈帧重构、容器道场升级、技术债的化身!
java·源纹天书
不良手残2 小时前
MyBatisPlus代码自动生成器
java
SamDeepThinking2 小时前
一次线程池线上故障复盘:四层防线如何避免数据丢失
java·后端·程序员
得物技术2 小时前
得物推荐系统诊断 Agent:从 “调接口” 到 “会思考”|AICon 演讲整理
人工智能·算法·架构
花生智源2 小时前
Java实现Prompt工程的技巧——从模板到工程化,告别字符串拼接
java·人工智能
Lugas2 小时前
为啥说男生找对象尽量在25岁前找到?
算法
MrZhao4002 小时前
从能跑到可用:一个 Agent Harness 还差哪些工程闭环?
算法
折哥的程序人生 · 物流技术专研2 小时前
Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
java·策略模式·java面试·comparator·模版方法模式·java设计模式·从踩坑到精通
库克克2 小时前
【C++】类和对象--this指针详解
java·开发语言·c++