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

news/2024/5/20 20:41:22

一.冒泡排序

原理图:


实现代码:

/* 冒泡排序或者是沉底排序 *//* 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.mrgr.cn/p/84885582

相关文章

通过一次线上问题,讲下Ribbon重试机制

前言 前段时间&#xff0c;产品经理在线上验证产品功能的时候&#xff0c;发现某个功能不符合需求预期&#xff0c;后来测试验证发现是服务端的一个接口大概率偶现超时&#xff0c;前端做了兜底处理&#xff0c;所以对线上用户么有太大影响。 问题排查过程 由于服务端的接口…

使用 CSS 自定义属性

我们常见的网站日夜间模式的变化&#xff0c;其实用到了 css 自定义属性。 CSS 自定义属性&#xff08;也称为 CSS 变量&#xff09;是一种在 CSS 中预定义和使用的变量。它们提供了一种简洁和灵活的方式来通过多个 CSS 规则共享相同的值&#xff0c;使得样式更易于维护和修改。…

亚马逊云科技纽约峰会,充分释放数据价值和生成式AI的潜力

生成式AI将深刻改变每个公司的运营方式&#xff0c;标志着人工智能技术发展的新转折点。亚马逊云科技昨日在纽约峰会上宣布&#xff0c;推出七项生成式AI新功能&#xff0c;进一步降低了生成式AI的使用门槛&#xff0c;让无论是业务用户还是开发者都能从中受益。借助这些新功能…

el-upload上传图片和视频,支持预览和删除

话不多说&#xff0c; 直接上代码&#xff1a; 视图层&#xff1a; <div class"contentDetail"><div class"contentItem"><div style"margin-top:5px;" class"label csAttachment">客服上传图片:</div><el…

(12)Qt事件系统(one)

目录 Qt Event System 事件处理的方法 系统事件处理函数 基本事件 窗口显示事件 窗口关闭事件 窗口隐藏事件 窗口移动事件 窗口大小改变事件 窗口状态改变事件 鼠标事件 鼠标进入、离开事件 鼠标按下抬起事件 鼠标双击事件 鼠标移动事件 鼠标滚轮事件 示例&#xff1…

【多模态】21、BARON | 通过引入大量 regions 来提升模型开放词汇目标检测能力(CVPR2021)

文章目录 一、背景二、方法2.1 主要过程2.2 Forming Bag of Regions2.3 Representing Bag of Regions2.4 Aligning bag of regions 三、效果 论文&#xff1a;Aligning Bag of Regions for Open-Vocabulary Object Detection 代码&#xff1a;https://github.com/wusize/ovdet…

怎么通过通过 p 名称空间配置 bean以及怎么去引用/注入其它 bean 对象--ref和怎么去引用/注入内部 bean 对象-内部 bean 对象

&#x1f600;前言 本章是spring基于XML 配置bean系类中第2篇讲解怎么通过通过 p 名称空间配置 bean以及怎么去引用/注入其它 bean 对象–ref和怎么去引用/注入内部 bean 对象 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0…

了解Unity编辑器之组件篇Miscellaneous(九)

一、Aim Constraint&#xff1a;是一种动画约束&#xff0c;用于使一个对象朝向另一个对象或一个指定的矢量方向 Activate按钮&#xff1a;用于激活或停用Aim Constraint。当Aim Constraint处于激活状态时&#xff0c;其约束效果将应用于目标对象。 Zero按钮&#xff1a;用于将…

工业平板电脑优化汽车工厂的生产流程

汽车行业一直是自动化机器人系统的早期应用领域之一。通过使用具有高负载能力和远程作用的大型机械臂&#xff0c;汽车装配工厂可以实现点焊、安装挡风玻璃、安装车轮等工作&#xff0c;而较小的机械手则用于焊接和安装子组件。使用机器人系统不仅提高了生产效率&#xff0c;还…

福特汽车在全球电动汽车市场的主导地位正在不断扩大

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 2023年7月27日&#xff0c;美国最大的汽车巨头之一福特汽车(F)公布了其2023年第二季度财报。 2023年7月6日&#xff0c;福特汽车宣布&#xff0c;第二季度美国市场的汽车销量已经较2023年第一季度增长了11.7%&#xff0c;令…

前后端分离开发流程

1、介绍 在前后端分离开发中&#xff0c;前端负责用户界面和交互逻辑的实现&#xff0c;后端则处理业务逻辑和数据持久化。这种开发模式的优势在于前后端可以独立进行开发&#xff0c;提高了开发效率&#xff0c;并且使得前后端可以采用不同的技术栈来实现各自的功能。 2、开…

学习笔记|大模型优质Prompt开发与应用课(二)|第二节:超高产文本生成机,传媒营销人必备神器

文章目录 01 文字写作技能的革新&#xff0c;各行各业新机遇四大类常见文字工作新闻记者的一天新闻记者的一天–写策划prompt 新闻记者的一天–排采访prompt生成结果prompt生成结果 大模型加持&#xff0c;文字写作我们如何提效营销创作营销创作-使用预置法为不同平台生成文案p…

以智慧监测模式守护燃气安全 ,汉威科技“传感芯”凸显智慧力

城市燃气工程作为城市基建的重要组成部分&#xff0c;与城市居民生活、工业生产紧密相关。提升城市燃气服务质量和安全水平&#xff0c;也一直是政府和民众关注的大事。然而&#xff0c;近年来居民住宅、餐饮等工商业场所燃气事故频发&#xff0c;时刻敲响的警钟也折射出我国在…

Mybatis插件

文章目录 1. 如何自定义插件1.1 创建接口Interceptor的实现类1.2 配置拦截器1.3 运行程序 2. 插件原理2.1 解析过程2.2 创建代理对象2.2.1 Executor2.2.2 StatementHandler2.2. 3ParameterHandler2.2.4 ResultSetHandler 2.3 执行流程 1. 如何自定义插件 1.1 创建接口Intercep…

el-table 表格头部合并

<el-table v-loading"listLoading" :key"tableKey" :data"list" stripe border fit highlight-current-rowstyle"width: 100%;" size"mini"><el-table-column label"第一行" align"center">…

Vue3 导出word

&#x1f642;博主&#xff1a;锅盖哒 &#x1f642;文章核心&#xff1a;导出word 目录 1.首先&#xff0c;你需要安装docxtemplater库。可以使用npm或yarn来安装&#xff1a; 2.在Vue组件中&#xff0c;你可以使用docxtemplater来生成Word文档并提供一个导出按钮供用户下载…

2023软件设计师中级备考经验分享(文中有资料链接分享)

先摊结论吧&#xff0c;软考中级设计师备考只是备考半个月&#xff08;期间还摆烂了几天&#xff09;&#xff0c;然而成绩如下&#xff1a; 我自己都没想到会这么好的成绩。。。 上午题&#xff1a;推荐把软考通APP里的历年真题刷3-4遍&#xff0c;直接刷真题&#xff0c;然后…

白盒测试和黑盒测试的区别是什么?

前言 曾言道“黑猫&#xff0c;白猫&#xff0c;只要能抓住老鼠就是好猫”。我们的测试亦是如此&#xff0c;不管是黑盒测试还是白盒测试&#xff0c;只要能测试出来bug&#xff0c;可以找出问题所在&#xff0c;保障软件质量就是好的测试方法。 对于刚入门的软件测试小白来说…

PHP数组转对象和对象转数组

PHP数组转对象和对象转数组 <?php function array_to_object($arr){$obj new stdClass();foreach ($arr as $key > $val) {if (is_array($val) || is_object($val)) {$obj->$key array_to_object($val);} else {$obj->$key $val;}}return $obj; } function o…

Verilog语法学习——LV2_异步复位的串联T触发器

LV2_异步复位的串联T触发器 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 题目描述&#xff1a; 用verilog实现两个串联的异步复位的T触发器的逻辑&#x…