当前位置: 首页 > article >正文

进阶-数据结构部分:​​​​​​​2、常用排序算法

飞书文档https://x509p6c8to.feishu.cn/wiki/FfpIwIPtviMMb4kAn3Sc40ABnUh

常用排序算法

这几种算法都是常见的排序算法,它们的优劣和适用场景如下:

冒泡排序(Bubble Sort):简单易懂,时间复杂度较高,适用于小规模数据排序。

选择排序(Selection Sort):简单易懂,时间复杂度较高,适用于小规模数据排序。

插入排序(Insertion Sort):对于部分有序的数据,插入排序的效率比较高,适合排序部分有序的小规模数据。

快速排序(Quick Sort):时间复杂度较低,适合排序大规模的数据,但对于有序数据排序,时间复杂度较高。

归并排序(Merge Sort):时间复杂度稳定,适用于大规模数据排序。

堆排序(Heap Sort):时间复杂度较低,但需要额外的空间存储堆。

计数排序(Counting Sort):时间复杂度较低,但需要额外的空间存储计数数组,适用于数据范围较小的排序。

桶排序(Bucket Sort):时间复杂度较低,但需要额外的空间存储桶,适用于数据范围较小的排序。

基数排序(Radix Sort):时间复杂度较低,但需要额外的空间存储桶,适用于数据范围较小的排序。

时间复杂度和空间复杂度

算法时间/空间复杂度是用来衡量算法执行时间和所需空间的一个指标。

它描述了算法在处理数据时所需的时间/空间量随着数据规模的增加而增加的速度。通常用大O符号(O)来表示。

时间复杂度是指算法执行所需的时间与问题规模之间的关系。
例如:
如果一个算法的时间复杂度是O(n^2),那么执行该算法所需的时间将随着问题规模n的增加而呈平方级增长。
如果一个算法的时间复杂度是O(n),那么执行该算法所需的时间将随着问题规模n的增加而线性增加。
如果一个算法的时间复杂度是O(logn),logn表示以2为底n的对数,比如,当数据增大256倍时,耗时只增大8倍,256/2除尽的次数。
如果一个算法的时间复杂度是O(1),也就是耗时与输入数据大小无关,无论输入数据增大多少倍,耗时都不变。

对数是一种数学函数,用来描述一个数在另一个数的幂次方中的指数。
具体来说,如果我们有一个正数 b(称为“底数”)和一个正数 x(称为“真数”),
那么 b 的 y 次幂等于 x,即 b^y = x。这时,我们就可以用对数函数来表示 y,即 y = logb(x)。
这里的“log”表示对数,“b”表示底数,“x”表示真数,“y”表示指数。
 log₂256=log₂(2^8)=8*(log₂2)=8*1=8 利用的是公式:log₂M^N=N*(log₂M)

算法的稳定性什么意思?

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,A1=A2,且A1在A2之前,而在排序后的序列中,A1仍在A2之前,则称这种排序算法是稳定的;否则称为不稳定的。

1、6、3、a1、9、a2、5、0,假设a1=a2 ;排序后:0、1、3、a1、a2、5、6、9

稳定也可以理解为一切皆在掌握中,元素的位置处在你在控制中.而不稳定算法有时就有点碰运气,随机的成分.当两元素相等时它们的位置在排序后可能仍然相同.但也可能不同.是未可知的.

综上所述,不同的排序算法适用于不同的场景。在实际应用中,应根据数据规模、排序稳定性、时间复杂度、空间需求等因素选择合适的排序算法。

冒泡排序

比较相邻的元素,把大的交换到右边,从第一对到最后一对,这步做完后,最后的元素会是最大的数。

对剩余数据重复以上步骤,找第二大的数、第三大的数直至最后。


#include <stdio.h>void exportArray(int arr[], int n){for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}//冒泡排序的基本思想是逐次判断相邻数值大小,把大的交换到右边。
//该函数中使用了两个嵌套的for循环来实现冒泡排序。
void bubbleSort(int arr[], int n) {int i, j, temp, step;//遍历整个数组for (i = 0; i < n - 1; i++) {//每一轮冒泡比较的次数,i越大比较次数越少//因为每次i++前,都会确定一个最大的值,完成的不需要再比较,所以判断条件变为j < n-i-1for (j = 0; j < n - i - 1; j++) {step ++;//step表示排序的步数//若左边值大于右边值,则交换两个值if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}//exportArray函数用于输出每一步排序后的结果printf("Sorted step %d:",step);exportArray(arr,n);}}
}int main() {int arr[] = {64, 34, 25, 12, 22};int n = sizeof(arr) / sizeof(arr[0]);bubbleSort(arr, n);printf("Sorted end: \n");exportArray(arr,n);return 0;
}

选择排序

  • 首先在未排序序列中找到最小元素,存放到排序序列的起始位置。
  • 再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。
  • 重复第二步,直到所有元素均排序完毕。

#include <stdio.h>void exportArray(int arr[], int n){for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}//遍历数组,每轮遍历时查找到最小的元素,放置左边
void selectionSort(int arr[], int n) {int i, j, min_idx;// 遍历整个数组for (i = 0; i < n-1; i++) {//设置当前数组第i个元素为假设最小值,其它元素会与其对比min_idx = i;// 遍历未排序的数组(未排序从i+1开始),找到数组中最小元素,记录它的索引for (j = i+1; j < n; j++) {printf("Find & Contrast %d\n",j);//如果当前元素小于假设最小值,则认为当前值是最小的元素,记录当前元素位置位置if (arr[j] < arr[min_idx])min_idx = j;}// 将最小元素与未排序部分的第一个元素交换,每轮遍历都会记录一次当前轮最小值int temp = arr[min_idx];arr[min_idx] = arr[i];arr[i] = temp;//exportArray函数用于输出每一步排序后的结果printf("Sorted step %d:",i);exportArray(arr,n);}
}int main() {int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr)/sizeof(arr[0]);selectionSort(arr, n);printf("Sorted end: \n");exportArray(arr,n);return 0;
}

插入排序

插入排序,只要打过扑克牌的人都应该能够秒懂,它的步骤如下:

  • 将第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
  • 依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。


#include <stdio.h>void exportArray(int arr[],int n){for(int i = 0; i < n; i++){printf("%d ",arr[i]);}printf("\n");
}void insertionSort(int arr[],int n){for(int i = 1;i < n;i ++){int key = arr[i];for(int j = i - 1;j >= 0; j--){int compara_value = arr[j];if(compara_value > key){arr[j + 1] = arr[j];arr[j] = key;}else{//key为当前轮最大值,不需要往前插入break;}}printf("第%d轮插入\n",i);exportArray(arr,n);}
}int main(){int arr[] = {12,11,1,5,6};int len = sizeof(arr)/sizeof(arr[0]);printf("main init\n");exportArray(arr,len);insertionSort(arr,len);
}

快速排序

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。

  1. 从数列中挑出一个元素,称为 "基准值";
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;


#include <stdio.h>void exportArray(int arr[], int n){for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}//交换两个值
void swap(int *a, int *b) {int tmp = *a;*a = *b;*b = tmp;
}//对比区间内,从第一个数开始与基准值的大小,如果比基准小,则把当前数与前面(比基准大的值)逐个交换
int partition(int arr[], int low, int high, int n) {//选择基准元素为当前区间最后位置的元素int pivot = arr[high];//记录当前区间首个元素的位置int i = low;//统计交换次数int times = 0;printf("本轮区间 %d-%d 基准值:%d\n",low, high ,pivot);//从第当前区间一个元素开始,到最后一个元素,与基准值比较for (int j = low; j < high ; j++) {if (arr[j] < pivot) {//如果当前元素小于基准值,则把当前元素交换至当前区间的前面swap(&arr[i], &arr[j]);//从当前区间首个位置开始存放,每次存放完加1i++;//统计交换次数,打印交换后的数组times++;printf("Sorted step %d:",times);exportArray(arr,n);}}//结束一轮后,把基准值放到比它小的所有元素后方,也就是位置i后方swap(&arr[i], &arr[high]);//统计交换次数,打印交换后的数组times++;printf("Sorted step %d:",times);exportArray(arr,n);//返回当前基准值位置return i;
}void quicksort(int arr[], int low, int high, int n) {//首次排序时,low等于数组首个元素位置(0),high等于数组最后一个元素的位置(数组长度)//排序结束时,low>=highif (low < high) {//开始执行区间排序,选择最后一个元素作为基准元素//排序后,数组分为两部分,左边比基准元素小,右边比基准元素大int pi = partition(arr, low, high, n);//根据上次排序划分的基准值位置,对左边区间排序quicksort(arr, low, pi - 1, n);//根据上次排序划分的基准值位置,对右边区间排序quicksort(arr, pi + 1, high, n);}
}/**
快速排序(Quicksort)是一种高效的排序算法,
它的基本思想是通过一趟排序将待排序的数据分割成两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行。
具体实现过程如下:
选择一个基准元素,通常选择第一个元素或者最后一个元素,本程序选择最后一个为6;
通过一趟排序将待排序列分成两部分,一部分比基准元素小,一部分比基准元素大;
将基准元素和两个子序列分别递归地进行快速排序。*/
int main() {int arr[] = {10, 7, 8, 9, 1, 5, 6};int n = sizeof(arr) / sizeof(arr[0]);quicksort(arr, 0, n - 1,n);printf("Sorted end: \n");exportArray(arr,n);return 0;
}

相关文章:

进阶-数据结构部分:​​​​​​​2、常用排序算法

飞书文档https://x509p6c8to.feishu.cn/wiki/FfpIwIPtviMMb4kAn3Sc40ABnUh 常用排序算法 这几种算法都是常见的排序算法&#xff0c;它们的优劣和适用场景如下&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;简单易懂&#xff0c;时间复杂度较高&…...

解决 Three.js Raycaster 点击位置与实际交点偏差问题

当使用 Three.js 的 Raycaster 时&#xff0c;如果发现点击位置与显示的碰撞点之间存在较大偏差&#xff0c;这通常是由于坐标系统不匹配或参数设置不正确导致的。以下是系统性的排查和解决方案&#xff1a; 1. 检查鼠标坐标转换 最常见的偏差原因是鼠标坐标到标准化设备坐标…...

25、DeepSeek-R1论文笔记

DeepSeek-R1论文笔记 1、研究背景与核心目标2、核心模型与技术路线3、蒸馏技术与小模型优化4、训练过程简介5、COT思维链&#xff08;Chain of Thought&#xff09;6、强化学习算法&#xff08;GRPO&#xff09;7、冷启动**1. 冷启动的目的****2. 冷启动的实现步骤****3. 冷启动…...

LeetCode --- 156双周赛

题目列表 3541. 找到频率最高的元音和辅音 3542. 将所有元素变为 0 的最少操作次数 3543. K 条边路径的最大边权和 3544. 子树反转和 一、找到频率最高的元音和辅音 分别统计元音和辅音的出现次数最大值&#xff0c;然后相加即可&#xff0c;代码如下 // C class Solution {…...

模型量化AWQ和GPTQ哪种效果好?

环境&#xff1a; AWQ GPTQ 问题描述&#xff1a; 模型量化AWQ和GPTQ哪种效果好? 解决方案&#xff1a; 关于AWQ&#xff08;Adaptive Weight Quantization&#xff09;和GPTQ&#xff08;Generative Pre-trained Transformer Quantization&#xff09;这两种量化方法的…...

npm 报错 gyp verb `which` failed Error: not found: python2 解决方案

一、背景 npm 安装依赖报如下错&#xff1a; gyp verb check python checking for Python executable "python2" in the PATH gyp verb which failed Error: not found: python2 一眼看过去都觉得是Python环境问题&#xff0c;其实并不是你python环境问题&#xf…...

初识Linux · IP协议· 下

目录 前言&#xff1a; 内网IP和公网IP 内网IP 公网IP 路由 前言&#xff1a; 前文我们介绍了IP协议的协议头&#xff0c;通过源码等方式我们理解了IP协议中的字段&#xff0c;比如8位协议&#xff0c;比如通过环回问题引出的8位最大生存时间&#xff0c;比如8位协议&…...

5.27本日总结

一、英语 复习list2list29 二、数学 学习14讲部分内容 三、408 学习计组1.2内容 四、总结 高数和计网明天结束当前章节&#xff0c;计网内容学完之后主要学习计组和操作系统 五、明日计划 英语&#xff1a;复习lsit3list28&#xff0c;完成07年第二篇阅读 数学&#…...

JavaScript基础-创建对象的三种方式

在JavaScript中&#xff0c;对象是构建复杂数据结构和实现面向对象编程的核心。掌握如何创建对象对于每个开发者来说都是必不可少的技能。本文将介绍创建JavaScript对象的三种主要方式&#xff1a;对象字面量、构造函数以及类&#xff08;ES6引入&#xff09;&#xff0c;并探讨…...

JAVA的常见API文档(上)

游戏打包 注意API文档中的方法不需要记忆&#xff01;&#xff01; 了解之后如果需要可以查询API文档 对Math的方法总结&#xff1a; 运用刚学的Math方法加快代码的运行效率 可以减少循环次数 找规律&#xff1a; 发现因子有规律&#xff1a; 必定一个大于平方根&#xff0c;…...

JavaScript 中的 for...in 和 for...of 循环详解

在 JavaScript 中&#xff0c;for...in 和 for...of 是两种常用的循环结构&#xff0c;但它们有着不同的用途和行为。很多初学者容易混淆这两者&#xff0c;本文将详细解析它们的区别、适用场景以及注意事项。 目录 for…in 循环 基本用法遍历对象属性注意事项 for…of 循环 …...

AtCoder AT_abc406_c [ABC406C] ~

前言 除了 A 题&#xff0c;唯一一道一遍过的题。 题目大意 我们定义满足以下所有条件的一个长度为 N N N 的序列 A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\dots,A_N) A(A1​,A2​,…,AN​) 为波浪序列&#xff1a; N ≥ 4 N\ge4 N≥4&#xff08;其实满足后面就必须满足这…...

Spark,连接MySQL数据库,添加数据,读取数据

连接数据库 可以看到shell中我们读取出的数据 在IDEA中打代码如果能输出跟shell中一样的结果即证明连接成功 【出错反思】 像我前面出错的原因就是在打代码时将密码输入错误 添加数据 读取数据就是在上面代码中一起展示了&#xff0c;这里我就不单独说了...

Linux容器技术详解

容器技术基础 什么是容器 容器是一种轻量级的虚拟化技术&#xff0c;它将应用程序及其依赖&#xff08;库、二进制文件、配置文件等&#xff09;打包在一个独立的单元中&#xff0c;可以在任何支持容器运行时的环境中一致地运行。 Docker官网&#xff1a;https://www.docker…...

【EDA软件】【联合Modelsim仿真使用方法】

背景 业界EDA工具仿真功能是必备的&#xff0c;例如Vivado自带仿真工具&#xff0c;且无需联合外部仿真工具&#xff0c;例如MoodelSim。 FUXI工具仿真功能需要联合Modelsim&#xff0c;才能实现仿真功能。 方法一&#xff1a;FUXI联合ModelSim 1 添加testbench文件 新建to…...

STM32 __main

STM32开发中__main与用户main()函数的本质区别及工作机制 在STM32开发中&#xff0c;__main和用户定义的main()函数是启动过程中的两个关键节点&#xff0c;分别承担运行时初始化和用户程序入口的职责。以下是它们的核心差异及协作机制&#xff1a; 一、定义与层级差异 ​__ma…...

【离散化 线段树】P3740 [HAOI2014] 贴海报|普及+

本文涉及知识点 C线段树 [HAOI2014] 贴海报 题目描述 Bytetown 城市要进行市长竞选&#xff0c;所有的选民可以畅所欲言地对竞选市长的候选人发表言论。为了统一管理&#xff0c;城市委员会为选民准备了一个张贴海报的 electoral 墙。 张贴规则如下&#xff1a; electoral…...

Python训练营打卡Day28

浙大疏锦行 DAY 28 类的定义和方法 知识点回顾&#xff1a; 1.类的定义 2.pass占位语句 3.类的初始化方法 4.类的普通方法 5.类的继承&#xff1a;属性的继承、方法的继承 作业 题目1&#xff1a;定义圆&#xff08;Circle&#xff09;类 要求&#xff1a; 1.包含属性&#x…...

MODBUS RTU通信协议详解与调试指南

一、MODBUS RTU简介 MODBUS RTU&#xff08;Remote Terminal Unit&#xff09;是一种基于串行通信&#xff08;RS-485/RS-232&#xff09;的工业标准协议&#xff0c;采用二进制数据格式&#xff0c;具有高效、可靠的特点&#xff0c;广泛应用于PLC、传感器、变频器等工业设备…...

CSP 2024 提高级第一轮(CSP-S 2024)单选题解析

单选题解析 第 1 题 在 Linux 系统中&#xff0c;如果你想显示当前工作目录的路径&#xff0c;应该使用哪个命令&#xff1f;&#xff08;A&#xff09; A. pwd B. cd C. ls D. echo 解析&#xff1a;Linux 系统中&#xff0c;pwd命令可以显示当前工作目录的路径。pwd&#x…...

六、绘制图片

文章目录 1.创建一个红色图片2.加载bmp图片3.加载png、jpg图片 前面的几个示例&#xff0c;我们已经展示过如果在Linux系统下使用xlib接口向窗口中绘制文本、线、矩形&#xff1b;并设置文本、线条的颜色。并利用xlib提供的接口结合事件处理机制完成了一个自绘按钮控件功能。有…...

Java 面向对象详解和JVM底层内存分析

先关注、点赞再看、人生灿烂&#xff01;&#xff01;&#xff01;&#xff08;谢谢&#xff09; 神速熟悉面向对象 表格结构和类结构 我们在现实生活中&#xff0c;思考问题、发现问题、处理问题&#xff0c;往往都会用“表格”作为工具。实际上&#xff0c;“表格思维”就是…...

深度学习---知识蒸馏(Knowledge Distillation, KD)

一、知识蒸馏的本质与起源 定义&#xff1a; 知识蒸馏是一种模型压缩与迁移技术&#xff0c;通过将复杂高性能的教师模型&#xff08;Teacher Model&#xff09;所学的“知识”迁移到轻量级的学生模型&#xff08;Student Model&#xff09;&#xff0c;使学生模型在参数量和计…...

基于CNN卷积神经网络的带频偏QPSK调制信号检测识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2024b 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…...

【DAY21】 常见的降维算法

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 目录 PCA主成分分析 t-sne降维 线性判别分析 (Linear Discriminant Analysis, LDA) 作业&#xff1a; 什么时候用到降维 降维的主要应用场景 知识点回顾&#xff1a; PCA主成分分析t-sne降维LDA线性判别 通常情况下&#xff0c;…...

PostGIS实现栅格数据入库-raster2pgsql

raster2pgsql使用与最佳实践 一、工具概述 raster2pgsql是PostGIS提供的命令行工具,用于将GDAL支持的栅格格式(如GeoTIFF、JPEG、PNG等)导入PostgreSQL数据库,支持批量加载、分块切片、创建空间索引及金字塔概览,是栅格数据入库的核心工具。 二、核心功能与典型用法 1…...

校园社区小程序源码解析

基于ThinkPHP、FastAdmin和UniApp开发的校园社区小程序源码&#xff0c;旨在为校园内的学生和教职员工提供一个便捷的在线交流和服务平台。 该小程序前端采用UniApp进行开发&#xff0c;具有良好的跨平台兼容性&#xff0c;可以轻松发布到iOS和Android平台。同时&#xff0c;后…...

第6章:文件权限

一、文件权限概述 Linux为了保证系统中每个文件的安全&#xff0c;引入了文件权限机制。针对于系统中的每一个文件Linux都可以提供精确的权限控制。它可以做到不同的用户对同一个文件具有不同的操作权利。而通常这个权利包括以下3个&#xff1a; 读的权利&#xff08;Read&…...

使用 Python 连接 Oracle 23ai 数据库完整指南

方法一:使用 oracledb 官方驱动(推荐) Oracle 官方维护的 oracledb 驱动(原 cx_Oracle)是最新推荐方案,支持 Thin/Thick 两种模式。 1. 环境准备 pip install oracledb2. 完整示例代码 import oracledb import getpass from typing import Unionclass Oracle23aiConn…...

C语言| 指针变量的定义

C语言| 指针的优点-CSDN博客 * 表示“指向”&#xff0c;为了说明指针变量和它所指向的变量之间的联系。 int * i&#xff1b;//表示指针变量i里面存放的地址&#xff0c;所指向的存储单元里的【数据】。 【指针变量的定义】 C语言规定所有变量&#xff0c;在使用前必须先定…...