几种排序的实现

直接插入排序

直接插入排序是一种简单的插入排序法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

实际中我们玩扑克牌时,就用了插入排序的思想:
就是,第一次摸牌我们把它放在第一张,第二次就和第一张比较,比它大就放在他的后面,否则就放在他的前面,摸第三张的时候先和后面大的一张牌开始比较,依次向前。
在这里插入图片描述
总结来说就是:
当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

下面我们对直接插入排序进行代码的实现
插入排序很简单
我们将第二个元素开始向后遍历,i=1,令end=i-1,并且保存a[i]的值
当a[end]大于此前i下标的元素的值时,将其调整,将end位置的值移动到end后面一个位置,同时end–,如果是小于的,那就直接跳出循环,就代表了前面的所有值都是升序的

void insertsort(int* a, int n)
{for (int i = 1; i < n; i++){int end = i - 1;int temp = a[i];while (end >= 0){if (a[end] > temp){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = temp;}
}

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。
在这里插入图片描述
下面为代码实现:
我们开始令gap为n的三分之一+1,加一是因为gap不能等于0,一般情况下gap是数组长度的三分之一是比较合适的
后面的逻辑就和插入排序差不多了
后面的for循环时各个分组的数字同时进行排序

void shellsort(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int temp = a[end + gap];while (end >= 0){if (a[end] > a[temp]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = temp;}}
}

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就
    会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定

选择排序

选择排序的思想就是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
代码实现:
第一次找出最大值最小值的下标,然后放在首尾
交换值,然后begin和end分别被前进和后退

void SelectSort(int* a, int n)
{assert(a);int begin = 0, end = n - 1;while (begin < end){int min = begin, max = begin;for (int i = begin; i <= end; i++){if (a[i] >= a[max])max = i;if (a[i] < a[min])min = i;}Swap(&a[begin], &a[min]);//如果最大的位置在begin位置//说明min是和最大的交换位置//这个时候max的位置就发生了变换//max变到了min的位置//所以要更新max的位置if (begin == max)max = min;Swap(&a[end], &a[max]);++begin;--end;}

快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:
任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

总结下来就是:
我们将小于中间位置的值的放在左边,大于的放在右边,然后再对左边进行一样的划分,右边也是,用递归实现即可

在实现快排前我们先定义一个找中间下标的函数:
也就是常说的三数取中,有利于更好更快得完成快排

int getmidindex(int* a, int left, int right)
{int midi = (left + right) / 2;if (a[left] < a[midi]){if (a[midi] < a[right]){return midi;}else if (a[left] < a[right]){return right;}elsereturn left;}else//a[left] >=a[midi]{if (a[midi] > a[right]){return midi;}else if (a[left] > a[right]){return right;}elsereturn left;}
}

快速排序一共有三种方法:

  1. hoare版本
    这种方法我们统称为霍尔法:
    就是我们将数组的第一个元素的值赋值给key,然后分别从左右 开始遍历,右边先走,一旦找到比key小的就停下来,然后左边开始走,左边找到大的就停下来,然后两个位置的值互换,知道二者相遇,将key位置的值和他们相遇位置的值交换,最后返回这个位置的下标
    在这里插入图片描述
    代码实现:
int partsort1(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int keyi = left;while (left < right){while (left < right && a[right] >= a[keyi]){right--;}while (left < right && a[left] <= a[keyi]){left++;}swap(&a[left], &a[right]);}swap(&a[keyi], &a[left]);return left;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}
  1. 挖坑法版本
    挖坑法就是把第一个元素存放到临时变量key中,形成一个坑位,然后右边先走,右边遇到比key小的,就把它给此位置的值放入坑位中,此位置就是新的坑位,然后左边开始找大的,如果出现大的就把值填入坑位中,然后此位置就是新的坑位,一直到left和right相遇时,就把挖出来的key值填入坑位中,并且返回这个坑位的下标
    在这里插入图片描述
    过程如下图:
    最后省略了一部分,依次类推即可
    在这里插入图片描述

代码实现如下:

int partsort2(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int hole = left;int key = a[left];while (left < right){while (left < right && a[right] >= key){right--;}a[hole] = a[right];hole = right;while (left < right && a[left] <= key){left++;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}
  1. 前后指针版本
    我们首先令第一个位置的下标为prev,他的下一个位置为cur,并且记录第一个位置的值为key
    然后cur先后遍历,当cur遇到小于key的值时,将prev和cur位置的值交换,并且再prev+1不等于cur的情况下prev进行+1操作(如果是等于的话就是自己和自己交换,没有什么意义),同时cur++,当遍历完成时,最后交换prev位置的值和key的值,返回prev位置的下标
    在这里插入图片描述
    遍历过程如下:
    在这里插入图片描述

代码实现:

int partsort3(int* a, int left, int right)
{int midi = getmidindex(a, left, right);swap(&a[left], &a[midi]);int prev = left;int cur = left + 1;int keyi = left;while (cur <= right){if (a[keyi] > a[cur] && ++prev != cur){swap(&a[prev] ,&a[cur]);}cur++;}swap(&a[prev] ,&a[keyi]);keyi = prev;return keyi;
}
void quicksort(int* a, int begin, int end)
{if (begin >= end)return;int midi = partsort1(a, begin, end);quicksort(a, begin, midi - 1);quicksort(a, midi + 1, end);
}

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
他的大概步骤如下:
在这里插入图片描述
归并排序的递归很简单:
就是将区间逐一划分
并且得开辟一块新的空间,最后将temp直接全部memcpy到目标空间a中

void _mergesort(int* a, int begin, int end, int* temp)
{if (begin >= end)return;int midi = (begin + end) / 2;_mergesort(a,begin, midi,temp);_mergesort(a,midi + 1, end,temp);int begin1 = begin;int begin2 = midi + 1;int end1 = midi;int end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){temp[i++] = a[begin1++];}else{temp[i++] = a[begin2++];}}while (begin1 <= end1){temp[i++] = a[begin1++];}while (begin2 <= end2){temp[i++] = a[begin2++];}memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
void mergesort(int* a, int n)
{int* temp = (int*)malloc(sizeof(int)*n);_mergesort(a, 0, n-1, temp);free(temp);
}

非递归就有点难了:

void mergesortnonr(int* a, int n)
{int* temp =(int*)malloc(sizeof(int) * n);if (temp == NULL){perror("malloc");}int gap = 1;while (gap < n){int j = 0;for (int i = 0; i < n; i += 2*gap){int begin1 = i;int begin2 = i + gap;int end1 = i + gap-1;int end2 = i + 2 * gap - 1;if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;//修正}while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){temp[j++] = a[begin1++];}else{temp[j++] = a[begin2++];}}while (begin1 <= end1){temp[j++] = a[begin1++];}while (begin2 <= end2){temp[j++] = a[begin2++];}//每归并完一组就拷贝一组memcpy(a + i, temp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}free(temp);
}

归并排序的特性总结:

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N)
  4. 稳定性:稳定

计数排序

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中
    其实计数排序就是用到了数组的映射,当数组元素过多时就不适用了,但是效率很高:
void countsort(int* a, int n)
{int i = 0;int j = 0;int max = a[0];int min = a[0];for (i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * n);memset(count, 0, sizeof(int) * range);for (i = 0; i < n; i++){count[a[i] - min]++;}int k = 0;for (j = 0; j < range; j++){while (count[j]--){a[k++] = j + min;}}
}

计数排序的特性总结:

  1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
  2. 时间复杂度:O(MAX(N,范围))
  3. 空间复杂度:O(范围)

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

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

相关文章

交付《啤酒游戏经营决策沙盘》的项目

感谢首富客户连续两年的邀请&#xff0c;交付《啤酒游戏经营决策沙盘》的项目&#xff0c;下周一JSTO首席学习官Luna想让我分享下系统思考与投资理财&#xff0c;想到曾经看过的一本书《深度思维》&#xff0c;看到一些结构来预判未来。不仅仅可以应用在企业经营和组织发展上&a…

Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21) 的一个解

关于Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21)的一个解 问题复现 <button onclick"deleteItem(${order.id},hire,"Orders")" >delete</button>报错 原因 函数参数的双引号和外面的双引号混淆了&#xff0c;改成…

【vuex】

vuex 1 理解vuex1.1 vuex是什么1.2 什么时候使用vuex1.3 vuex工作原理图1.4 搭建vuex环境1.5 求和案例1.5.1 vue方式1.5.2 vuex方式 2 vuex核心概念和API2.1 getters配置项2.2 四个map方法的使用2.2.1 mapState方法2.2.2 mapGetters方法2.2.3 mapActions方法2.2.4 mapMutations…

“HALCON error #2454:HALCON handle was already cleared in operator set_draw“

分析&#xff1a;错误提示是窗口句柄已经被删除&#xff0c;这是因为前边的一句 HOperatorSet.CloseWindow(hWindowControl1.HalconWindow); 关掉了窗口&#xff0c;屏蔽或删除即可。

UDS诊断 10服务的肯定响应码后面跟着一串数据的含义,以及诊断报文格式定义介绍

一、首先看一下10服务的请求报文和肯定响应报文格式 a.诊断仪发送的请求报文格式 b.ECU回复的肯定响应报文格式 c.肯定响应报文中参数定义 二、例程数据解析 a.例程数据 0.000000 1 725 Tx d 8 02 10 03 00 00 00 00 00 0.000806 1 7A5 Rx d 8 06 50 03 00 32 01 F4 CC …

Brushed DC mtr--PIC

PIC use brushed DC mtr fundmental. Low-Cost Bidirectional Brushed DC Motor Control Using the PIC16F684 DC mtr & encoder

《opencv实用探索·八》图像模糊之均值滤波、高斯滤波的简单理解

1、前言 什么是噪声&#xff1f; 该像素与周围像素的差别非常大&#xff0c;导致从视觉上就能看出该像素无法与周围像素组成可识别的图像信息&#xff0c;降低了整个图像的质量。这种“格格不入”的像素就被称为图像的噪声。如果图像中的噪声都是随机的纯黑像素或者纯白像素&am…

TailwindCSS 如何设置 placeholder 的样式

前言 placeholder 在前端多用于 input、textarea 等任何输入或者文本区域的标签&#xff0c;它用户在用户输入内容之前显示一些提示。浏览器自带的 placeholder 样式可能不符合设计规范&#xff0c;此时就需要通过 css 进行样式美化。 当项目中使用 TailwindCSS 处理样式时&a…

JAVA程序如何打jar和war问题解决

背景: 近期研究一个代码审计工具 需要jar包 jar太多了 可以将jar 打成war包 首先看下程序目录结构 pom.xml文件内容 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"ht…

Android12 WIFI 无法提供互联网连接

平台 RK3588 Android 12 问题描述 ConnectivityService是Android系统中负责处理网络连接的服务之一。它负责管理设备的网络连接状态&#xff0c;包括Wi-Fi、移动数据、蓝牙等。 在Android系统中&#xff0c;ConnectivityService提供了一些关键功能&#xff0c;包括但不限于…

Spring Boot Async:从入门到精通,原理详解与最佳实践

Spring Boot 的异步功能&#xff08;Async&#xff09;允许我们将某些任务异步执行&#xff0c;而不会阻塞主线程。这对于处理耗时的操作非常有用&#xff0c;如发送电子邮件、生成报表、调用外部 API 等。通过异步处理&#xff0c;我们可以释放主线程&#xff0c;让它继续处理…

低多边形游戏风格3D模型纹理贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

区块链实验室(29) - 关闭或删除FISCO日志

1. FISCO日志 缺省情况下&#xff0c;FISCO启动日志模块&#xff0c;日志记录的位置在节点目录中。以FISCO自带案例为例&#xff0c;4节点的FISCO网络&#xff0c;24个区块产生的日志大小&#xff0c;见下图所示。 2.关闭日志模块 当节点数量增大&#xff0c;区块高度增大时&…

【EI会议征稿中】第三届信号处理与通信安全国际学术会议(ICSPCS 2024)

第三届信号处理与通信安全国际学术会议&#xff08;ICSPCS 2024&#xff09; 2024 3rd International Conference on Signal Processing and Communication Security 信号处理和通信安全是现代信息技术应用的重要领域&#xff0c;近年来这两个领域的研究相互交叉促进&#xf…

InsCode:CSDN的创新代码分享平台,融合AI技术提升编程体验

InsCode AI Chat 能够让你通过聊天的方式帮你优化代码。 一&#xff1a;前言 InsCode 是csdn推出的一个代码分享网站 二、使用 AI 辅助完成代码 下面我们就从实践出发&#xff0c;基于 InsCode 的 AI辅助编程&#xff0c;写Python实现的计算器。 1.基于模板创建项目 这里我…

行业地位失守,业绩持续失速,科沃斯的故事不好讲

特劳特曾在《定位》一书中提到&#xff0c;为了在容量有限的消费者心智中占据品类&#xff0c;品牌最好的差异化就是成为第一&#xff0c;做品类领导者或开创者&#xff0c;销量遥遥领先&#xff1b;其次分化品类&#xff0c;做到细分品类的唯一&#xff0c;即细分品类的第一。…

Elon Musk艾隆・马斯克的聊天机器人Grok上线可以使用啦,为X Premium Plus订阅者推出

艾隆・马斯克旗下的 AI 初创公司X&#xff08;前身“推特”&#xff09;开发的 ChatGPT 竞争对手 Grok 已经在 X 平台上正式推出。Grok 是一个基于生成模型 Grok-1的聊天机器人&#xff0c;它能够回答问题并提供最新的信息。与其他聊天机器人不同&#xff0c;Grok 可以实时获取…

Java基础-IDEA下载、卸载、安装、使用

目录 1. IDEA下载2. IDEA卸载3. IDEA安装4. 基本使用 1. IDEA下载 IDEA下载网址 2. IDEA卸载 3. IDEA安装 更改IDEA安装目录 是否创建桌面图标 下一步 success&#xff01; 4. 基本使用 新建项目 新建模块 新建包 新建Java文件 编写代码 运行测试

【C语言】网络字节序和主机字节序

网络字节序和主机字节序是计算机中字节的两种排序方式&#xff0c;它们主要用于解决不同计算机之间数据通信的问题。 一、网络字节序 也被称为大端字节序&#xff0c;是一种标准的字节序。在网络通信中&#xff0c;如果两台主机的字节序不同&#xff0c;可能会导致数据解释的二…

shell条件测试

1.1.用途 为了能够正确处理Shell程序运行过程中遇到的各种情况&#xff0c;Linux Shell提供了一组测试运算符. 通过这些运算符&#xff0c;shell程序能够判断某种或者几个条件是否成立。 条件测试在各种流程控制语句&#xff0c;例如判断语句和循环语句中发挥了…