【C++】 排序算法合集 && 单元测试

这篇具有很好参考价值的文章主要介绍了【C++】 排序算法合集 && 单元测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

排序算法是《数据结构与算法》中最基本的算法之一。

十种常见排序算法可以分为两大类:

  • 比较类排序:通过比较来决定元素间的相对次序,时间复杂度为 O(nlogn)~O(n²)。
  • 非比较类排序:不通过比较来决定元素间的相对次序,其时间复杂度可以突破 O(nlogn),以线性时间运行。

【十大经典排序算法分类】 ​

【十大经典排序算法的复杂度分析】 ​

名词解释:

  • 时间/空间复杂度:描述一个算法执行时间/占用空间与数据规模的增长关系。
  • n:待排序列的个数。
  • k:“桶”的个数(上面的三种非比较类排序都是基于“桶”的思想实现的)。
  • In-place:原地算法,指的是占用常量内存,不占用额外内存。即空间复杂度为 O(1) 。
  • Out-place:非原地算法,占用额外内存。
  • 稳定性:假设待排序列中两元素相等,排序前后这两个相等元素的相对位置不变,则认为是稳定的。


一、排序算法代码合集 & 测试用例

        对前面分享的十种排序算法做单元测试。

1.1、博客地址

  • 冒泡排序 & 选择排序:【C++】十大排序算法之 冒泡排序 & 选择排序-CSDN博客
  • 插入排序 & 希尔排序:【C++】十大排序算法之 插入排序 & 希尔排序-CSDN博客
  • 归并排序 & 快速排序:【C++】十大排序算法之 归并排序 & 快速排序-CSDN博客
  • 堆排序  & 计数排序:【C++】十大排序算法之 堆排序 & 计数排序-CSDN博客
  • 桶排序  & 基数排序:【C++】十大排序算法之 桶排序 & 基数排序-CSDN博客

1.2、 C++排序算法代码合集

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file SortAlgorithm.hpp
* @brief 排序算法合集
* @autor 写代码的小恐龙er
* @date 2024/03/07
*/
// =================================================================
// ==========================十大排序算法===========================
// =================================================================
// 
// 
// 【冒泡排序】 -- 时间复杂度 O(n2) , 空间复杂度 O(1)
void BubbleSort(int arr[], int n) 
{
	// 设定一个交换标志 以提前结束排序
	bool isChange = false;

	// 最多做n - 1趟排序
	// 外循环为 趟数 
	for (int i = 0; i < n - 1; i++) {
		isChange = false;
		// 内循环为 针对后面的序列做冒泡排序
		for (int j = 0; j < n - i - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
				// 对交换标志位置位
				isChange = true;
			}
		}
		// 如果某一趟的排序未发生交换 则说明已经排序完成 无需后续排序
		if (!isChange) return;
	}
}

// 【选择排序】 -- 时间复杂度 O(n2) , 空间复杂度 O(1)
void SelectSort(int* arr, int n)
{
	// 存放最小元素的下标
	int minIndex = 0;
	// 存放每一次循环的起始位置的原始值(因为起始位置需要被最小元素替换)
	int temp = 0;

	// 排序 n - 1 次
	for (int i = 0; i < n - 1; i++) {
		minIndex = i;
		for (int j = i + 1; j < n; j++) {
			if (arr[j] < arr[minIndex]) minIndex = j;
		}

		// 将每一轮的最小值放置在循环起点
		if (minIndex != i) {
			temp = arr[minIndex];
			arr[minIndex] = arr[i];
			arr[i] = temp;
		}
	}
}

// 【插入排序】 -- 时间复杂度 O(n2) , 空间复杂度 O(1)
void InsertSort(int arr[], int n)
{
	int i = 0;
	int j = 0;
	int temp = 0;

	for (i = 1; i < n; i++) {
		temp = arr[i];

		//挪出位置
		for (j = i; j > 0 && arr[j - 1] > temp; j--) {
			arr[j] = arr[j - 1];
		}

		// 插入
		arr[j] = temp;

	}
}

// 【希尔排序】 -- 时间复杂度 O(n * logn) , 空间复杂度 O(1)
void ShellSort(int* arr, int size)
{
	int i, j, tmp, increment;
	// 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
	// 按增量序列个数 k,对序列进行 k 趟排序;
	for (increment = size / 2; increment > 0; increment /= 2) {
		// 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。 
		// 仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
		for (i = increment; i < size; i++){
			tmp = arr[i];
			// 直接插入排序
			for (j = i - increment; j >= 0 && tmp < arr[j]; j -= increment) {
				arr[j + increment] = arr[j];
			}
			// 插入
			arr[j + increment] = tmp;
		}
	}
}

// 【归并排序】 -- 时间复杂度 O(n * logn) , 空间复杂度 O(n)
// 【分治法】&【递归法】
void Merge(int arr[], int l, int m, int r)
{
	// 将arr数组左右两个 有序序列合并在一起;
	int size = r - l + 1;
	vector<int> newArr(size, 0);

	// k代表新数组的下标
	int i = l, j = m + 1, k = 0;

	while (i <= m && j <= r) newArr[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
	while (i <= m) newArr[k++] = arr[i++];
	while (j <= r) newArr[k++] = arr[j++];


	// 重新赋值
	k = 0;
	for (i = l; i <= r; i++) {
		arr[i] = newArr[k++];
	}
}
// 递归
void MergeSort(int arr[], int l, int r)
{
	// 终止条件
	if (l >= r) return;

	// 中间节点
	int m = (l + r) / 2;
	// 分别递归进行子序列排列
	MergeSort(arr, l, m);
	MergeSort(arr, m + 1, r);
	// 最后将两个子序列合并在一块
	Merge(arr, l, m, r);

}

// 【快速排序】 -- 时间复杂度 O(n * logn) , 空间复杂度 O(logn) 
// 【分治法】&【递归法】
void QuickSort(int arr[], int begin, int end)
{
	// 终止条件
	if (begin > end) return;

	//基准数
	int pivot = arr[begin];
	int i = begin;
	int j = end;

	while (i != j) {
		// 从右向左 找比基准数小的数
		while (arr[j] >= pivot && i < j) j--;
		// 再从左向右找 比基准数 大的数
		while (arr[i] <= pivot && i < j) i++;
		if (i < j) {
			// 交换两个数在数组中的位置
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}

	// 最终将基准数归位 -- 将基准数 放置在 中间
	arr[begin] = arr[i];
	arr[i] = pivot;

	// 递归左右两侧的序列
	QuickSort(arr, begin, i - 1);
	QuickSort(arr, i + 1, end);

}

// 【堆排序】 -- 时间复杂度 O(n * logn) , 空间复杂度 O(1)
//void Swap(int arr[], int i, int j) {
//	int temp = arr[i];
//	arr[i] = arr[j];
//	arr[j] = temp;
//}
//void Heapify(int tree[], int n, int i) {
//	// n 表示序列长度,i 表示父节点下标
//	if (i >= n) return;
//	// 左侧子节点下标
//	int left = 2 * i + 1;
//	// 右侧子节点下标
//	int right = 2 * i + 2;
//	int max = i;
//	if (left < n && tree[left] > tree[max]) max = left;
//	if (right < n && tree[right] > tree[max]) max = right;
//	if (max != i) {
//		Swap(tree, max, i);
//		Heapify(tree, n, max);
//	}
//}
//void BuildHeap(int tree[], int n) {
//	// 树最后一个节点的下标
//	int last_node = n - 1;
//	// 最后一个节点对应的父节点下标
//	int parent = (last_node - 1) / 2;
//	int i;
//	for (i = parent; i >= 0; i--) {
//		Heapify(tree, n, i);
//	}
//}
//void HeapSort(int tree[], int n) 
//{
//	// 第一次建立大顶堆,从后向前依次调整
//	BuildHeap(tree, n);
//	// 每次将根和待排序的最后一次交换,然后再调整
//	int i;
//	for (i = n - 1; i >= 0; i--) {
//		// 将堆顶元素与最后一个元素交换
//		Swap(tree, i, 0);
//		// 调整成大顶堆
//		Heapify(tree, i, 0);
//	}
//}

// 【堆排序】 -- 时间复杂度 O(n * logn) , 空间复杂度 O(1)
void HeapAdjust(int* arr, int start, int end)
{
	int tmp = arr[start];
	for (int i = 2 * start + 1; i <= end; i = i * 2 + 1)
	{
		//有右孩子并且左孩子小于右孩子
		if (i < end && arr[i] < arr[i + 1]){
			i++;
		}//i一定是左右孩子的最大值
		if (arr[i] > tmp)
		{
			arr[start] = arr[i];
			start = i;
		}
		else break;
	}
	arr[start] = tmp;
}
void HeapSort(int* arr, int len)
{
	//第一次建立大根堆,从后往前依次调整
	for (int i = (len - 1 - 1) / 2; i >= 0; i--){
		HeapAdjust(arr, i, len - 1);
	}
	//每次将根和待排序的最后一次交换,然后在调整
	int tmp;
	for (int i = 0; i < len - 1; i++){
		tmp = arr[0];
		arr[0] = arr[len - 1 - i];
		arr[len - 1 - i] = tmp;
		HeapAdjust(arr, 0, len - 1 - i - 1);
	}
}


// 【计数排序】 -- 时间复杂度 O(n + k) , 空间复杂度 O(k)
void CountingSort(int arr[], int n) 
{
	if (arr == NULL) return;
	// 寻找最值元素
	int max = arr[0], min = arr[0];
	int i;
	for (i = 1; i < n; i++) {
		if (max < arr[i]) max = arr[i];
		if (min > arr[i]) min = arr[i];
	}
	int r = max - min + 1;
	// 定义辅助空间并初始化
	vector<int> C(r, 0);

	// 统计每个元素出现的次数
	for (i = 0; i < n; i++) C[arr[i] - min]++;

	i = 0;
	for (int j = 0; j < r; j++) {
		while (C[j]--) {
			arr[i++] = j + min;
		}
	}
}
// 【计数排序- 重载】 -- 时间复杂度 O(n + k) , 空间复杂度 O(k)
void CountingSort(vector<int> arr, int n)
{
	if (n == 0) return;
	// 寻找最值元素
	int max = arr[0], min = arr[0];
	int i;
	for (i = 1; i < n; i++) {
		if (max < arr[i]) max = arr[i];
		if (min > arr[i]) min = arr[i];
	}
	int r = max - min + 1;
	// 定义辅助空间并初始化
	vector<int> C(r, 0);

	// 统计每个元素出现的次数
	for (i = 0; i < n; i++) C[arr[i] - min]++;

	i = 0;
	for (int j = 0; j < r; j++) {
		while (C[j]--) {
			arr[i++] = j + min;
		}
	}
}

// 【桶排序】 -- 时间复杂度 O(n + k) , 空间复杂度 O(n + k)
void BucketSort(int arr[], int n, int r) 
{
	if (arr == NULL || r < 1) return;

	// 根据最大/最小元素和桶数量,计算出每个桶对应的元素范围
	int max = arr[0], min = arr[0];
	int i, j;
	for (i = 1; i < n; i++) {
		if (max < arr[i]) max = arr[i];
		if (min > arr[i]) min = arr[i];
	}
	int range = (max - min + 1) / r++;

	// 建立桶对应的二维数组,一个桶里最多可能出现 n 个元素
	vector<vector <int>> buckets(r, vector <int>(n, 0));
	vector <int> counts(n, 0);

	for (i = 0; i < n; i++) {
		int k = (arr[i] - min) / range;
		buckets[k][counts[k]++] = arr[i];
	}

	int index = 0;
	for (i = 0; i < r; i++) {
		// 分别对每个非空桶内数据进行排序,比如计数排序
		if (counts[i] == 0) continue;
		sort(buckets[i].begin(), buckets[i].begin() + counts[i]);
		// CountingSort(buckets[i], counts[i]);
		// 拼接非空的桶内数据,得到最终的结果
		for (j = 0; j < counts[i]; j++) {
			arr[index++] = buckets[i][j];
		}
	}
}

// 基数
#define RADIX 10

// 【基数排序】 -- 时间复杂度 O(n * k) , 空间复杂度 O(n + k)
void RadixSort(int arr[], int n) 
{
	// 获取最大值和最小值
	int max = arr[0], min = arr[0];
	int i, j, l;
	for (i = 1; i < n; i++) {
		if (max < arr[i]) max = arr[i];
		if (min > arr[i]) min = arr[i];
	}
	// 假如序列中有负数,所有数加上一个常数,使序列中所有值变成正数
	if (min < 0) {
		for (i = 0; i < n; i++) arr[i] -= min;
		max -= min;
	}
	// 获取最大值位数
	int d = 0;
	while (max > 0) {
		max /= 10;
		d++;
	}
	vector<vector <int>> queue(RADIX, vector <int>(n, 0));
	int count[RADIX] = { 0 };
	for (i = 0; i < d; i++) {
		// 分配数据
		for (j = 0; j < n; j++) {
			// 依次 从 个位 到最高位 取出 数值
			int key = arr[j] % (int)pow(RADIX, i + 1) / (int)pow(RADIX, i);
			// 放置到 对应 位数的数组中   count[key]++ 是为了记录 位数相同的  值 共有多少个
			queue[key][count[key]++] = arr[j];
		}
		// 收集数据
		int c = 0;
		// 依次将各个基数中的数据排列起来
		for (j = 0; j < RADIX; j++) {
			for (l = 0; l < count[j]; l++) {
				arr[c++] = queue[j][l];
				queue[j][l] = 0;
			}
			count[j] = 0;
		}
	}
	// 假如序列中有负数,收集排序结果时再减去前面加上的常数
	if (min < 0) {
		for (i = 0; i < n; i++) arr[i] += min;
	}
}

1.3 、C++测试代码

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file SortTest.hpp
* @brief 排序算法测试用例
* @autor 写代码的小恐龙er
* @date 2024/03/07
*/

// 头文件
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <memory>

void SortTest() 
{
	// 数组中的元素个数
	int n = 10;
	// 起始下标
	int begin = 0;
	// 终止下标
	int end = 9;
	int l = 0;
	int r = 9;

	// ============ 冒泡排序 =============
	int arr1[10] = {2,5,8,4,0,6,1,3,7,9};
	BubbleSort(arr1, n);
	printf("冒泡排序后为:");
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}
	std::cout << endl;

	// ============选择排序 =============
	int arr2[10] = { 2,5,8,4,0,6,1,3,7,9 };
	SelectSort(arr2, n);
	printf("选择排序后为:");
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%d ", arr2[i]);
	}
	std::cout << endl;

	// ============ 插入排序 =============
	int arr3[10] = { 2,5,8,4,0,6,1,3,7,9 };
	InsertSort(arr3, n);
	printf("插入排序后为:");
	for (int i = 0; i < sizeof(arr3) / sizeof(arr3[0]); i++)
	{
		printf("%d ", arr3[i]);
	}
	std::cout << endl;

	// ============ 希尔排序 =============
	int arr4[10] = { 2,5,8,4,0,6,1,3,7,9 };
	ShellSort(arr4, n);
	printf("希尔排序后为:");
	for (int i = 0; i < sizeof(arr4) / sizeof(arr4[0]); i++)
	{
		printf("%d ", arr4[i]);
	}
	std::cout << endl;

	// ============ 归并排序 =============
	int arr5[10] = { 2,5,8,4,0,6,1,3,7,9 };
	MergeSort(arr5, l, r);
	printf("归并排序后为:");
	for (int i = 0; i < sizeof(arr5) / sizeof(arr5[0]); i++)
	{
		printf("%d ", arr5[i]);
	}
	std::cout << endl;

	// ============ 快速排序 =============
	int arr6[10] = { 2,5,8,4,0,6,1,3,7,9 };
	QuickSort(arr6, begin, end);
	printf("快速排序后为:");
	for (int i = 0; i < sizeof(arr6) / sizeof(arr6[0]); i++)
	{
		printf("%d ", arr6[i]);
	}
	std::cout << endl;

	// ============ 堆排序 =============
	int arr7[10] = { 2,5,8,4,0,6,1,3,7,9 };
	HeapSort(arr7, n);
	printf("堆排序后为  :");
	for (int i = 0; i < sizeof(arr7) / sizeof(arr7[0]); i++)
	{
		printf("%d ", arr7[i]);
	}
	std::cout << endl;

	// ============ 计数排序 =============
	int arr8[10] = { 2,5,8,4,0,6,1,3,7,9 };
	CountingSort(arr8, n);
	printf("计数排序后为:");
	for (int i = 0; i < sizeof(arr8) / sizeof(arr8[0]); i++)
	{
		printf("%d ", arr8[i]);
	}
	std::cout << endl;

	// ============ 桶排序 =============
	int arr9[10] = { 2,5,8,4,0,6,1,3,7,9 };
	BucketSort(arr9, n, 3);
	printf("桶排序后为  :");
	for (int i = 0; i < sizeof(arr9) / sizeof(arr9[0]); i++)
	{
		printf("%d ", arr9[i]);
	}
	std::cout << endl;

	// ============ 基数排序 =============
	int arr10[10] = { 2,5,8,4,0,6,1,3,7,9 };
	RadixSort(arr10, n);
	printf("基数排序后为:");
	for (int i = 0; i < sizeof(arr10) / sizeof(arr10[0]); i++)
	{
		printf("%d ", arr10[i]);
	}
	std::cout << endl;
}

using namespace std;

int main()
{
	cout << "-----------------------------------------------" << endl;
	cout << "单元测试用例 : " << endl;
	cout << "-----------------------------------------------" << endl;

    // 排序算法的单元测试
    SortTest();
	cout << "-----------------------------------------------" << endl;

	system("pause");
	return 0;
}

1.4 、输出结果

【C++】 排序算法合集 && 单元测试,排序算法,c++,单元测试



 -- 排序算法结束。文章来源地址https://www.toymoban.com/news/detail-840053.html

到了这里,关于【C++】 排序算法合集 && 单元测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++单元测试Gtest+Stub攻略

    笔者环境为linux环境(deepin),以下均在此环境进行 Gtest源码链接 Stub源码链接 StubExt源码链接 Stub的使用方法在cpp-stub/README_zh.md中有讲解 StubExt的使用方法在 cpp-stub-ext/ README.md中有讲解 StubExt可支持Lambda表达式进行打桩写Gtest时如果想获取一个固定的返回值或者出参十分好用 搭建环

    2024年02月10日
    浏览(34)
  • C++常见排序算法——冒泡排序算法

    首先说一下冒泡排序的基本算法思想: 它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸

    2023年04月08日
    浏览(27)
  • 一文掌握谷歌 C++ 单元测试框架 GoogleTest

    GoogleTest GoogleTest(简称 GTest) 是 Google 开源的一个跨平台的(Liunx、Mac OS X、Windows等)的 C++ 单元测试框架,可以帮助程序员测试 C++ 程序的结果预期。不仅如此,它还提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。 GoogleTest 官网:https://google.github.io/go

    2024年02月03日
    浏览(29)
  • C++类对象单元测试中的Mock使用

      在进行单元测试时,我们想要测试自己缩写 函数A ,但是 函数A 却依赖于 函数B ,当 函数B 无法满足预期时就无法对 函数A 进行测试,主要由于下面几个原因: 函数B 依赖于硬件设备 真实的 函数B 的返回值无法满足我们的预期 团队开发中 函数B 尚未实现   这时就需要

    2023年04月15日
    浏览(29)
  • C++中的断言机制与gtest单元测试

       这部分内容网上已经有很多人讲了,我就不做重复性工作,制造垃圾了,大家看看下面两个链接就可以了,因为我的专栏除了分享自己学习的知识,主要想为大家提供完整学习路线,让大家的知识体系更加完善! (1)参考:https://www.cnblogs.com/lvchaoshun/p/7816288.html (1)参考:

    2023年04月08日
    浏览(88)
  • 一个简单好用的C++语言单元测试框架-GoogleTest

    GoogleTest 是由 Google 开发的一个用于编写 C++ 单元测试的框架。单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在实际项目中,单元测试往往由开发人员完成。

    2024年01月19日
    浏览(80)
  • C++排序算法:归并排序详解

    一、归并排序 二、基本算法         1、分离         2、合并         3、图片讲解 三、代码实现         1、分离函数         2、合并函数          3、完整代码          4、样例 四、总结          归并排序 (Merge Sort)是建立在归并操作上的一种既有效又稳

    2024年02月12日
    浏览(33)
  • 【C C++开源库】适合单片机 嵌入式的C语言单元测试库_单片机 单元测试框架

    #define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((thres

    2024年04月25日
    浏览(35)
  • 【教程】在 Visual Studio 2015 上对 C++ 进行单元测试

    更新中 本文的测试环境是 Visual Studio 2015,高级别版本(如,2017,2022)的操作略有不同,但提供了更强大的测试功能,这两种版本 IDE 下的测试方式,可以阅读官方文档 os:win10 IDE:Visual Studio 2015 Test Explorer:可视化的测试辅助工具,可以在这个工具里查看测试的结果,它取

    2024年02月09日
    浏览(33)
  • [C++] 基础教程 - 如何使用google test进行单元测试

    https://download.csdn.net/download/u011775793/88601877 单元测试是一种软件测试方法,用于测试代码中的最小可测试单元。在软件开发中,我们通常将代码分解为多个模块或类,每个模块或类都有自己的功能和行为。单元测试的目的是确保每个模块或类都能正常工作,不会影响其他模块或

    2024年02月04日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包