关于我、重生到500年前凭借C语言改变世界科技vlog.14——常见C语言算法
文章目录
- 1.冒泡排序
- 2.二分查找
- 3.转移表
- 希望读者们多多三连支持
- 小编会继续更新
- 你们的鼓励就是我前进的动力!
根据当前所学C语言知识,对前面知识进行及时的总结巩固,出了这么一篇 vlog 介绍当前所学知识能遇到的常见算法,这些算法是在C数据结构初阶常用的一些算法,重要性不言而喻,本章将用简单易懂的语言带领读者深入理解
1.冒泡排序
冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地走访要排序的数列,一次比较两个数据元素,如果顺序不对则进行交换,并一直重复这样的走访操作,直到没有要交换的数据元素为止
核心思想:两两元素进行比较交换
基本原理
1.比较相邻的元素,如果第一个比第二个大(假设是按照升序排序,若为降序则相反),就交换它们两个
2.对每一对相邻元素作同样的操作,从开始第一对到结尾的最后一对,这样在经过第一轮比较后,最大的元素就会 “浮” 到数列的末尾
3.针对所有的元素重复以上的步骤,除了最后已经排好序的元素(因为每一轮都会把当前未排序部分的最大元素移到最后,所以每轮结束后末尾的元素数量会增加,这些元素就不需要再参与后续排序了)
4.持续重复上述过程,直到整个数列都按照要求的顺序排列好
理论知识介绍完,举个例子或许你就完全明白了
假设我们有一个数组 [5, 4, 3, 2, 1] 要进行升序排序:
第一轮排序
1.比较第 1 个元素 5 和第 2 个元素 4,因为 5 > 4,所以交换它们,数组变为 [4, 5, 3, 2, 1]
2.接着比较第 2 个元素 5 和第 3 个元素 3,因为 5 > 3,交换后数组变为 [4, 3, 5, 2, 1]
3.再比较第 3 个元素 5 和第 4 个元素 2,交换得到 [4, 3, 2, 5, 1]
4.最后比较第 4 个元素 5 和第 5 个元素 1,交换后数组变为 [4, 3, 2, 1, 5]。此时第一轮排序结束,最大的元素 5 已经 “浮” 到了数组的末尾
第二轮排序
1.对除了最后一个元素 5 之外的数组部分 [4, 3, 2, 1] 进行同样操作
2.先比较第 1 个元素 4 和第 2 个元素 3,交换得 [3, 4, 2, 1]
3.再比较第 4 个元素 4 和第 3 个元素 2,交换得 [3, 2, 4, 1]
4.最后比较第 3 个元素 4 和第 4 个元素 1,交换得 [3, 2, 1, 4]。第二轮排序结束,此时未排序部分的最大元素 4 也 “浮” 到了合适位置
…以此类推
可以发现每次都将最大的那个数送到最右边,假设有 n 个数,那么需要运送的趟数就为 (n-1)
每一轮,每两个数都要进行比较,已经被运送到最右边的就不需要比较
那么需要比较 (n-1-已经运送到右边的数的个数)
所以交换的函数可以这么写
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{int i = 0;for(i=0; i<sz-1; i++){int j = 0;for(j=0; j<sz-i-1; j++){if(arr[j] > arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}}int main()
{int arr[] = {3,1,7,5,8,9,0,2,4,6};int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr, sz);int i = 0;for(i=0; i<sz; i++){printf("%d ", arr[i]);}return 0;
}
这里简单说明一下时间复杂度的概念,这里只需要理解概念即可,如何计算到了C数据结构会讲解
1.时间复杂度是用来衡量算法运行时间随着输入规模增长而增长的趋势的一个重要指标
2. 时间复杂度通常用大 O 表示法来表示,大 O 表示法描述的是算法在最坏情况下的时间复杂度,也就是当输入对算法运行造成最大困难时的运行时间增长趋势
对于该冒泡排序
最坏情况:当输入的数组是完全逆序时,第一轮需要比较 n-1 次,第二轮需要比较 n-2 次,以此类推,总共需要比较的次数为 (n-1)+(n-2)+…+1,这个和等于 n (n-1)/2,所以需要进行 n(n-1)/2 次比较和交换操作,所以时间复杂度为 O(n^2),其中 n 是数组的元素个数
最好情况:当输入的数组已经是有序的,只需要进行一轮比较(每个元素都和它相邻的元素比较一次),此时时间复杂度为 O(n)
假设有多个序列需要排列,所以为了提高效率,对最好情况进行快速排序,对代码可进行如下优化
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{int i = 0;for(i=0; i<sz-1; i++){int flag = 1;//假设这⼀趟已经有序了int j = 0;for(j=0; j<sz-i-1; j++){if(arr[j] > arr[j+1]){flag = 0;//发⽣交换就说明,⽆序int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}if(falg == 1)//这⼀趟没交换就说明已经有序,后续⽆序排序了break;}}int main()
{int arr[] = {3,1,7,5,8,9,0,2,4,6};int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr, sz);int i = 0;for(i=0; i<sz; i++){printf("%d ", arr[i]);}return 0;
}
冒泡排序虽然简单易懂,但由于其时间复杂度较高,在处理大规模数据排序时效率相对较低,通常会被更高效的排序算法如快速排序、归并排序等所替代,但在一些数据量较小且对排序效率要求不是特别高的场景下,仍然可以使用冒泡排序
2.二分查找
二分查找(Binary Search),也叫折半查找,是一种用于在有序数组(或其他有序数据结构)中快速查找特定元素的高效查找算法
核心思想:不断对半查找
基本原理
1.每次查找时都将待查找的区间分成两部分
2.然后根据要查找元素与中间元素的比较结果,确定下一次查找应该在左半部分还是右半部分继续进行
3.如此反复,直到找到目标元素或者确定目标元素不存在为止
还是通过举例来说明,假设我们有一个有序数组 [1, 3, 5, 7, 9, 11, 13, 15],要查找元素 7
首先,确定整个数组为待查找区间,计算中间元素的索引,对于长度为 n 的数组,中间元素索引 mid 计算公式为:mid = (left + right) / 2(这里 left 表示区间的左端点,right 表示区间的右端点,在初始时 left = 0,right = n - 1)。在这个例子中,n = 8,所以 mid = (0 + 7) / 2 = 3,中间元素就是 7
然后,将目标元素 7 与中间元素 7 进行比较,发现它们相等,这就找到了目标元素,查找过程结束
再假设要查找元素 4
1.同样先确定整个数组为待查找区间,计算中间元素索引 mid = (0 + 7) / 2 = 3,中间元素是 7
2.将目标元素 4 与中间元素 7 进行比较,因为 4 < 7,所以目标元素如果存在,一定在左半部分。此时更新待查找区间为左半部分,即 left = 0,right = mid - 1 = 2
3.再次计算新的中间元素索引 mid = (0 + 2) / 2 = 1,新的中间元素是 3
将目标元素 4 与新的中间元素 3 进行比较,因为 4 > 3,所以目标元素如果存在,一定在右半部分,更新待查找区间为右半部分,即 left = mid + 1 = 2,right = 2
4.第三次计算中间元素索引 mid = (2 + 2) / 2 = 2,中间元素是 5
5.将目标元素 4 与中间元素 5 进行比较,因为 4 < 5,所以目标元素如果存在,一定在左半部分,更新待查找区间为左半部分,即 left = 2,right = mid - 1 = 1,此时 left > right,说明目标元素在这个有序数组中不存在,查找过程结束
可以发现每次折中查找,然后和目标元素比较,以此往复完成二分查找
对于二分查找
二分查找每次查找都会将搜索范围缩小一半,最多需要查找的次数为以 2 为底,n(数组元素个数)的对数次
即 log 2^n ,所以二分查找的时间复杂度为 O(log n),这使得它在处理较大规模的有序数组时,查找速度比顺序查找(时间复杂度为 O(n))快得多
例如,当数组有 1024 个元素时,二分查找最多只需要查找 10 次(因为 )就可以确定目标元素是否存在
如果是顺序查找就要找 1024 次,往往查找的数目还不止这么多,甚至更加庞大
int binary_search(int arr[], int n, int target)
{int left = 0;int right = n - 1;while (left <= right){// 计算中间元素的索引int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid;} else if (arr[mid] > target) {right = mid - 1;} else{left = mid + 1;}}return -1;
}int main()
{int arr[] = {1, 3, 5, 7, 9, 11, 13, 15};int n = sizeof(arr) / sizeof(arr[0]);int target = 7;int result = binary_search(arr, n, target);if (result!= -1) {printf("目标元素 %d 在数组中的索引为 %d\n", target, result);} else {printf("目标元素 %d 在数组中不存在\n", target);}return 0;
}
二分查找是一种非常高效的查找算法,但它的前提是数组必须是有序的。如果数组未排序,则需要先对数组进行排序,再使用二分查找
3.转移表
转移表是一种数据结构和编程技巧,用于实现根据不同的条件或输入值快速跳转到相应的代码段执行
例如:写一个简单的计算器程序,它可以执行加、减、乘、除四种运算。你可以创建一个转移表,表中包含四个元素,分别对应四种运算的处理函数的指针,当用户输入一个运算符号后,程序可以根据这个符号在转移表中快速找到对应的处理函数并执行,而不需要使用一长串的 if-else 或 switch 语句来逐个判断运算符号并调用相应函数
根据前面所学的 switch 结构和 加法函数,可以写出一个简易的四则运算计算器
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}
但是这种写法过于重复啰嗦,可以运用函数数组指针来简化代码
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = {0, add, sub, mul, div };//转移表do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf( "输⼊操作数:" );scanf( "%d %d", &x, &y);ret = (*p[input])(x, y);printf( "ret = %d\n", ret);}else if(input == 0){printf("退出计算器\n");}else{printf( "输⼊有误\n" ); }}while (input);return 0;
}
这样就通过函数指针数组实现了根据不同的索引值灵活调用不同函数的功能,这在很多需要根据条件或情况动态选择执行不同函数的场景中非常有用
如果还有不懂可以私信博主或回顾往期 vlog 查缺补漏
主页传送门:DARLING Zero two♡ 的 blog
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!

相关文章:
关于我、重生到500年前凭借C语言改变世界科技vlog.14——常见C语言算法
文章目录 1.冒泡排序2.二分查找3.转移表希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 根据当前所学C语言知识,对前面知识进行及时的总结巩固,出了这么一篇 vlog 介绍当前所学知识能遇到的常见算法,这些算法是…...
简记Vue3(三)—— ref、props、生命周期、hooks
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
ARM cpu算力KDMIPS测试
一、引言 KDMIPS(KiloDhrystone Million Instructions Per Second)是一种衡量处理器性能的指标,它表示处理器每秒钟可以执行多少百万条Dhrystone指令。 二、测试说明 1、将cpu模式调整为perfermance 2、将cpu的频率和gpu的频率调大最大 3、将ddr和各core的电压和频率调大最…...
自杀一句话木马(访问后自动删除)
在做安全测试时,例如文件上传时就要上传可以解析的脚本文件解析证明存在漏洞,这个时候就需要(访问后自动删除文件的一句话木马) PHP <?php echo md5(1);unlink(__FILE__); ?> 访问后自动删除...
Nginx 反向代理(解决跨域)
文章目录 前言一、同源策略二、跨域是什么?三、Nginx解决跨域1.前端示例代码2.说明 四、nginx反向代理配置五、启动nginx六、最终效果总结 前言 Nginx反向代理解决跨域 一、同源策略 定义:同源策略(Same-Origin Policy)是指浏览…...
gRPC-4种通信模式
4种通信模式 1、简单模式(Simple RPC) 简单模式:也称简单 RPC,即客户端发起一次请求,服务端响应处理后返回一个结果给客户端。 在 proto 文件中可如下定义: rpc SayHello(HelloRequest) returns (Hello…...
第五项修炼—系统思考
感谢合作伙伴的推荐,圆满结束为期两天的马上消费《第五项修炼—系统思考》项目!这不仅是一次培训,更是未来实践的起点。 两天的系统思考学习让我们看到,在技术管理的每个决策背后,都蕴含着深刻的系统关联。希望各位技…...
PYNQ 框架 - VDMA驱动 - 帧缓存
目录 1. 简介 2. 代码分析 2.1 _FrameCache 类定义 2.1.1 xlnk.cma_array() 2.1.2 pointerNone 2.1.3 PynqBuffer 2.2 _FrameCache 例化与调用 2.3 _FrameCache 测试 2.4 _FrameList 类定义 2.5 _FrameList 例化与调用 2.6 _FrameList 测试 3. 帧的使用 3.1 读取帧…...
Java导出Word文档的几种方法
文章目录 1. 使用 Apache POI2. 使用 Docx4j3. 使用 JODConverter4. 使用 FreeMarker 模板 在 Java 中导出 Word 文档可以通过多种库和方法实现。以下是几种常用的方法: 1. 使用 Apache POI Apache POI 是一个强大的库,可以用来读写 Microsoft Office 格…...
OceanBase V4.3.3,首个面向实时分析场景的GA版本发布
在10月23日举办的 OceanBase年度发布会 上,我们怀着激动之情,正式向大家宣布了 OceanBase 4.3.3 GA 版的正式发布,这也是OceanBase 为实时分析(AP)场景打造的首个GA版本。 2024 年初,我们推出了 4.3.0 版本…...
Maven随笔
文章目录 1、什么是MAVEN2、Maven模型3、Maven仓库4、项目集成1_Idea集成Maven设置2_创建Maven项目3_POM配置详解4_maven 坐标详情5_Maven工程类型6_导入Maven项目 5、依赖管理1_依赖配置2_依赖传递3_可选依赖4_排除依赖4_可选依赖和排除依赖的区别5_依赖范围6_继承与聚合7_版本…...
牛客题目解析
一.最长回文子串 1.题目:给定一个仅包含小写字母的字符串,求它的最长回文子串的长度。 最长回文子串__牛客网 2.算法原理: <1>动态规划算法:O(n^2),O(n^2) 具有通性,凡涉及回文子串的问题都可利用此法解决 知识储备&am…...
AG32的3个ADC可以并联使用吗
AG32的3个ADC可以并联使用吗? Customer: 需求: 在t1时间段,用5M的速度ch1通道采样得到结果1. 在t2时间段,用5M的速度ch2通道采样得到结果2. 在t3时间段,用5M的速度ch3通道采样得到结果3. 然后如此循环 。 考虑用3…...
什么是 OpenTelemetry?
OpenTelemetry 定义 OpenTelemetry (OTel) 是一个开源可观测性框架,允许开发团队以单一、统一的格式生成、处理和传输遥测数据(telemetry data)。它由云原生计算基金会 (CNCF) 开发,旨在提供标准化协议和工具,用于收集…...
[vulnhub]DC:7
https://www.vulnhub.com/entry/dc-7,356/ 端口扫描主机发现 探测存活主机,178是靶机 nmap -sP 192.168.75.0/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-03 13:30 CST Nmap scan report for 192.168.75.1 Host is up (0.00037s l…...
个性化十足的贵族服务器,惠普ML310e Gen8,服务器中的 “潘多拉魔盒”
个性化十足的贵族服务器,惠普ML310e Gen8,服务器中的 “潘多拉魔盒” 小伙伴们大家好呀,这里是勤奋的凯尔森同学,今天给大家分享一款好玩的服务器,惠普ML310e Gen8 V2,相比大家都很熟悉HP ProLiant MicroS…...
百度社招内推
百度社招内推 「百度内推」快来投递你心仪的职位吧( 网申链接地址:https://dwz.cn/ah4OUcca),填入内推码,完成投递,get内推绿色通道~我的内推码:IZ9PVH 内推有什么好处: 简历直达…...
本地部署开源在线即时通讯软件Fiora打造个人私密聊天室
文章目录 前言1.关于Fiora2.安装Docker3.本地部署Fiora4.使用Fiora5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定Uptime Kuma公网地址 前言 相信大家在聊天时候总是很没安全感,比如在和小姐妹背着男朋友聊一些不能说的坏话,或者背着女朋友和兄…...
TS(类 接口 泛型)
文章目录 类复习相关知识属性修饰符public 修饰符属性的简写形式 protected修饰符private修饰符readonly修饰符 抽象类 接口(interface)定义类结构定义对象结构定义函数结构接口之间的继承接口自动合并 (可重复定义)一些相似的概念…...
docker 启动 neo4j
docker 启动 neo4j 1. 启动2. 导入数据 1. 启动 运行下面命令启动 neo4j, docker run \-d \--restartalways \--publish7474:7474 --publish7687:7687 \--volume$HOME/neo4j-4.4.38/data:/data \--name neo4j-apoc-4.4.38 \-e NEO4J_dbms_allow__upgradetrue \-e …...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
