数据结构-排序算法篇

前言

  在我们的生活中有很多东西都是有大小的,那么该如何去排序?假设有10个数字要你去排序,眼睛一扫就看出来了,那100、1000、10000····要怎么去排?下面就为大家介绍各种排序的算法。

内容

1.冒泡排序

2.选择排序

3.插入排序

4.希尔排序

5.快排

6.归并排序

7.计数排序

1.冒泡排序

   冒泡排序排序是一种交换排序,第一个数与第二个数进行比较(这里排序都默认是升序)如果第二个数小于第一个数,那就交换这两数位置然后第二个数再和第三个数依次进行比较,最后会将这个数组中最大数移动到数组最后的位置。

图解

代码
//冒泡排序
void BubbleSort(int* a, int n)
{for (int i = 0; i < n; i++){//j<n-i这样写是因为每比遍历一次数组就将最大的数放到了数组的最后面//下次排序就不用再比较了可以提高效率int flang = 1;//假设已经这个数组已经有序了for (int j = 0; j < n - i; j++){if (j + 1<n && a[j + 1] < a[j])//j + 1 < n是为防止越界{flang = 0;//进入到这里说明数组还没有完全有序Wsap(&a[j + 1], &a[j]);}}//如果flang==1那就说明这个数组已经有序就可以直接终止循环提高效率//防止出现 9 1 2 3 4 5 6 7 8 这种情况可以提升代码的效率if (flang == 1){break;}}
}

2.选择排序

图解

代码
// 选择排序
void SelectSort(int* a, int n)
{int min = 0;for (int j = 0; j < n; j++){min = j;for (int i = j; i < n; i++){if (a[i] < a[min]){min = i;}}Wsap(&a[j], &a[min]);}
}
//优化算法
void SelectSortpro(int* a, int n)
{int min = 0,max = 0;//用begin和end来控制数组的左右两边int begin = 0, end = n - 1;while (begin < end){for (int i = begin; i <= end; i++){if (a[i] < a[min]){min = i;}if (a[i] > a[max]){max = i;}}Wsap(&a[begin], &a[min]);if (a[min] > a[max]){max = min;}Wsap(&a[end], &a[max]);//每次遍历之后因为已经将此次遍历的最小和最大放到了两边所以需要缩小区间begin++;end--;}
}

3.插入排序

        首先要将数组分为已排序和未排序两个部分,一般需要从第二个元素开始因为第一个元素只有一个已经有序了。

图解

代码
// 插入排序
void InsertSort(int* a, int n)
{for (int i = 0; i < n-1; i++){int begin = 0, end = i;int key = a[end + 1];while (end >= begin){if (key < a[end]){a[end + 1] = a[end];end--;}//当a[end]>key时就停止循环这时end+1的位置是要插入key的位置else{break;}}//当数组的首元素位置是要插入key的时候end=-1所以end需要加一才是首元素的位置a[end + 1] = key;}
}

4.希尔排序

图解

代码
// 希尔排序
void ShellSort(int* a, int n)
{int gap = n;//当需要排序的内容过多时不再3组3组的分,需要数组长度不断除3来提升效率//除完加一是保证最后gap除3之后为零时gap= 1while (gap > 1){gap = gap/3+1;for (int i = 0; i < n - gap; i++)//i<n-gap 是保证数组不会越界{int end = i;int key = a[end + gap];while (end >= 0){if (key < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = key;}}
}

5.快排

  快排需要借助递归来实现快排的版本有很多图解中为大家一一叙述,快排的非递归需要借助栈来是实现这里就不过多的叙述了详细的思想见图解。

霍尔版本

   霍尔版本的快排,需要选择数组最左边的值做为key然后定义一个left和right分别指向最左边和最右边的元素然后right先走遍历数组找到比key小的数停止,left遍历找到比key大的停止然后left和right交换一直到left遇到right或者right遇到left停止,然后交换left或right和key的位置。由key分割数组的区间进行,递归操作。

图解

代码
//霍尔版本
int QuickSort1(int* a, int begin, int end)
{int key = a[begin], left = begin, right = end, key1 = begin;while (left < right){while (left < right && a[right] > key)//找比key小的数{right--;}while (left < right && a[left] <= key)//找比key大的数{left++;}Wsap(&a[left], &a[right]);}Wsap(&a[left], &a[key1]);return left;
}
//快排
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int key = QuickSort1(a, begin, end);QuickSort(a, begin, key - 1);QuickSort(a, key+1, end);
}

双指针法

  双指针法的也需要定义一个key指向数组最左边的值,再定义一个prev和cur,prev指向首元素的位置,cur的指向prev的下一个元素。 比较key和cur位置的值如果cur下于key那么就交换prev和cur位置的值如果cur大于key那么cur就加加,直到cur=right就结束。

代码
//双指针法
int QuickSort2(int* a, int left, int right)
{int prev = left, cur = left + 1, key = left;while (cur <= right){//++prev != cur 是为了防止prev和cur相等时交换可以提升效率if (a[cur] < a[key] && ++prev != cur){Wsap(&a[cur], &a[prev]);}else{cur++;}}Wsap(&a[key], &a[prev]);return prev;
}
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int key = QuickSort1(a, begin, end);QuickSort(a, begin, key - 1);QuickSort(a, key+1, end);
}

挖坑法

  首先定义key存储首元素,将首元素的位置看做一个坑定义变量ken,再定义一个begin,和end用来遍历数组,end先遍历找到比key小的元素就停止,然后让ken的位置等于end指向的元素再使end位置成为一个新的坑也就是使ken=end。然后begin开始遍历找比key大的数找到后停止再使ken的位置等于begin位置所指向的元素再使begin位置成为新的坑。直到begin和end相遇然后让begin和end指向的位置等于key。

代码
//挖坑法
int QuickSort3(int* a, int left, int right)
{int ken = left, key = a[left], begin = left, end = right;while (begin < end){while (a[end] >= key&& begin < end){end--;}a[ken] = a[end];ken = end;while (a[begin] <= key&& begin < end){begin++;}a[ken] = a[begin];ken = begin;}a[begin] = key;return begin;
}
//快排
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int key = QuickSort3(a, begin, end);QuickSort(a, begin, key - 1);QuickSort(a, key+1, end);
}

快排的优化

三数取中和小区间优化

代码
//三数取中
int GetMid(int left, int mid, int end)
{if (left > mid){if (end > left)//end>left>mid{return left;}else if (mid > end){return mid;}else{return end;}}else//mid>left{if (end > mid)//end>mid>left{return mid;}else if (left > end)//mid>left>end{return left;}else{return end;}}
}
//快排
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}if (end - begin + 1 <= 10){InsertSort(a, end - begin + 1);}else{int key = QuickSort3(a, begin, end);QuickSort(a, begin, key - 1);QuickSort(a, key + 1, end);}
}

6.归并排序

递归版本

  归并的本质是分组,将数组分成两份一份是有序的另一份也是有序的,然后创建数组tmp从两份有序的数首元素开始遍历谁小谁就尾插到tmp数组中,直到两份数组都没有元素。将tmp数组中的内容拷贝到原数组中。

代码
//归并排序
void _MergeSort(int* a, int* tmp, int left, int right)
{	if (left == right){return;}int mid = (right + left) / 2;_MergeSort(a, tmp, left, mid);_MergeSort(a, tmp, mid+1, right);int begin1 = left, begin2 = mid+1, end1 = mid, end2 = right;int j = 0;while (begin1 <= end1 && begin2 <= end2){//谁小谁就尾插到tmp中if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}//当出现6 7 8 9,2 3 4 5时6大于第二份中的所有数时//我们需要将第一份剩余是数组继续插入到tmp中while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}//每次递归都要拷贝一次因为本质是对a中的数据排序但是现在我们是在tmp使其有序//所以每次排序完都要拷贝回去使a中也有序memcpy(a+left, tmp, (right - left + 1)*sizeof(int));
}
//归并排序
void MergeSort(int* a, int n)
{//创建数组tmpint* tmp = malloc(sizeof(int) * n+1);if (tmp == NULL){perror("tmp fail:");return;}_MergeSort(a, tmp, 0, n);
}

非递归版本 

        当递归的层度太深的话就会导致栈溢出的分险,所以我们需要尝试不借用递归实现归并排序。归并的本质是对数组进行分组比较,最开始的时候是每组有一个元素然后每相邻的两个组进行比较。1X1归并2X2归并4X4归并直到数组有序(当然也会出现不能均匀分割的情况,但是3X4依旧可以归并)。归并的难点在于怎么样去控制下标进行分组,首先对数组进行1X1的分组定义变量gap=1(gap组),进行遍历数组相邻的两组进行比较,小的就尾插到copy数组中,然后再将已经有序的部分拷贝会原数组中这是一次循环,在这个循坏外再加上一次循环用来控制每组元素的个数直到整个数组有序。

代码
//归并非递归
void MergeSortNOT(int* a, int n)
{//创建coap数组用于拷贝int* copy = (int*)malloc(sizeof(int)*(n+1));if (copy==NULL){perror("copy fail:");return;}int gap = 1;//组数while (gap < n){for (int i = 0; i < n; i += 2 * gap){//定义变量分割区间int begin1 = i, end1 = i + gap - 1, begin2 = i + gap, end2 = i + 2 * gap - 1;//printf("[%d %d] [%d %d]", begin1, end1, begin2, end2);//防止越界情况的发生if (end1 > n){break;}if (end2 > n){end2 = n - 1;}int j = 0;while (begin1 <= end1 && begin2 <= end2){//谁小谁就尾插到tmp中if (a[begin1] <= a[begin2]){copy[j++] = a[begin1++];}else{copy[j++] = a[begin2++];}}while (begin1 <= end1){copy[j++] = a[begin1++];}while (begin2 <= end2){copy[j++] = a[begin2++];}memcpy(a+i, copy, (end2-i+1) * sizeof(int));}gap*=2;printf("\n");}
}

7.计数排序

  计数排序是创建一个数组count用来记录a数组中元素的出现的个数,然后通过数组下标的自然有序使a数组中的元素出现在正确的位置上,使a有序。

代码
//计数有序
void CountSort(int* a, int n)
{//首先找出数组中的最大,最小值int max = a[0], min = a[0];for (int i = 0; i < n; i++){if (a[i] > max)max = a[i];if (a[i] < min)min = a[i];}//创建max-min+1个空间是为防止出现6 6 6 6 10的情况减少申请的内存空间int* count = calloc((max-min+1),sizeof(int));if(count==NULL){perror("count fail::");}for (int i = 0; i < n; i++){count[a[i] - min]++;}int b = 0;for (int j = 0; j < (max-min+1); j++){while (count[j]--){a[b++] = j + min;}}free(count);
}

总结

本篇章讲述了大部分的常用的排序,还有一个堆排将在二叉树中详细讲解。

希望大大多多指点。

记得三连哦!感谢!感谢!感谢!

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

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

相关文章

postman使用笔记

Postman 是一个广泛使用的 API 开发工具&#xff0c;它提供了一个用户友好的图形界面来发送 HTTP 请求、查看响应、组织测试用例和创建自动化测试。以下是一些基本的 Postman 使用教程&#xff0c;结合了搜索结果中的信息&#xff1a; 安装 Postman 访问 Postman 官方网站下载…

vue2 中如何使用 vuedraggable 库实现拖拽功能

1.通过 npm 或 yarn 安装 vuedraggable 库 npm install vuedraggableyarn add vuedraggable 2. 引入组件内部使用&#xff0c;以下代码是一个Demo&#xff0c;可直接复制粘贴演示 注意&#xff1a;因项目使用了 vant&#xff0c;需要安装 vant 才能正常运行 <template&g…

windows USB设备驱动开发-开发USB 设备端驱动

USB 设备是通过单个端口连接到计算机的外设&#xff0c;例如鼠标设备和键盘。 USB 客户端驱动程序是计算机上安装的软件&#xff0c;该软件与硬件通信以使设备正常运行。 如果设备属于 Microsoft 支持的设备类&#xff0c;Windows 会为该设备加载 Microsoft 提供的 USB 驱动程序…

简单分享下python封装

目录&#xff1a; 一、简介&#xff0c;什么是封装 二、封装的优点与好处 三、封装的示例 四、可封装的场景 一、简介&#xff0c;什么是封装 通俗理解&#xff1a;封装&#xff0c;简而言之&#xff0c;就是把数据&#xff08;变量&#xff09;和操作这些数据的方法&#xff0…

什么是低代码(Low Code)?全面解析国内十大低代码平台

什么是低代码&#xff08;Low Code&#xff09;&#xff1f;为什么低代码这么火&#xff1f;国内排名前十的低代码平台分别是哪些&#xff1f;低代码平台的操作方法&#xff1f;低代码的优缺点&#xff1f;以及低代码有哪些典型案例&#xff1f;本文集合本人5年来的低代码实践经…

Spring Boot与Kafka的集成应用

Spring Boot与Kafka的集成应用 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 引言 Kafka作为一款高性能、分布式的消息队列系统&#xff0c;与Spring Bo…

TongRDS2214手动部署版指引(by lqw+sy)

文章目录 前言准备工作单机版集群版哨兵版多个中心节点配置 前言 由于一些特殊原因&#xff08;例如服务器没有联网&#xff0c;没有办法直接更新和下载unzip指令&#xff0c;从而导致控制台版本安装节点之后&#xff0c;会报file not found的错误&#xff0c;或者使用不了rds…

1.什么是js?特点是什么?组成部分?

Js是一种直译式脚本语言&#xff0c;一种动态类型&#xff0c;弱类型&#xff0c;基于原型的高级语言。 直译式&#xff1a;js程序运行过程中直接编译成机器语言。 脚本语言&#xff1a;在程序运行过程中逐行进行解释说明&#xff0c;不需要预编译。 动态类型&#xff1a;js…

C++:静态函数的作用

在C中&#xff0c;静态函数&#xff08;static 函数&#xff09;的作用主要是限定该函数的可见性和链接性&#xff0c;而不是直接关联于函数的返回类型或参数列表&#xff08;尽管你提到了static int()这样的形式&#xff0c;这里的static是修饰函数本身的&#xff0c;而不是in…

(PC+WAP)高端大气的装修装潢公司网站模板

(PCWAP)高端大气的装修装潢公司网站模板PbootCMS内核开发的网站模板&#xff0c;该模板适用于装修公司网站、装潢公司网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b;(PCWAP)&#xff0c;同一个后台&#xff0c;数据即…

javascript Reflect.has作用

JavaScript中的Reflect.has()方法用于检查一个属性是否存在于对象中。它的作用类似于 in 运算符&#xff0c;但是作为函数形式提供&#xff0c;更适合在某些需要函数调用的上下文中使用&#xff0c;尤其是在函数式编程风格中。Reflect.has()方法接收两个参数&#xff1a; targ…

采集网关iGR-1700产品组成与集成

采集网关iGR-1700作为国瑞iGR-IMS数据综合管理系统的一个重要组成部分&#xff0c;其产品组成与集成主要体现在以下几个方面&#xff1a; 一、产品组成 iGR-1700数据采集网关主要用于生产数据的采集。具体而言&#xff0c;它能够&#xff1a; 1. 自动化提取数据&#xff1a;…

Pandas实战秘籍:轻松驾驭重复值与异常值的处理艺术,让数据清洗更高效!

1.导包 import numpy as np import pandas as pd2.删除重复行 def make_df(indexs,columns):data [[str(j)str(i) for j in columns] for i in indexs]df pd.DataFrame(datadata,indexindexs,columnscolumns)return df使用 duplicated() 函数检测重复的行 返回元素为布尔类…

2025年大数据专业毕设必过选题

一、Hive数据仓库相关选题 基于hive的太原共享单车数据分析与实现&#xff08;难度系数&#xff1a;⭐⭐⭐&#xff09; 基于Hive的外汇交易数据分析与研究&#xff08;难度系数&#xff1a;⭐⭐&#xff09; 基于hive的垃圾分类大数据可视化&#xff08;难度系数&#xff1…

如何下载huggingface仓库里某一个文件

如何下载huggingface仓库里某一个文件&#xff1a; https://huggingface.co/PixArt-alpha/PixArt-Sigma/tree/main 直接用命令&#xff1a; wget https://huggingface.co/PixArt-alpha/PixArt-Sigma/resolve/main/PixArt-Sigma-XL-2-2K-MS.pth

什么是浏览器指纹识别?

一段时间以来&#xff0c;网络隐私一直是一个持续存在的问题。如何保持匿名、保护数据并使其真正成为隐私&#xff1f;我们大多数人都使用 VPN 和代理网络来使我们的虚拟生活更加安全。这是一个不错的想法&#xff0c;但它真的有用吗&#xff1f; 是的&#xff0c;在一定程度上…

信息学奥赛初赛天天练-42-CSP-J2020基础题-变量地址、编译器、逻辑运算、逻辑与运算、逻辑或运算、冒泡排序、递归应用

PDF文档公众号回复关键字:20240702 2020 CSP-J 选择题 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1.在内存储器中每个存储单元都被赋予一个唯一的序号&#xff0c;称为&#xff08; &#xff0…

VUE项目安全漏洞扫描和修复

npm audit 1、npm audit是npm 6 新增的一个命令,可以允许开发人员分析复杂的代码并查明特定的漏洞。 2、npm audit名称执行&#xff0c;需要包package.json和package-lock.json文件。它是通过分析 package-lock.json 文件&#xff0c;继而扫描我们的包分析是否包含漏洞的。 …

Polygon链的对接及使用

Polygon&#xff08;前身为Matic Network&#xff09;是一个基于以太坊的侧链&#xff0c;旨在解决以太坊网络拥堵和高昂 gas 费的问题。Polygon 使用侧链技术将交易从以太坊主网转移到自己的侧链上&#xff0c;从而提高交易速度和降低 gas 费。北京木奇移动技术有限公司&#…

Python语言接入关键词搜索商品api疑点解析

接入关键词搜索商品API通常需要以下步骤&#xff1a; 了解API文档&#xff1a;首先&#xff0c;你需要阅读API的文档&#xff0c;了解API的基本功能、请求方式&#xff08;GET、POST等&#xff09;、请求参数、返回数据格式等信息。 安装必要的库&#xff1a;根据API的要求&am…