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

算法与数据结构(四)--排序算法

一.冒泡排序

原理图:


实现代码:

/* 冒泡排序或者是沉底排序 *//* int arr[]: 排序目标数组,这里元素类型以整型为例; int len: 元素个数 */
void bubbleSort (elemType arr[], int len) {//为什么外循环小于len-1次?//考虑临界情况,就是要循环到len-1个沉底/冒泡,则排序完毕for (int i=0; i<len-1; i++) {//为什么内循环小于等于len-2-i次?//考虑临界情况,第一次循环最后是索引为len-2与len-1进行比较,所以第一次循环到len-2,//每循环一次多沉底/冒泡一个,所以每循环完一次要多减去1,也就是多减去i,所以为len-2-ifor (int j=0; j<=len-2-i; j++) { //相邻元素比较,符合条件进行交换,数值大的元素沉底,数值小的元素冒泡if (arr[j] > arr[j+1]) { int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
}

二.插入排序


原理图:

 实现代码:

// 插入排序函数(n是数组的长度)
void insertionSort(int arr[], int n) {//先对第二个元素进行插入(索引比实际位置少一),直到对n个元素进行插入for (int i = 1; i < n; i++) {int key = arr[i]; // 当前要插入的元素j = i-1;// 将当前元素与前面的比较,将比当前元素大的元素往后移动,自己往前移动// 直到找到合适的位置或者遍历到数组的开头while (int j >= 0 && arr[j] > key) {arr[j+1] = arr[j]; // 当前元素比key大,向后移动一位j = j-1; // 继续向前比较}arr[j+1] = key; // 将当前元素插入到正确的位置}
}

三.选择排序

原理图:

实现代码:

void selectionSort(int arr[], int n) {// 遍历数组,从第一个元素到倒数第二个元素,要排序n-1次,n-1个排好才算全部排好for (int i = 0; i < n - 1; i++) {int minIndex = i;//假设当前循环开始时,第一个元素为最小值// 在未排序部分寻找最小值for (int j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}// 如果最小值不是当前循环的第一个元素,则进行交换if (minIndex != i) {// 交换两个元素的位置int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}

上面三种简单排序算法在最坏情况及平均情况下都需要O(n^{2})计算时间。
下面讨论的排序算法,它在平均情况下需要O(nlogn)时间。下面这些是目前最快的排序。

四.快速排序--分治法+挖坑填数



原理:

去B站看其中快速排序的哪一节!!!

分治法:大问题分解成各个小问题,对小问题求解,使得大问题得以解决。


实现代码:

#include<iostream>
using namespace std;
void PrintArray(int arr[],int len) {for(int i=0; i<len; i++) {cout<<arr[i]<<" ";}cout<<endl;
}
//快速排序,从小到大
void QuickSort(int arr[],int start,int end) {//i和j是索引的值,也可以看做是指针,//先让它们指向要排序数据的首尾int i=start;int j=end;//基准数,这里取数据的start位置,同时也是此时i的位置//挖坑填数时挖出来的第一个数(也就是第一个的坑)为基准数的位置/也是此时start和i的位置int temp=arr[start];//保证参数输入正确,即,start<end,否则不执行if(i<j) {//只要i和j不重合,就不断地移动j,挖坑填数,移动i,挖坑填数...//最后做到基准数小的数都在基准数的左边,比基准数大的数都在基准数的右边while(i<j) //移动指针j,从右向左找比基准数小的元素,比基准数大继续左移,//直到遇到比基准数小的元素才跳出循环,用该元素填坑while(i<j&&arr[j]>=temp) {j--;}//用j位置的数据给i的坑填数(将j的数据赋值给i),j变成坑if(i<j) {arr[i]=arr[j];}//移动指针i,从左向右找比基准数大的数,比基准数小i继续右移,//直到遇到比基准数小的元素才跳出循环,用该元素填坑while(i<j&&arr[i]<temp) {i++;}//用i位置的数据给j的坑填数(将i的数据赋值给j),j变成坑if(i<j) {arr[j]=arr[i];}}//最后i和j重叠的位置就是基准数的位置,把基准数放到i的位置填上最后一个坑arr[i]=temp;//递归//1.对左半部分进行快速排序QuickSort(arr,start,i-1);//2.对右半部分进行快速排序QuickSort(arr,i+1,end); }
}
int main() {int myArr[]= {4,2,8,0,5,7,1,3,9};int len=sizeof(myArr)/sizeof(int);PrintArray(myArr,len);QuickSort(myArr,0,len-1);PrintArray(myArr,len);return 0; 
}

五.归并排序/合并排序--分治法+合并两个有序序列

基本思想:分治法+将两个有序序列合并成一个有序序列
怎么合并呢?
就是开辟一块临时的存储空间。就比如有两个身高从低到高的队伍,要合并成一个也是身高从小到高的队伍,就先将每个队伍的第一个人比较身高,然后低的进去,然后第二个人再与另一个队的第一个人比较身高,低的进去。。。以此类推,差不多就是这样。

去B站看其中合并排序的哪一节!!!

#include<iostream>
#include<time.h>
#include<sys/timeb.h>
using namespace std;
#define MAX 10
//创建数组
int* CreatArray() {srand((unsigned int)time(NULL));int* arr=(int*)malloc(sizeof(int)*MAX);for(int i=0; i<MAX; i++) {arr[i]=rand()%MAX;}return arr;
}
//打印
void PrintArray(int arr[],int len) {for(int i=0; i<len; i++) {cout<<arr[i]<<" ";}cout<<endl;
}
//合并算法,从小到大
//int *temp--临时的存储空间 
void Merge(int arr[],int start,int end,int mid,int *temp) {//一.将序列拆分为i,j两个序列 int i_start=start;//i序列的头指针 int i_end=mid;//i序列的尾指针 int j_start=mid+1;//j序列的头指针 int j_end=end;//j序列的尾指针 int length=0;//表示辅助空间有多少个元素//二.合并两个有序序列,并且使得合并后仍然有序//遍历到其中一个序列空为止while(i_start<=i_end&&j_start<=j_end) {//如果i指针指向的元素比j小,则先推出到辅助空间中if(arr[i_start]<arr[j_start]) {//将数据存到辅助空间中temp[length]=arr[i_start];//辅助空间长度加一length++;//i序列指针往后移判断下一个推入辅助空间的元素i_start++;} else {//如果j指针指向的元素比i小,则先推出到辅助空间中//将数据存到辅助空间中temp[length]=arr[j_start];//辅助空间长度加一length++;//j序列指针往后移判断下一个要推入辅助空间的元素j_start++;}}//三.只有一个序列为空,说明有一个序列里面还有剩下的元素,要将剩下的元素也存到辅助空间 //如果i这个序列的头指针仍然在尾指针之前,说明里面还有元素while (i_start<=i_end) {//将数据存到辅助空间中temp[length]=arr[i_start];//辅助空间长度加一length++;//i序列指针往后移判断下一个推入辅助空间的元素i_start++;}//如果j这个序列的头指针仍然在尾指针之前,说明里面还有元素while(j_start<=j_end) {//将数据存到辅助空间中temp[length]=arr[j_start];//辅助空间长度加一length++;//j序列指针往后移判断下一个要推入辅助空间的元素j_start++;}//四.把辅助空间中的数据覆盖到原空间for(int i=0;i<length;i++){arr[start+i]=temp[i];} 
}
//归并排序
void MergeSort(int arr[],int start,int end,int* temp) {if(start>=end) {return;}int mid=(start+end)/2;//分组//左半边MergeSort(arr,start,mid,temp);//右半边MergeSort(arr,mid+1,end,temp);//合并Merge(arr,start,end,mid,temp);}
int main() {int* myArr=CreatArray();PrintArray(myArr,MAX);//辅助空间,来存储合并后的有序序列。int * temp=(int*)malloc(sizeof(int)* MAX) ;MergeSort(myArr,0,MAX-1,temp);PrintArray(myArr,MAX);//释放空间free(temp);free(myArr);
}

六.希尔排序--分治法+插入排序(插入排序的提升版)

[算法]六分钟彻底弄懂希尔排序,简单易懂

20希尔排序

#include <stdio.h>
void shellSort(int arr[],int length) {int increasement=length;//确定分组的增量,你可以用你喜欢的增量,我这里取长度除以2 increasement=increasement/2;//增量小于1停止,也就是最后对一整组进行插入排序后停止 while(increasement>1) {//遍历每一组for(int i=0; i<increasement; i++) {// 对每一组进行快速排序//遍历当前这组的元素 for(int j=i+increasement; j<length; j+=increasement) {// 如果当前元素小于前一个元素,则进行插入操作if(arr[j]<arr[j-increasement]) {int temp=arr[j];int k;// 将大于temp的元素向后移动for(k=j-increasement; k>=0&&temp<arr[k]; k-=increasement) {arr[k+increasement]=arr[k];}// 插入temp到正确的位置arr[k+increasement]=temp;}}}//缩小增量 increasement=increasement/2;} 
}
void printArray(int arr[], int n) {for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {12, 34, 54, 2, 3};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: ");printArray(arr, n);shellSort(arr, n);printf("排序后的数组: ");printArray(arr, n);return 0;
}

为什么分组后的插入排序会快呢?
因为插入排序在元素序列基本有序和元素个数比较小的时候速度较快,而分组就创造了这种条件。

总结

可以发现,下面三种快的排序(平均情况下的时间复杂度都为O(nlogn))都使用了分治法,将一个大问题分为几个相同的小问题,分而治之。

相关文章:

算法与数据结构(四)--排序算法

一.冒泡排序 原理图&#xff1a; 实现代码&#xff1a; /* 冒泡排序或者是沉底排序 *//* int arr[]: 排序目标数组,这里元素类型以整型为例; int len: 元素个数 */ void bubbleSort (elemType arr[], int len) {//为什么外循环小于len-1次&#xff1f;//考虑临界情况&#xf…...

【C/C++】C++11 在各编译器版本支持详情

C11 是在 2011 年发布的 C 标准&#xff0c;各编译器对 C11 的支持情况如下&#xff1a; GCC&#xff1a;GCC 4.8 及以上版本支持 C11。Clang&#xff1a;Clang 3.3 及以上版本支持 C11。Visual Studio&#xff1a;Visual Studio 2010 及以上版本支持部分 C11 特性&#xff0c…...

flutter开发实战-图片保存到相册

flutter开发实战-图片保存到相册。保存相册使用的是image_gallery_saver插件 一、引入image_gallery_saver插件 在pubspec.yaml中引入插件 # 保存图片到相册image_gallery_saver: ^1.7.1# 权限permission_handler: ^10.0.0二、保存到相册的代码 使用image_gallery_saver将图…...

数据结构---栈

(一)栈之基础补充 C语言内存分配 对于一个C语言程序而言,内存空间主要由五个部分组成 代码段(text)、数据段(data)、未初始化数据段(bss),堆(heap) 和 栈(stack) 组成,其中代码段,数据段和BSS段是编译的时候由编译器分配的,而堆和栈是程序运行的时候由系统分配的。布局如…...

【RabbitMQ】golang客户端教程1——HelloWorld

一、介绍 本教程假设RabbitMQ已安装并运行在本机上的标准端口&#xff08;5672&#xff09;。如果你使用不同的主机、端口或凭据&#xff0c;则需要调整连接设置。如果你未安装RabbitMQ&#xff0c;可以浏览我上一篇文章Linux系统服务器安装RabbitMQ RabbitMQ是一个消息代理&…...

计算机图形学笔记2-Viewing 观测

观测主要解决的问题是如何把物体的三维“模型”变成我们在屏幕所看到的二维“图片”&#xff0c;我们在计算机看到实体模型可以分成这样几步&#xff1a; 相机变换(camera transformation)或眼变换(eye transformation)&#xff1a;想象把相机放在任意一个位置来观测物体&#…...

Redis - 三大缓存问题(穿透、击穿、雪崩)

缓存穿透 概念&#xff1a; 查询一个数据库中也不存在的数据&#xff0c;数据库查询不到数据也就不会写入缓存&#xff0c;就会导致一直查询数据库 解决方法&#xff1a; 1. 缓存空数据 如果数据库也查询不到&#xff0c;就把空结果进行缓存 缺点是 - 消耗内存 2. 使用布…...

web自动化测试-PageObject 设计模式

为 UI 页面写测试用例时&#xff08;比如 web 页面&#xff0c;移动端页面&#xff09;&#xff0c;测试用例会存在大量元素和操作细节。当 UI 变化时&#xff0c;测试用例也要跟着变化&#xff0c; PageObject 很好的解决了这个问题。 使用 UI 自动化测试工具时&#xff08;包…...

golang json.Marshal() 结构体、map 携带 符号 转成 “\u0026“

问题&#xff1a;数据结构中的值 带有 & > < 等符号&#xff0c;当我们要将 struct map 转成json时&#xff0c;使用 json.Marshal() 函数&#xff0c;此函数会将 值中的 & < > 符号转义 为 类似 "\u0026" 像我们某个结构体中…...

【设计模式|行为型】备忘录模式(Memento Pattern)

说明 备忘录模式是一种行为型设计模式&#xff0c;通过捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便在需要时恢复对象到原先的状态。备忘录模式包含三个核心角色&#xff1a;。 发起人&#xff08;Originator&#xff09;&#xff1a;负责…...

Redis与其他缓存解决方案(如Memcached)的区别是什么?

Redis和其他缓存解决方案&#xff08;如Memcached&#xff09;在设计理念、功能和特点上有一些区别&#xff0c;以下是它们的主要区别&#xff1a; 数据类型支持&#xff1a;Redis支持多种数据类型&#xff08;如字符串、哈希表、列表、集合、有序集合等&#xff09;&#xff0…...

《面试1v1》Kafka的ack机制

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…...

基于双 STM32+FPGA 的桌面数控车床控制系统设计

桌 面数控 设 备 对 小 尺寸零件加工在成 本 、 功 耗 和 占 地 面 积等方 面有 着 巨 大 优 势 。 桌 面数控 设 备 大致 有 3 种 实 现 方 案 : 第 一种 为 微 型 机 床搭 配 传统 数控系 统 &#xff0c; 但 是 桌 面数控 设 备 对 成 本 敏感 ; 第二 种 为 基 于 PC…...

ES-5-进阶

单机 & 集群 单台 Elasticsearch 服务器提供服务&#xff0c;往往都有最大的负载能力&#xff0c;超过这个阈值&#xff0c;服务器 性能就会大大降低甚至不可用&#xff0c;所以生产环境中&#xff0c;一般都是运行在指定服务器集群中 配置服务器集群时&#xff0c;集…...

Java面试准备篇:全面了解面试流程与常见问题

文章目录 1.1 Java面试概述1.2 面试流程和注意事项1.3 自我介绍及项目介绍1.4 常见面试问题 在现代职场中&#xff0c;面试是求职过程中至关重要的一环&#xff0c;特别是对于Java开发者而言。为了帮助广大Java开发者更好地应对面试&#xff0c;本文将提供一份全面的Java面试准…...

Go语言进阶语法八万字详解,通俗易懂

文章目录 File文件操作FileInfo接口权限打开模式File操作文件读取 I/O操作io包 文件复制io包下的Read()和Write()io包下的Copy()ioutil包总结 断点续传Seeker接口断点续传 bufio包bufio包原理Reader对象Writer对象 bufio包bufio.Readerbufio.Writer ioutil包ioutil包的方法示例…...

Apache RocketMQ 远程代码执行漏洞(CVE-2023-37582)

​ 漏洞简介 Apache RocketMQ是一款低延迟、高并发、高可用、高可靠的分布式消息中间件。CVE-2023-37582 中&#xff0c;由于对 CVE-2023-33246 修复不完善&#xff0c;导致在Apache RocketMQ NameServer 存在未授权访问的情况下&#xff0c;攻击者可构造恶意请求以RocketMQ运…...

Kotlin Multiplatform 使用 CocoaPods 创建多平台分发库

Kotlin Multiplatform 支持直接创建Framework 方式和使用CocoaPods 方式创建Framework。 1、不同之处在于创建的时候需要选择不同的方式。 2、使用CocoaPods 方式还需要在 build.gradle(.kts) 文件中添加内容 在build.gradle(.kts) 文件中添加完成后&#xff0c;执行一下文件。…...

前端食堂技术周刊第 92 期:VueConf 2023、TypeChat、向量数据库、Nuxt 服务器组件指南

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;整颗牛油果酸奶 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先…...

用C语言构建一个手写数字识别神经网络

(原理和程序基本框架请参见前一篇 "用C语言构建了一个简单的神经网路") &#xff11;&#xff0e;准备训练和测试数据集 从http://yann.lecun.com/exdb/mnist/下载手写数字训练数据集, 包括图像数据train-images-idx3-ubyte.gz 和标签数据 train-labels-idx1-ubyte.…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...