【C++】C++学习(模板+排序+测时)

news2024/11/19 20:33:36

本文主要记录使用模板函数来编写排序算法,并计算运行时间。

模板函数(Template Function)是一种通用函数,可以在其定义时不指定具体的参数类型,在调用时再根据需要指定具体类型。模板函数可以接受不同类型的参数,并产生可重用性强的代码。

使用模板函数的主要目的是为了提高代码的复用性和灵活性,特别是当需要编写的函数在不同的参数类型下都要执行相同的操作时。通过模板函数可以避免重复编写相似的代码,使程序更加简洁简单易于维护

  • 选择排序
    • 选择排序是不稳定的排序,因为其在排序过程中,会改变原本元素的相对位置
    • 时间复杂度:O(n²)
    • 空间复杂度:O(1)
  • 冒泡排序
    • 冒泡排序是稳定的排序,因为每次排序都是相邻两个元素比较排序,不会改变相等元素的相对位置
    • 时间复杂度:O(n²)
    • 空间复杂度:O(1)
  • 快速排序
    • 快速排序是不稳定的排序
    • 时间复杂度:O(nlogn)
    • 空间复杂度:O(1) 因为采用递归,占用了栈空间

  1. 定义了一个交换函数
  2. 定义了一个打印函数
  3. 定义了一个选择排序函数
// 模板函数格式
template <typename T>
xxx函数,如
void fun(T a, T b)
{
    xxx
}
// 调用(例如整型)
fun<int>(a,b);
#include <iostream>
using namespace std;

template <typename T>
void my_swap(T &a, T &b) // 交换
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

template <typename T>
void print(T arr[], int len) // 打印函数
{
	cout << "排序结果: ";
	for (int i = 0; i < len; i++) {
		cout <<  arr[i] << " ";
	}
	cout << endl;
}

template <typename T>
void select_sort(T arr[], int len) //选择排序
{
	for (int i = 0; i < len; i++) {
		int max_index = i;
		for (int j = i + 1; j < len; j++) {
			if (arr[max_index] < arr[j]) {
				max_index = j;
			}
		}
		if (max_index != i) {
			my_swap<T>(arr[max_index], arr[i]);
		}
	}
	print<T>(arr, len);
}

当我们使用不同数据类型时,就会发现模板函数的好处多多~

int main()
{
    int a[5]{ 1,2,3,4,5 };
	int len_a = sizeof(a) / sizeof(int);
    select_sort<int>(a, len_a);
    return 0;
}

int main()
{
	double b[5]{ 1.1,2.2,3.3,4.4,5.5 };
	int len_b = sizeof(b) / sizeof(double);
	select_sort<double>(b, len_b);
    return 0;
}

int main()
{
	char c[] = "abcde";
	int len_c = sizeof(c) / sizeof(char);
	select_sort<char>(c, len_c);
    return 0;
}

接下来,我们来测试下,冒泡排序,以及稍微改进的冒泡排序的运行时间

template <typename T>
void bubble_sort(T arr[], int len) //冒泡排序
{
	for (int i = 0; i < len; i++) {
		for (int j = i + 1; j < len; j++) {
			if (arr[i] < arr[j]) {
				my_swap<T>(arr[i], arr[j]);
			}
		}
	}
	print<T>(arr, len);
}

template <typename T>
void bubble_p_sort(T arr[], int len) //冒泡排序(优化)
{
	for (int i = 0; i < len; i++) {
		bool flag = false;
		for (int j = i + 1; j < len; j++) {
			if (arr[i] < arr[j]) {
				my_swap<T>(arr[i], arr[j]);
				flag = true;
			}
		}
		if (!flag) break;
	}
	print<T>(arr, len);
}
#include <iostream>
#include <chrono> // 测时
#include <random> // 生成随机数
using namespace std;

int main()
{
    // 创建随机数引擎
	std::random_device rd;
	std::mt19937 gen(rd()); // 使用 Mersenne Twister 引擎
	// 创建分布对象
	std::uniform_int_distribution<int> dist(0, 100);//0-100

    int a[100];
	for (int i = 0; i < 100; i++) // 生成100个随机数
	{
		a[i] = dist(gen);// 生成随机整数
	}

    int len = sizeof(a) / sizeof(a[0]);
    
    auto start1 = std::chrono::high_resolution_clock::now(); // 开始计时
	bubble_sort(a, len); // 冒泡排序
	auto end1 = std::chrono::high_resolution_clock::now(); // 结束计时
	auto t1 = std::chrono::duration_cast<std::chrono::duration<double>> (end1 - start1).count() * 1000;

	std::cout << "冒泡排序代码运行时间: " << t1 << " 毫秒" << std::endl;

    auto start2 = std::chrono::high_resolution_clock::now(); // 开始计时
	bubble_p_sort(a, len); // 冒泡排序(优化)
	auto end2 = std::chrono::high_resolution_clock::now(); // 结束计时
	auto t2 = std::chrono::duration_cast<std::chrono::duration<double>> (end2 - start2).count() * 1000;

	std::cout << "冒泡排序(优化)代码运行时间: " << t2 << " 毫秒" << std::endl;

    return 0;
}

我们可以发现,在时间上还是稍微加快一丢丢,原因是当输入数组已经有序时,会提前结束排序。

使用快速排序

// 从小到大排序
template <typename T>
int Partition(T a[], int low, int high)
{
	T base = a[low]; // 把左边的值作为基准值
	while (low < high) {
		while (low < high && a[high] >= base) high--; // 如果大于base,则向左平移,找小的数
		a[low] = a[high]; // 把小的数放到左侧
		while (low < high && a[low] <= base) low++; // 如果小于base,则向右平移,找大的数
		a[high] = a[low]; // 把大的数放到右侧
	}
	a[low] = base;
	return low;
}
template <typename T>
void qsort(T a[], int low, int high)
{
	if (low < high) {
		int pos = Partition<T>(a, low, high);
		qsort(a, low, pos - 1);
		qsort(a, pos + 1, high);
	}
}
#include <iostream>
#include <chrono>
#include <random>
using namespace std;


int main()
{
    // 创建随机数引擎
	std::random_device rd;
	std::mt19937 gen(rd()); // 使用 Mersenne Twister 引擎
	// 创建分布对象
	std::uniform_int_distribution<int> dist(0, 100);//0-100

	int a[100];
	for (int i = 0; i < 100; i++) // 生成100个随机数
	{
		a[i] = dist(gen);// 生成随机整数
	}
	int n = 100;
	auto start1 = std::chrono::high_resolution_clock::now(); // 开始计时
	qsort<int>(a, 0, n - 1);
	auto end1 = std::chrono::high_resolution_clock::now();
	auto t1 = std::chrono::duration_cast<std::chrono::duration<double>> (end1 - start1).count() * 1000;
	print(a, n);
	std::cout << "快速排序代码运行时间: " << t1 << " 毫秒" << std::endl;

    return 0;
}

// 从大到小排序
template <typename T>
int Partition(T a[], int low, int high)
{
	T base = a[low]; // 把左边的值作为基准值
	while (low < high) {
		while (low < high && a[high] <= base) high--; 
		a[low] = a[high]; // 把大的数放到左侧
		while (low < high && a[low] >= base) low++; 
		a[high] = a[low]; // 把小的数放到右侧
	}
	a[low] = base;

	return low;
}
template <typename T>
void qsort(T a[], int low, int high)
{
	if (low < high) {
		int pos = Partition<T>(a, low, high);
		qsort(a, low, pos - 1);
		qsort(a, pos + 1, high);
	}
}
#include <iostream>
#include <chrono>
#include <random>
using namespace std;


int main()
{
    // 创建随机数引擎
	std::random_device rd;
	std::mt19937 gen(rd()); // 使用 Mersenne Twister 引擎
	// 创建分布对象
	std::uniform_int_distribution<int> dist(0, 100);//0-100

	int a[100];
	for (int i = 0; i < 100; i++) // 生成100个随机数
	{
		a[i] = dist(gen);// 生成随机整数
	}
	int n = 100;
	auto start1 = std::chrono::high_resolution_clock::now(); // 开始计时
	qsort<int>(a, 0, n - 1);
	auto end1 = std::chrono::high_resolution_clock::now();
	auto t1 = std::chrono::duration_cast<std::chrono::duration<double>> (end1 - start1).count() * 1000;
	print(a, n);
	std::cout << "快速排序代码运行时间: " << t1 << " 毫秒" << std::endl;

    return 0;
}

快速排序名不虚传,确实挺快的!同样100个随机数,冒泡排序选择排序都要10多毫秒,快速排序只需要0.005毫秒左右!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1112337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

057:mapboxGL中layout,paint等属性的函数表达说明

第057个 点击查看专栏目录 本篇文章是mapbox的layer中layout,paint等属性的函数表达 mapbox中 Function 是什么 函数 Function 可以作为其 layout布局类属性和 paint 绘制类属性的属性值。在使用 Function 作为属性值时,实际上是一个对象。 layers的3种函数类型 Function …

error: unable to read askpass response from

报错信息 解决方法&#xff1a; 中文&#xff1a;文件-->设置-->版本控制-->Git-->勾选使用凭证帮助程序 英文&#xff1a;File -> Settings -> Version Control -> Git / Check "User credential Helper" 因为我的webstrom是中文版的&#…

Simulink 最基础教程(四)模型参数与全局变量

4.1模型参数 上面介绍常用模块的时候&#xff0c;都是找到模块&#xff0c;双击模块&#xff0c;设置参数。这些参数都是模块参数。与之相对的&#xff0c;是模型参数。一些说明&#xff1a; 1&#xff09;模型参数和模块参数并不是隶属关系&#xff0c;而是配合关系。当模型参…

起重机控制电路接线 - 基础与进阶(修订中...)

1.基础篇 起重机电气接线 - 理论与实践 - 知乎1.现场配电箱这是一台10吨电动葫芦的电器箱。你能看出这个起重机用到了几个电机吗&#xff1f;先看空开和继电器。 电机为了控制正反转&#xff0c;一般每个电机需要用到两个继电器。这上面有7个继电器&#xff0c;所以&#xff0…

数字图像处理实验记录四(图像的空间域增强-平滑处理)

前言&#xff1a;要是是实验报告赶工的话&#xff0c;建议总结上网抄&#xff0c;或者重构我的总结&#xff0c;仅供学习参考&#xff0c;不要照抄 文章目录 一、基础知识1&#xff0c;噪声2&#xff0c;椒盐噪声3&#xff0c;高斯噪声4&#xff0c;滤波器5&#xff0c;均值滤…

[云原生1.] Docker容器的简单介绍和基本管理

1. Docker容器的基本概述 1.1 简介 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级…

Unity之ShaderGraph如何实现无贴图水球效果

前言 我们今天来实现一个无贴图水球效果&#xff0c;如下图所示&#xff1a; 主要节点 UVSplit&#xff1a;可以获得UV在RGB三个颜色分别的分量 Remap&#xff1a;重映射节点 基于输入 In 值在输入In Min Max的 x 和 y 分量之间的线性插值&#xff0c;返回输入Out Min Max…

爬虫三大库

Requests库安装 Requests库的作用是请求网站获得网页数据 在pycharm中安装方式如下&#xff1a; 选择settings 选择Project Interpreter&#xff0c;单击号添加第三方库 BeautifulSoup库按同样方式安装。 Requests库 pycharm返回结果为<Response [200]>,说明请求网址成…

简单秒表设计仿真verilog跑表,源码/视频

名称&#xff1a;简单秒表设计仿真 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 秒表显示最低计时为10ms&#xff0c;最大为59:99&#xff0c;超出返回00&#xff1a;00 具有复位、启动、暂停三个按键 四个数码管分别显示4个时间数字。 演示…

了解 Elasticsearch 自动生成的文档 _id:重复是一个问题吗?

Elasticsearch 中自动生成的文档 ID 当你在未指定 ID 的情况下对文档建立索引时&#xff0c;Elasticsearch 会自动为该文档生成唯一的 ID。 该 ID 是 Base64 编码的 UUID&#xff0c;由多个部分组成&#xff0c;每个部分都有特定的用途。 ID 生成过程针对索引速度和存储效率进…

互联网Java工程师面试题·Java 总结篇·第九弹

目录 75、阐述 JDBC 操作数据库的步骤。 76、Statement 和 PreparedStatement 有什么区别&#xff1f;哪个性 能更好&#xff1f; 77、使用 JDBC 操作数据库时&#xff0c;如何提升读取数据的性能&#xff1f;如何提升更新数据的性能&#xff1f; 78、在进行数据库编程时&a…

git 查看本地秘钥

第一步&#xff1a; 1&#xff0c;打开终端或者命令行窗口&#xff0c;输入一下命令&#xff1a; cd ~/.ssh进入ssh目录 2&#xff0c;查看该目录下的所有文件&#xff0c;输入以下命令: ls -al该命令将显示ssh目录下的所有文件&#xff0c;包括秘钥文件和配置文件,如果不存…

100天掌握网络安全知识点!

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

C++ Primer 第十一章 关联容器 重点解读

1 map自定义排序 #include <map> #include <iostream> #include <functional> using namespace std; int main() {function<bool(pair<int, int>, pair<int, int>)> cmp [&](pair<int, int> p1, pair<int, int> p2) -&g…

设计模式-综合应用(一)

介绍 使用jQuery做一个模拟购物车的示例 用到的设计模式 工厂模式 单例模式装饰器模式 观察者模式状态模式 模板方法模式 代理模式 UML类图

leetcode - 319. Bulb Switcher

Description There are n bulbs that are initially off. You first turn on all the bulbs, then you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on). For the ith round, you toggl…

Apollo的搭建

Apollo的搭建 1.环境准备 jdk : 1.8 mysql 5.6.5 2.下载 两种方式&#xff1a; a.下载源码自己编译&#xff08;需要修改源码的可以选择&#xff09; 源码&#xff1a;https://github.com/ctripcorp/apoll b.编译好的直接使用 地址&#xff1a;Releases apol…

人人开源前后端分离开源项目启动流程(超详细)

renren-security是一个轻量级的&#xff0c;前后端分离的Java快速开发平台&#xff0c;能快速开发项目并交付【接私活利器】采用SpringBoot、Shiro、MyBatis-Plus、Vue3、TypeScript、Element Plus、Vue Router、Pinia、Axios、Vite框架&#xff0c;开发的一套权限系统&#xf…

Vue2基础知识(一) 认识Vue

&#x1f48c; 所属专栏&#xff1a;【Vue2】&#x1f600; 作 者&#xff1a;长安不及十里&#x1f4bb;工作&#xff1a;目前从事电力行业开发&#x1f308;目标&#xff1a;全栈开发&#x1f680; 个人简介&#xff1a;一个正在努力学技术的Java工程师&#xff0c;专注基础和…

原创!—混合灰狼层次结构的自适应麻雀搜索算法GWHASSA

麻雀搜索算法&#xff08;SSA&#xff09;是薛建凯等人[1]提出的一种群体智能优化算法,是受麻雀觅食和躲避捕食者行为启发而设计出的算法。该算法于2020年首次提出&#xff0c;具有局部搜索能力强、调整参数少等特点&#xff0c;已成功应用于CT图像的现场检测、电池堆参数的优化…