[Collection与数据结构] 七大排序算法汇总

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(93平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

1.概述

1.1 概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

1.2 常见应用

  1. 高校排行
    在这里插入图片描述
  2. 商品排序
    在这里插入图片描述

2. 常见排序

2.1 直接插入排序

从序列的第二个位置开始为基准,把前面的一个元素依次与下一个元素比较,前一个元素大于后一个元素(升序),则交换,如果碰到小于的,则证明前几个元素已经有序了,因为是从第二个元素开始进行插入排序的,直接break掉.
动态演示:
在这里插入图片描述

/*** 插入排序* @param array 传入的数组*/public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {//基准从1开始for (int j = i-1; j >= 0; j--) {if (array[j] > array[j+1]){//把前面的元素依次比较swap(j,j+1,array);}else {break;//遇到不符合条件的直接break}}}}private static void swap(int a,int b,int[] array){int tmp = array[a];array[a] = array[b];array[b] = tmp;}

特性总结:

  1. 元素越趋于有序,插入排序越快,因为遇到比较不符合条件的直接回break掉.
  2. 时间复杂度:两层循环,O(n2)
  3. 空间复杂度:只在数组本身上进行了操作,O(1)
  4. 稳定性:稳定

2.2 希尔排序

希尔排序实际上是直接插入排序的一种升级版,先把序列中的元素按照一定的间隔个数分成多个组,之后把各个组中的元素进行排序,之后缩小缩小间隔个数,也就是缩小组数,增大各个组中的元素个数,再次排序,直到元素之间的间隔小于1为止.
动态演示:
在这里插入图片描述

 /*** 希尔排序,本质上是插入排序的一种升级版* @param array*/public static void shellSort(int[] array){int gap = array.length;while (gap > 1){//数据间隙大于1时继续希尔排序gap = gap/2;//缩小数据间隙shell(array,gap);}}private static void shell(int[] array,int gap){for (int i = gap; i < array.length; i++) {//针对每一组数据进行插入排序for (int j = i-gap; j >= 0; j-=gap) {//只不过每次的步数变成了gapif (array[j] > array[j+gap]){swap(j,j+gap,array);}else {break;}}}}

其实我们观察上述代码,我们为什么说他是直接插入排序的升级版,是因为,它相比直接插入排序只是改变了每次走的步数.

特性总结:

  1. 希尔排序是针对直接插入排序的优化
  2. 当gap>1时都是预排序,目的是让数据越来越接近有序.当gap==1的时候,就是直接插入排序,这时数据已经趋于有序了,直接插入排序就会特别快.
  3. 时间复杂度:目前仍然存在争议,一般认为是O(n1.25~1.6n1.25)
  4. 稳定性:不稳定

2.3 选择排序

从第一个元素开始,寻找比基准元素小的元素,下标保存到tmp中,之后继续寻找比tmp小的元素,直到找到最小的元素为止,之后交换基准元素和tmp下标的元素,基准后移,一些此类推.
动态演示:

在这里插入图片描述

/*** 选择排序* @param array*/public static void selectSort(int[] array){for (int i = 0; i < array.length; i++) {int min = i;//最小值的下标赋值为i,如果没有找到比min下标小的,说明i就是最小的int j = i+1;for (; j < array.length; j++) {if (array[min] > array[j]){min = j;}}swap(min,i,array);}}

特性总结:

  1. 时间复杂度:O(n2)
  2. 空间复杂度:O(1)
  3. 稳定性:不稳定
  4. 这种排序方法虽然好理解,但是由于效率太低,日常开发中很少用.

2.4 冒泡排序

之所以叫冒泡排序,是因为就像水中的气泡一样,一点一点地浮出水面.先确定排序的趟数(下标最大值),就是外层循环,再确定排序交换的次数(下标最大值-i),就是内层循环,遇到比自己小的就交换,这样最大值就像冒泡一样排到了最后.
优化: 如果发现在内层循环遍历的时候,一次都没有交换,说明已经有序,我们通过flag来标记.
动态演示:
在这里插入图片描述

/*** 冒泡排序* @param array*/public static void bubbleSort(int[] array){for (int i = 0; i < array.length-1; i++) {//如果遍历到最后一个元素,就没有必要比较了,就要-1boolean flag = true;for (int j = 0; j < array.length-i-1; j++) {//这里必须-1,因为如果不-1,就会遍历到最后一个元素,j+1就会越界if (array[j] > array[j+1]){swap(j+1,j,array);flag = false;//发生了交换.说明不有序,设置为false}}if (flag){//如果flag == true,说明没有发生交换,整个数组已经有序return;//直接返回}}}

特性总结:

  1. 时间复杂度:O(n2)
  2. 空间复杂度:O(1)
  3. 稳定性:稳定

2.5 堆排序

首先如果是升序的话,先创建一个大根堆,让end指向最后一个元素为什么不创建小根堆呢?是因为小根堆只可以保证父节点是最小的,而不可以保证子节点是从小到大排列的.之后把堆顶元素和堆尾元素交换,就把整个堆的最大元素排到了最后.之后继续把该堆向下调整为大根堆,之后让end向前移动
动态演示:
在这里插入图片描述

/*** 堆排序,从小到大排序,创建大根堆* @param array*/public static void heapSort(int[] array){int end = array.length-1;createBigHeap(array);//先创建大根堆while (end > 0){swap(0,end,array);//交换堆顶元素和最后一个元素,把堆顶最大的元素放在最后end--;//end向前移动shiftDown(0,end,array);//再次向下调整为大根堆//先向下调整,再--,因为向下调整的时候,while循环没有等号,如果传入end-1,倒数第二个结点就调整不到}}private static void createBigHeap(int[] array){for (int i = (array.length-1-1)/2; i >= 0 ; i--) {shiftDown(i,array.length-1,array);}}private static void shiftDown(int parent,int end,int[] array){int child = parent*2+1;while (child <= end){if (child+1 < end && array[child] < array[child+1]) {child++;}if (array[child] > array[parent]){swap(parent,child,array);parent = child;child = child*2+1;}else {break;}}}

特点总结:

  1. 堆排序适用于海量数据排序,数据越多,堆排序效率越高.
  2. 时间复杂度:复杂度主要集中于向下调整中,元素个数x树的高度,O(n*log2n)
  3. 空间复杂度:没有额外空间,O(1)
  4. 稳定性:不稳定

2.6 快速排序(重点)

之所以叫快速排序,说明它是真的快.快速排序整体思想为分治思想,就是把通过递归的思想把整个数组通过一定的方法切成二叉树的形式,之后对每科子树进行排序.
快速排序的方法有两种,一种是霍尔法,一种是挖坑法.

2.6.1 霍尔法

分别定义start和end指向数组首和尾,选取第一个元素为key,之后先让end向前移动,找到比key小的元素,之后再让start向后移动,找到比key大的元素,之后交换end和start下标的值,以此类推.直到start和end相遇,把相遇位置的元素和key交换,之后以相遇点分治,递归以此类推.
动态演示:
在这里插入图片描述

/*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}swap(left,mid,array);//把区间内的中间值放在头int pos = position(left,right,array);//通过霍尔法找到分治点quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}/*** 霍尔法找到相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position(int start,int end,int[] array){int tmp = array[start];int i = start;//提前准备比较数据的下标while (start < end){while (start < end && array[end] >= tmp){//先走后面,注意加上等号end--;}while (start < end && array[start] <= tmp){//加前一个条件是为了防止出现已经排好序的极端情况start++;}swap(start,end,array);//当在前面找到比tmp大的数据,在后面找到比tmp大的数据,就交换}swap(i,start,array);//当start和end相遇的时候,交换数列头元素和相遇地方的元素return start;//返回相遇的点,以相遇的点分制}

2.6.2 挖坑法

先把key(首)元素下标放入tmp中,让end向前移动,找到比tmp小的元素,填上key元素的坑,之后让start向后移动找到比tmp大的元素,填上上一个end的坑.以此类推,最后让tmp填上start和end相遇位置的坑.之后分治,递归重复上述操作.

 /*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}swap(left,mid,array);//把区间内的中间值放在头int pos = position2(left,right,array);quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}/***挖坑法找相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position2(int start,int end,int[] array){int tmp = array[start];while (start < end){if (start < end && array[end] >= tmp){//先走后面,否则下面没法填坑end--;}array[start] = array[end];if (start < end && array[start] <= tmp){start++;}array[end] = array[start];}array[start] = tmp;return start;}

2.6.3 快速排序优化

  • 由于快速排序越来越趋向有序,所以我们可以以分治之后数组的长度作为基准,当小于一定的值之后,就可以对分治区域使用插入排序.
  • 为了防止出现二叉树单分支的情况而降低效率,所以我们需要在分治区间找到中间大小的元素,与首元素交换.

快速排序最终版:

/*** 快速排序,整体思想:把小的往前放,把大的往后放* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);//规定开始和结束位置}private static void quick(int[] array,int s,int e){int left = s;int right = e;if (left >= right){//当左下标大于右下标的时候,说明递归完成,直接返回return;}//优化2:在霍尔法或者挖坑法使得数组不断趋于有序时,我们就可以发挥直接插入排序的优势//越趋于有序,越快if (right-left < 7){insertSort2(left,right,array);}//优化1:寻找中间大小的数字,防止出现单分支情况导致效率太低int mid = findmid(array,left,right);swap(left,mid,array);//把区间内的中间值放在头int pos = position(left,right,array);quick(array,left,pos-1);quick(array,pos+1,right);//以分制点为基准,向两侧递归}private static void insertSort2(int start,int end,int[] array){for (int i = start+1; i <= end; i++) {for (int j = i-1; j < end; j++) {if (array[j] > array[j+1]){swap(j,j+1,array);}else {break;}}}}//比较区间内的开始,中间,结束位置的值private static int findmid(int[] array,int start,int end){int mid = (start+end)/2;//区间内的中间位置//先比较左右开始和结束的值if (array[start] < array[end]){if (array[end] < array[mid]){//mid插入它们两个之间的三个空隙return end;} else if (array[mid] > array[start]) {return mid;}else {return start;}}else {if (array[start] < array[mid]){return start;} else if (array[end] < array[mid]) {return mid;}else {return end;}}}/*** 霍尔法找到相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position(int start,int end,int[] array){int tmp = array[start];int i = start;//提前准备比较数据的下标while (start < end){while (start < end && array[end] >= tmp){//先走后面,注意加上等号end--;}while (start < end && array[start] <= tmp){//加前一个条件是为了防止出现已经排好序的极端情况start++;}swap(start,end,array);//当在前面找到比tmp大的数据,在后面找到比tmp大的数据,就交换}swap(i,start,array);//当start和end相遇的时候,交换数列头元素和相遇地方的元素return start;//返回相遇的点,以相遇的点分制}/***挖坑法找相遇位置* @param start 开始位置* @param end 结束位置* @param array 原始数组* @return*/private static int position2(int start,int end,int[] array){int tmp = array[start];while (start < end){if (start < end && array[end] >= tmp){//先走后面,否则下面没法填坑end--;}array[start] = array[end];if (start < end && array[start] <= tmp){start++;}array[end] = array[start];}array[start] = tmp;return start;}

2.7 归并排序

先把数组从中间拆分开,让每个小数组有序,之后把小数组合并回来,大数组就是有序的.也是分治思想,整体也是一棵二叉树的形状.
动态演示:

在这里插入图片描述

/*** 归并排序* @param array*/public static void mergSort(int[] array){mergFunc(0,array.length-1,array);}private static void mergFunc(int left,int right,int[] array){//拆分数组int mid = (left+right)/2;if (left >= right){//递归到left>=right的时候,直接返回return;}//向两侧递归mergFunc(left,mid,array);mergFunc(mid+1,right,array);//开始合并merg(left,right,mid,array);}//在合并的时候进行排序private static void merg(int left,int right,int mid,int[] array){int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;int k = 0;int [] tmp = new int[right-left+1];while (s1 <= e1 && s2 <= e2){if (array[s1] < array[s2]){tmp[k] = array[s1];k++;s1++;}else {tmp[k] = array[s2];k++;s2++;}}//看哪个数组还有数据,拷贝进去while (s1 <= e1){tmp[k] = array[s1];k++;s1++;}while (s2 <= e2){tmp[k] = array[s2];k++;s2++;}//把临时数组中的数据拷贝到原数组中for (int i = 0; i < tmp.length; i++) {array[left+i] = tmp[i];}}

特性总结:

  1. 时间复杂度:元素个数x数的高度,O(n*log2n)
  2. 空间复杂度:额外申请了一个数组,所以是O(n)
  3. 稳定性:稳定

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

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

相关文章

PyTorch中 DataLoader 和 TensorDataset 的详细解析

DataLoader 和 TensorDataset PyTorch DataLoader 和 TensorDataset 的详细解析DataLoader 介绍DataLoader 的核心功能 TensorDataset 介绍TensorDataset 的核心功能 使用 DataLoader 和 TensorDataset 加载数据关键内容解析 结论 PyTorch DataLoader 和 TensorDataset 的详细解…

VTK —— 三、图形格式 - 示例1 - 读取.vtp文件并输出.ply文件(附完整源码)

代码效果&#xff1a;演示程序读取.vtp后输出.ply文件&#xff0c;使用paraview打开该输出的.ply文件 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用V…

堡垒机——网络技术手段

目录 一、简介 1.什么是跳板机 2.跳板机缺陷 3.什么是堡垒机 4.为什么要使用堡垒机 4.1堡垒机设计理念 4.2堡垒机的建设目标 4.3堡垒机的价值 4.4总结 5.堡垒机的分类 6.堡垒机的原理 7.堡垒机的身份认证 8.堡垒机的运维方式常见有以下几种 9.堡垒机其他常见功能…

低代码优于无代码?

从1804年打孔式编程出现&#xff0c;编程语言至今已经存在了200多年。而从50年代以来&#xff0c;新的编程语言也不断涌现&#xff0c;现在已经有250多种了。这就意味着&#xff0c;开发人员最需要习惯的事情就是不断改变。 编程界最近的一个变化是集成开发环境&#xff08;IDE…

如何使用摇摆交易?fpmarkets实例讲解

各位投资者五一节后快乐&#xff01;祝愿投资者在接下来的日子里每次交易都以盈利结算。 五一节日也是劳动节&#xff0c;在这个特殊的日子里fpmarkets澳福和各位勤劳的投资者一起学习如何使用摇摆交易策略进行交易&#xff1f; 其实很简单&#xff0c;首先判断出买卖点&#x…

FANUC机器人故障诊断—报警代码(五)

FANUC机器人故障诊断中关于报警代码的介绍更新如下&#xff1a; 一、报警代码&#xff08;SRVO-214&#xff09; SRVO-214 6轴放大器保险丝熔断 [原因]6轴伺服放大器上的保险丝(FS2,FS3)已熔断。括号内的数字表示在第几台6轴伺服放大器上检测出了保险丝熔断。 [对策] 1.保险…

省公派出国|社科类普通高校教师限期内赴英国访学交流

在国外访问学者申请中&#xff0c;人文社科类相对难度更大&#xff0c;尤其是英语语言学&#xff0c;作为非母语研究并不被国外高校看重。经过努力&#xff0c;最终我们帮助Z老师申请到英国坎特伯雷基督教会大学的访学职位&#xff0c;并在限期内出国。 Z老师背景&#xff1a; …

开源之夏 2024 学生报名通道现已正式开启!奖金都是12000元,冲啊!!!

Apache SeaTunnel作为数据集成平台的先行者&#xff0c;数以千计的开发者活跃在这个开源社区&#xff0c;我们深知开源社区就像是“众人拾柴火焰高”&#xff0c;希望有更多的青年力量能参与到社区的建设中来&#xff01; 在前段时间&#xff0c;我们不仅成功入选中科院软件所主…

简述 BIO 、NIO 模型

BIO : 同步阻塞I/O&#xff08;Block IO&#xff09; 服务器实现模式为每一个连接一个线程&#xff0c;即客户端有连接请求时服务器就需要启动一个线程进行处理&#xff0c;如果这个连接不做任何事情会造成不必要的线程开销&#xff0c;此处可以通过线程池机制进行优化。 impo…

一键自动化博客发布工具,用过的人都说好(segmentfault篇)

segmentfault是我在这些平台中看过界面最为简洁的博客平台了。 今天就以segmentfault为例&#xff0c;讲讲在blog-auto-publishing-tools中的实现原理。 前提条件 前提条件当然是先下载 blog-auto-publishing-tools这个博客自动发布工具,地址如下&#xff1a;https://github…

视频剪辑入门:快速掌握AI智剪基本技巧,批量剪辑很简单

在数字媒体日益盛行的今天&#xff0c;视频剪辑已经成为了一个非常热门的技能。无论你是专业的视频制作人&#xff0c;还是业余的视频爱好者&#xff0c;掌握一些基本的视频剪辑技巧都是非常必要的。近年来&#xff0c;随着人工智能技术的发展&#xff0c;AI智剪工具也应运而生…

AI 不仅会画画,还能造车 | 最新快讯

本周的北京&#xff0c;正在上演一场深刻的变革。 汽车产业&#xff0c;这个曾经以工业制造为核心的行业&#xff0c;正迅速地被数字化浪潮所改变&#xff0c;汽车、电商、互联网、人工智能等领域的界限变得模糊。在这样的背景下&#xff0c;车企们纷纷开始打破传统&#xff0c…