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

一.冒泡排序

原理图:


实现代码:

/* 冒泡排序或者是沉底排序 *//* 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))都使用了分治法,将一个大问题分为几个相同的小问题,分而治之。

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

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

相关文章

Neo4j 集群和负载均衡

Neo4j 集群和负载均衡 Neo4j是当前最流行的开源图DB。刚好读到了Neo4j的集群和负载均衡策略&#xff0c;记录一下。 1 集群 Neo4j 集群使用主从复制实现高可用性和水平读扩展。 1.1 复制 集群的写入都通过主节点协调完成的&#xff0c;数据先写入主机&#xff0c;再同步到…

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测 近年来&#xff0c;随着城市化的不断推进和基础设施建设的不断发展&#xff0c;隧道建设也日益成为城市交通发展的必需品。然而&#xff0c;隧道建设中存在着一定的安全隐患&#xff0c;如地质灾害、地下水涌流等&…

springboot第32集:redis系统-android系统-Nacos Server

Error parsing HTTP request header HTTP method names must be tokens 检查发送HTTP请求的客户端代码&#xff0c;确保方法名中不包含非法字符。通常情况下&#xff0c;HTTP请求的方法名应该是简单的标识符&#xff0c;例如"GET"、"POST"、"PUT"…

《TCP IP网络编程》第十二章

第 12 章 I/O 复用 12.1 基于 I/O 复用的服务器端 多进程服务端的缺点和解决方法&#xff1a; 为了构建并发服务器&#xff0c;只要有客户端连接请求就会创建新进程。这的确是实际操作中采用的一种方案&#xff0c;但并非十全十美&#xff0c;因为创建进程要付出很大的代价。…

免费商用 Meta 发布开源大语言模型 Llama 2

Meta 和微软深度合作&#xff0c;正式推出下一代开源大语言模型 Llama 2&#xff0c;并宣布免费提供给研究和商业使用。 Llama 2 论文地址&#xff1a;Llama 2: Open Foundation and Fine-Tuned Chat Models 据介绍&#xff0c;相比于 Llama 1&#xff0c;Llama 2 的训练数据多…

Tensorflow学习

一、处理数据的结构 案例代码如下: import tensorflow.compat.v1 as tf tf.disable_v2_behavior() import numpy as np# create data x_data np.random.rand(100).astype(np.float32) y_data x_data*0.1 0.3# 创建结构(一维结构) Weights tf.Variable(tf.random.uniform(…

C++模板

目录 函数模板隐式实例化显式实例化 类模板 下面是多种类型的交换函数 void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left right;right temp; } void Swap(ch…

Redis 哨兵 (sentinel)

是什么 官网理论&#xff1a;https://redis.io/docs/management/sentinel/ 吹哨人巡查监控后台 master 主机是否故障&#xff0c;如果故障了根据投票数自动将某一个从库转换为新主库&#xff0c;继续对外服务。 作用&#xff1a;无人值守运维 哨兵的作用&#xff1a; 1…

Pytorch深度学习-----神经网络的卷积操作

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

【状态估计】基于UKF、AUKF的电力系统负荷存在突变时的三相状态估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SentencePiece android ndk编译

LLaMa等LLM语言模型一般使用SentencePiece tokenizer&#xff0c;在端侧部署需要编译和使用其c版本。 在安卓平台使用NDK编译 CMakeLists.txt需要进行一些修改&#xff1a; src/CMakeLists.txt如下位置加上log依赖&#xff0c;否则提示android log相关符号不存在。 此外&…

RNN架构解析——LSTM模型

目录 LSTMLSTM内部结构图 Bi-LSTM实现 优点和缺点 LSTM LSTM内部结构图 Bi-LSTM 实现 优点和缺点

解决IDEA的git非常缓慢方法

解决IDEA的git非常缓慢方法 xxxx\IDEA2021.1.3\IntelliJ IDEA 2021.1.3\bin

transformer代码注解

其中代码均来自李沐老师的动手学pytorch中。 class PositionWiseFFN(nn.Module):ffn_num_inputs 4ffn_num_hiddens 4ffn_num_outputs 8def __init__(self,ffn_num_inputs,ffn_num_hiddens,ffn_num_outputs):super(PositionWiseFFN,self).__init__()self.dense1 nn.Linear(ffn…

微服务项目,maven无法加载其他服务依赖

微服务项目&#xff0c;导入了工具类工程&#xff0c;但是一直报错&#xff0c;没有该类&#xff0c; 检查maven 这里的Maven的版本与idea版本不匹配可能是导致依赖加载失败的最重要原因 检查maven配置&#xff0c;我这是原来的maven&#xff0c;home 修改之后,就不报错了

Autosar通信实战系列02-CAN报文发送周期测试脚本开发及周期不准优化

本文框架 前言1. CAN发送报文的周期测试脚本开发2. 发送报文周期不准的可能原因及优化策略2.1 发送报文的控制逻辑2.2 送报文周期不准的可能原因及优化策略前言 在本系列笔者将结合工作中对通信实战部分的应用经验进一步介绍常用,包括但不限于通信各模块的开发教程,代码逻辑…

【ArcGIS Pro二次开发】(53):村规制表、制图【福建省】

这篇算是村规入库的一个延续。 村庄规划中有一些图纸是需要严格按照规范制图&#xff0c;或形成一定规范格式的。 这些图纸的制作基本算是机械式的工作&#xff0c;可以用工具来代替人工。 一、要实现的功能 如上图所示&#xff0c;在【村庄规划】组&#xff0c;新增了两个工…

【雕爷学编程】MicroPython动手做(16)——掌控板之图片图像显示3

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

vue3+vite——打测试包+正式包+本地预览打包后的文件——基础积累

最近在学习vue3vite的内容&#xff0c;发现vite和webpack类似&#xff0c;下面将区别及使用方法做一下记录&#xff1a; 1.vite添加环境配置文件 ... ├── src ... ├── .env # 通用环境变量配置 ├── .env.development …

机器学习:提取问题答案

模型BERT 任务&#xff1a;提取问题和答案 问题的起始位置和结束位置。 数据集 数据集 DRCDODSQA 先分词&#xff0c;然后tokenize 文章长度是不同的&#xff0c;bert的token的长度有限制&#xff0c;一般是512&#xff0c; self-attention的计算量是 O ( n 2 ) O(n^2) O(n…