排序算法见解(2)

1.快速排序

1.1基本思想:

快速排序是通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

1.2基本思路:

(1)选择基准:从待排序的序列中选取一个元素作为基准,这个元素可以是序列的第一个、最后一个、中间的一个或者通过某种方式计算得到的值等。

(2)分区:重新排列序列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于序列的中间位置。这个称为分区操作。

(3)递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。

1.3图解过程:

1.3.1hoare版本:

(左边找大,右边找小(先从右边开始找),找到后交换两个位置的值,直到 left=right ,再把 tmp 位置的值与 left 位置的值交换)

动图展示:

这里 tmp 值从右边选取,所以从左先开始找,效果其实一样的。

1.3.2挖坑法:

(1)选 left 做 tmp(tmp 是单趟排序后能排到最后该待的位置的数据,left 同时也作为第一个坑)
(2)right 开始找,right 遇到比 tmp 大或相等的就往左边走,遇到比 tmp 小的就停下,然后将right 赋值给 left(left = right)(填 left 坑),right 则成为了新的坑,进行第三步。(若 right 超过了 left,直接进行第四步)
(3)left 开始找,left 遇到比 tmp 小或相等的就往右边走,遇到比 tmp 大的就停下,然后将 left 赋值给 right(right = left)(填 right 坑),left 则成为了新的坑,进行第二步。(若 left 超过了right,直接进行第四步)
(4)将 tmp 赋值给 left。

动图展示:

这个从右开始取 tmp 值,所以从左先开始找,效果一样。

1.3.3前后指针:

具体思路:先选定左边第一个为 tmp ,同时设定 left 位置为 prev,prev 的后一个位置为 cur,从a[cur] 开始和 tmp 比较,如果 a[cur] 比 tmp 小,就先将 prev++,再让 a[cur] 和 a[prev] 交换,然后 cur++,如果 a[cur] 比 tmp大,那么就不改变 prev,也不用交换,只对 cur++,以此类推,直到cur>right 就结束,最后将 a[prev] 和 tmp 交换就完成了一趟快排。

动图展示:

1.4代码实现:

1.4.1hoare版本:
// 快速排序hoare版本
int PartSort1(int* arr, int left, int right)
{//优化1:三数取中int mid = chose_middle(arr, left, right);Swap(&arr[left], &arr[mid]);//交换两个位置值的函数int key = left;int begin = left;int end = right;while (begin < end){//右边找小while (begin < end && arr[end] >= arr[key]){end--;}//左边找大while (begin < end && arr[begin] <= arr[key]){begin++;}Swap(&arr[begin], &arr[end]);//交换两个位置值的函数}Swap(&arr[key], &arr[begin]);//交换两个位置值的函数return begin;
}void Quick_sort(int* arr, int left, int right)
{// 快速排序hoare版本//int key = PartSort1(arr, left, right);Quick_sort(arr, left, key - 1);Quick_sort(arr, key + 1, right);
}
1.4.2挖坑法:
// 快速排序挖坑法
int PartSort2(int* arr, int left, int right)
{//优化1:三数取中//int mid = chose_middle(arr, left, right);//Swap(&arr[left], &arr[mid]);int pit = left;int key = arr[left];int begin = left;int end = right;while (begin < end){while (arr[end] > key && begin < end){end--;}Swap(&arr[end], &arr[pit]);pit = end;while (arr[begin] < key && begin < end){begin++;}Swap(&arr[begin], &arr[pit]);pit = begin;Print_arr(arr, 9);printf("\n");}Swap(&arr[pit], &key);return begin;
}void Quick_sort(int* arr, int left, int right)
{// 快速排序挖坑法int key = PartSort2(arr, left, right);Quick_sort(arr, left, key - 1);Quick_sort(arr, key + 1, right);
}
1.4.3前后指针:
// 快速排序前后指针法
int PartSort3(int* arr, int left, int right)
{//优化1:三数取中int mid = chose_middle(arr, left, right);Swap(&arr[left], &arr[mid]);int key = left;int prev = left;int cur = prev + 1;while (cur <= right){if (arr[cur] < arr[key] && ++prev != cur)Swap(&arr[cur], &arr[prev]);cur++;}Swap(&arr[prev], &arr[key]);return prev;
}void Quick_sort(int* arr, int left, int right)
{// 快速排序前后指针法int key = PartSort3(arr, left, right);Quick_sort(arr, left, key - 1);Quick_sort(arr, key + 1, right);
}

2.计数排序

2.1基本思想:

计数排序在于将输入的数据值转化为键存储在额外开辟的数组空间中。用新数组对应下标位置的值来表示该数在原数组出现的次数,计数排序要求输入的数据必须是有确定范围的整数。

2.2基本思路:

 (1)找出待排序数组中的最大值和最小值:这是为了确定计数数组(或称为桶)的大小和范围。计数数组的大小通常是最大值与最小值之差加1(如果包含负数,则需要调整以包含所有可能的值)。

 (2)创建计数数组并初始化:根据步骤1确定的范围,创建一个新的数组,用于记录每个元素在原数组中出现的次数。这个数组的所有元素初始化为0。

(3)统计每个元素的出现次数:遍历原数组,对于每个元素,将其值作为计数数组的索引(如果元素是负数或范围超出常规,则需要进行适当的调整,如加上一个偏移量),并将该索引位置上的值加1。这样,计数数组的每个位置就记录了原数组中对应元素的出现次数。

(4)对计数数组进行累加(可选,但有助于后续排序):从计数数组的第一个元素开始,向后遍历,将每个元素的值更新为当前元素与前一个元素之和。这一步是为了确定每个元素在排序后数组中的位置。例如,如果某个元素在原数组中出现了n次,并且它是第k个不同的元素,那么它在排序后的数组中应该占据从第k个位置开始的n个连续位置

(5)根据计数数组重构原数组:这是排序的最后一步。从后向前遍历原数组(或者从后向前遍历计数数组,同时遍历一个指针指向排序后数组的末尾),对于原数组中的每个元素,找到它在计数数组中的索引,并根据计数数组的值(或者累加后的值)确定它在排序后数组中的位置,然后将该元素放到排序后数组的相应位置上,并减少计数数组中对应索引的值(如果进行了累加)。这个过程可能需要从后向前遍历原数组,以确保稳定性(即相等元素的相对顺序不变)。

(6)处理负数或特殊范围:如果原数组中包含负数或元素范围超出了常规整数范围,可能需要在步骤1和步骤2中进行适当的调整,如加上一个偏移量,以确保所有元素都能被正确地映射到计数数组的索引上。

2.3图解过程:

  

动图展示:

  

2.4代码实现:

// 计数排序
void CountSort(int* arr, int n)
{int min = arr[0];int max = arr[0];for (int i = 1; i < n; i++){if (arr[i] < min){min = arr[i];}if (arr[i] > max){max = arr[i];}}//创建一个数组来计算(相对)下标出现的次数int count = max - min + 1;//calloc会自动初始化数组为0//int* tmp = (int*)calloc(count,sizeof(int));//if (tmp == NULL)//{//	perror("calloc error");//	return;//}//使用malloc时需要初始化数组int* tmp = (int*)malloc(count * sizeof(int));if (tmp == NULL){perror("malloc error");return;}for (int i = 0; i < count; i++){tmp[i] = 0;}//把原数组映射到开辟的数组中for (int i = 0; i < n; i++){tmp[arr[i] - min]++;}//排序int j = 0;for (int i = 0; i < count; i++){while (tmp[i]--){arr[j] = i + min;j++;}}free(tmp);tmp = NULL;
}

3.归并排序

3.1基本思想:

归并排序基本思想是将一个数组分成两半,对每半部分递归地应用归并排序,然后将排序好的两半合并在一起。这个过程一直递归进行,直到数组被分割成只包含一个元素的子数组,这些子数组自然就是排序好的。然后,算法开始合并这些子数组,直到合并成一个完整的排序好的数组。

3.2基本思路:

(1)分解:将数组分解成两个较小的子数组,直到子数组的大小为1。

(2)递归进行排序并合并:递归地对子数组进行归并排序,并将已排序的子数组合并成一个大的有序数组,直到合并为1个完整的数组

3.3图解过程:

3.4代码实现:

void _Merge_sort(int* arr, int* arr1, int left, int right)
{if (left >= right){return;}//划分区间int key = (left + right) / 2;//[left,key],[key+1,right]_Merge_sort(arr, arr1, left, key);_Merge_sort(arr, arr1, key + 1, right);//归并int left1 = left;int right1 = key;int left2 = key + 1;int right2 = right;int i = left;while (left1 <= right1 && left2 <= right2){if (arr[left1] < arr[left2]){arr1[i] = arr[left1];i++;left1++;}else{arr1[i] = arr[left2];i++;left2++;}}while (left1 <= right1){arr1[i] = arr[left1];i++;left1++;}while (left2 <= right2){arr1[i] = arr[left2];i++;left2++;}//交换完一次拷贝一次memcpy(arr + left, arr1 + left, (right - left + 1) * sizeof(int));
}//归并排序(递归)
void Merge_sort(int* arr, int n)
{int* arr1 = (int*)malloc(sizeof(int) * n);if (arr1==NULL){perror("malloc error");return;}_Merge_sort(arr, arr1, 0, n - 1);free(arr1);arr1 = NULL;
}

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

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

相关文章

解决Springboot项目Maven下载依赖速度慢的问题

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

智能客服系统:提升客户体验与企业效率的革命性工具

在当今数字化时代&#xff0c;企业与客户之间的互动方式正在迅速改变。智能客服系统作为一种新兴技术&#xff0c;不仅在提高客户满意度方面发挥着重要作用&#xff0c;还能够大大提高企业的运营效率。本文将详细探讨智能客服系统的工作原理、优势、实施步骤以及未来发展趋势。…

AI的未来已来:GPT-4商业应用带来的无限可能

随着人工智能技术的快速发展&#xff0c;OpenAI于2023年3月15日发布了多模态预训练大模型GPT-4&#xff0c;这一里程碑式的进步不仅提升了AI的语言处理能力&#xff0c;还拓展了其应用范围。本文将深入探讨GPT-4的技术进步、商业化进程、用户体验改善、伦理和社会影响&#xff…

vue项目安装pnpm和无法加载pnpm,已解决

vue3安装pnpm命令&#xff1a; 1.提升依赖安装速度&#xff1a;npm config set registry https://registry.npmjs.org 2.安装pnpm:npm install -g pnpm 3.安装pnpm依赖&#xff1a;pnpm install 4…windows电脑&#xff0c;无法安装pnpm&#xff0c;pnpm install命令&#xff0…

Java三大器之拦截器(Interceptor)的实现原理及代码示例

1&#xff0c;拦截器的概念 java里的拦截器是动态拦截Action调用的对象&#xff0c;它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码&#xff0c;也可以在一个Action执行前阻止其执行&#xff0c;同时也提供了一种可以提取Action中可重用部分代码的方式。在AO…

Oracle迁移至openGauss的工具:ora2op的安装配置

目录 前言 1. ora2op的下载 1.1 下载地址 1.2 ora2op 介绍 2. ora2op的安装 2.1 安装perl的依赖包 2.2 安装连接Oracle数据库的模块 2.3 安装ora2op 2.4 安装连接openGauss数据库的模块 前言 本工具是使用perl&#xff0c;在安装时会遇到各种问题&#xff0c;解决方式…

如何在知行之桥上通过业务单号查找原始报文?

在知行之桥中接收或发送的数据通常是EDI原始报文&#xff0c;知行之桥会对EDI原始报文进行格式转换&#xff0c;以方便用户后端系统的处理。因此&#xff0c;一般情况下&#xff0c;用户看到的都是转换后的数据结构&#xff0c;例如Json、XML或Excel等&#xff0c;无需直接查看…

2024年第十五届蓝桥杯图形化省赛真题分享包含答案

Scratch初级:8月24日9:30-11:00 Scratch中级:8月24日14:00-15:30 Python:8月25日9:30-11:00 C++:8月25日14:00-15:30 这次考了哪些内容呢,我们来大概看看(编程题没有答案,编程题有,大家可以评论群留言单选题的答案): <

AT LINE-SELECTION

Syntax 语法 AT LINE-SELECTION. Effect 作用 This statement defines an event block whose event is triggered by the ABAP runtime environment during the display of a screen list - provided the scren cursor is on a list line and you select a function using t…

【数据结构】总结二叉树的概念以及存储结构

目录 1. 树的概念及结构 1.1 树的名词定义 1.2 树的表示 2. 二叉树的概念及结构 2.1 二叉树的概念 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树的存储结构 2.3.1 顺序存储 2.3.2 链式存储 3. 选择题 1. 树的概念及结构 1.1 树的名词定义 1. 节…

太阳方向角/高度角/赤纬角/太阳时角/真平太阳时差/理论计算方法(matlab)

1. 理论学习 方向角&#xff0c;高度角计算公式 如图&#xff0c;直观地描述了方位角(圆盘上红色夹角)与高度角(黄色线与圆盘的夹角) 赤纬角计算公式 地球赤道平面与太阳和地球中心的连线之间的夹角 如图所示&#xff0c;23度那个. 时角计算公式 太阳时角是指日面中心的时角…

SAP BW/BPC:实现自动执行BPC跑包程序

作者 idan lian 如需转载备注出处 如果对你有帮助&#xff0c;请点赞收藏~~~ 用途&#xff1a;创建程序&#xff0c;跑BPC包&#xff0c;把数据从BW应用层跑到BPC,程序可放到处理链或自动作业中&#xff0c;实现定时跑包。 1.步骤 首先需要BPC顾问创建一个他们手动执行的包…

在 Facebook 上投放广告需要多少钱?

Facebook 拥有 23.2 亿的月活跃用户&#xff0c;用户体量非常庞大&#xff0c;你的目标群体出现在社交媒体平台上的可能性非常高&#xff0c;所以企业会选择在Facebook 上投放广告。很多朋友想入局&#xff0c;但总是在思考Facebook 推广到底要花多少钱才能有效&#xff1f;如果…

NoSql数据库 Redis集群详解

目录 一、NoSql数据库简介 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 1.2 为什么还要用 NoSQL 数据库呢&#xff1f; 1.3 RDBMS和NOSQL的特点及优缺点&#xff1a; 二 Remote Dictionary Server 简介&#xff08;redis&#xff09; 2.1 什么是redis …

【数据结构】队列(Queue)

目录 队列概念 ​方法 队列模拟实现 链表实现队列 入队列 出队列 获取队头元素 数组实现队列 入队列 出队列 返回头队列 返回尾队列 完整代码 双链表实现队列 数组实现队列&#xff08;设计循环队列&#xff09; 队列概念 队列&#xff1a;只允许在一段进行插入…

悬浮翻译软件有哪些?试试这些利器

在观看外国电影或电视剧的奇幻旅程中&#xff0c;面对字幕如流星般划过屏幕&#xff0c;是否渴望能即时捕捉每一个细微的情感涟漪与幽默火花&#xff0c;让体验更加完整无憾&#xff1f; 此刻&#xff0c;无需再为语言障碍而烦恼&#xff01;悬浮翻译器电脑版作为你贴心的跨文…

TPM管理培训究竟需要多少天?完整攻略在此

在探讨TPM管理培训究竟需要多少天这一核心问题时&#xff0c;我们首先需要明确TPM管理的核心理念、目标及其在企业运营中的重要性。TPM不仅仅是一套设备维护的方法论&#xff0c;更是一种以提升设备综合效率、改善企业体质为目标的管理哲学。它强调全员参与、全系统管理和全效率…

k8s-使用Network Policies实现网络隔离

一、需求 Kubernetes 的命名空间主要用于组织和隔离资源&#xff0c;但默认情况下&#xff0c;不同命名空间中的 Pod 之间是可以相互通信的。为了实现更严格的网络隔离&#xff0c;同一套k8s需要根据不同的命名空间进行网络环境隔离&#xff0c;例如开发&#xff08;dev01&…

SRE 必备知识 - Kafka 探秘之零拷贝技术

如果你了解过 Kafka&#xff0c;那么它用到的一个性能优化技术可能会引起你的注意 -- 操作系统的零拷贝&#xff08;zero-copy&#xff09;优化。 零拷贝操作可以避免对数据的非必要拷贝&#xff0c;当然&#xff0c;并非是说完全没有拷贝。 在 Kafka 的场景下&#xff0c;操作…

发布npm包到GitLab教程

之前在研究如何搭建UI组件库&#xff08;内部使用&#xff09;&#xff0c;其中重要的一步就是发布npm包到GitLab。中间踩了很多坑&#xff0c;在这里记录一下整个流程方便大家快速上手。不足之处欢迎指出&#x1f64f; 1. 获取Token 在gitlab中打开access tokens申请页面&am…