常见的排序算法

ops/2024/10/11 13:27:15/

前言

算法对于我们普通的工程师来说可算得上陌生又熟悉,因为在平时的业务代码中可能见到他的身影比较少,但在底层的代码中我们可能会经常发现算法>排序算法的影子,如数据库索引,操作系统的进程调度。因此,掌握这种算法中的思想还是致关重要,今天大猿就带大家来实战一下基础的算法>排序算法,加强记忆。

常见的排序分类

在这里插入图片描述

直接插入排序

先直接上代码:

java">    public static void insertSort2(int [] arr){for (int i = 1; i < arr.length; i++) {int key = arr[i];int j=i-1;for ( ; j >= 0 ; j--) {if(key < arr[j]){arr[j + 1] = arr[j];}else {break;}}arr[j + 1] = key;}StringBuffer stringBuffer = new StringBuffer();for (int j : arr) {stringBuffer.append(",").append(j);}System.out.println(stringBuffer);}public static void main(String[] args) {int [] arr = {345,23,79,54,67,666,23,78,2,22,985};//   insertSort(arr);insertSort2(arr);}

运行结果

在这里插入图片描述

复杂度

时间复杂度

运行复杂度,当整个序列基本有序的情况下此时插入排序将出现最好情况 O(n) , 这个也不难想象,当整个排序序列基本有效时,比较只需要n次,内部循环几乎可以不执行。
对于一般情况时间复杂度是O(n^2);

空间复杂度

因为在程序执行过程中,我们只用一个一个临时存储变量,所以空间复杂度为O(1);

稳定性

算法是稳定算法,如何理解稳定性呢?稳定性最直白的理解就是如果出现相同元素的时候,看原来的序列是否遭到破坏。

希尔排序

上代码,

java">    public static void main(String[] args) {int[] arr = new int[100];for (int i = 0; i < 100; i++) {arr[i] = (int) (Math.random() *100);}shellSort(arr);}public static void shellSort(int [] arr){for (int gap = arr.length /2; gap>0; gap /=2){for(int i = gap; i < arr.length ; i ++){int temp = arr[i];int j=i - gap;for( ; j >= 0; j -= gap){if(arr[j] < temp){arr[j+gap]=arr[j];}else {break;}}arr[j+gap] = temp;}}StringBuffer stringBuffer = new StringBuffer();for (int j : arr) {stringBuffer.append(",").append(j);}System.out.println(stringBuffer);}

运行结果

在这里插入图片描述

复杂度

时间复杂度

希尔排序可以理解为特殊的插入排序,最好和最坏时间复杂度基本与插入排序保持一致。软设上给出的平均复杂度为O(n^1.3) 有兴趣的同学可以去研究一下理论。

空间复杂度

空间复杂度基本与插入排序是一致的。

稳定性

算法为非稳定算法

计数排序

代码

java">    public static int[] countSort(int[] array) {//1.得到数列的最大值int max = array[0];for(int i=1; i<array.length; i++){if(array[i] > max){max = array[i];}}//2.根据数列最大值确定统计数组的长度int[] countArray = new int[max+1];//3.遍历数列,填充统计数组for(int i=0; i<array.length; i++){countArray[array[i]]++;}//4.遍历统计数组,输出结果int index = 0;int[] sortedArray = new int[array.length];for(int i=0; i<countArray.length; i++){for(int j=0; j<countArray[i]; j++){sortedArray[index++] = i;}}return sortedArray;}public static int[] countSortV2(int[] array) {//1.得到数列的最大值和最小值,并算出差值dint max = array[0];int min = array[0];for(int i=1; i<array.length; i++) {if(array[i] > max) {max = array[i];}if(array[i] < min) {min = array[i];}}int d = max - min;//2.创建统计数组并统计对应元素个数int[] countArray = new int[d+1];for(int i=0; i<array.length; i++) {countArray[array[i]-min]++;}//3.统计数组做变形,后面的元素等于前面的元素之和for(int i=1;i<countArray.length;i++) {countArray[i] += countArray[i-1];}//4.倒序遍历原始数列,从统计数组找到正确位置,输出到结果数组int[] sortedArray = new int[array.length];for(int i=array.length-1;i>=0;i--) {sortedArray[countArray[array[i]-min]-1]=array[i];countArray[array[i]-min]--;}return sortedArray;}public static void main(String[] args) {int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};int[] sortedArray = countSort(array);System.out.println(Arrays.toString(sortedArray));array = new int[] {95,94,91,98,99,90,99,93,91,92};sortedArray = countSortV2(array);System.out.println(Arrays.toString(sortedArray));}

运行结果

在这里插入图片描述

时间复杂度

计数排序的时间复杂度为O(n+k),其中n是待排序序列的长度,k是待排序序列中的最大值,注意计算时间复杂度时只是考虑了构造统计数组的最大长度k和

空间复杂度

计数排序的空间复杂度为O(k)。

稳定性

算法是一个稳定算法,对于数的范围不大,但是算量很多的情况非常实用。

选择排序

继续先上代码

java">    public static void selectSort(int [] arr){int maxIndex =0;for (int i = 0; i < arr.length-1; i++) {for (int j = i; j <arr.length ; j++) {if(arr[maxIndex]<arr[j]){maxIndex =j;}}if(maxIndex != i){int temp =0;temp = arr[maxIndex];arr[maxIndex] = arr[i];arr[i] = temp;}}StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i <arr.length; i++) {stringBuffer.append(",").append(arr[i]);}System.out.println(stringBuffer.toString());}public static void main(String[] args) {int [] arr = {345,23,79,54,67,666,23,78,2,22,985};selectSort(arr);}

运行结果

在这里插入图片描述

时间和空间复杂度

选择排序的时间复杂度为O(n^2) 空间复杂度为O(1)

稳定性

算法为不稳定算法

堆排序

堆排序稍微复杂点,先上个截图,至于具体理论的话请同学们自己去找教材或者视频,下面给出算法及代码
在这里插入图片描述

java">    public static void main(String[] args) {int arr [] ={1,10,3,2,6,5,7,9,8,0,4};heapSort(arr);System.out.println(Arrays.toString(arr));}/**** @param array*/private static  void heapSort(int []  array){//构建堆for (int i = (array.length-2)/2; i >=0; i--) {downAdjust(array,i,array.length);}System.out.println("-----------------------");System.out.println(Arrays.toString(array));//调整堆for (int i = array.length-1; i >0; i--) {int temp = array[i];array[i] = array[0];array[0] = temp;downAdjust(array,0,i);/*            if("UP".equals(cmd)){upAdjust(array);}*/}}/**** 节点下沉* @param arr* @param parentIndex* @param length*/private static void  downAdjust(int [] arr,int parentIndex , int length){int temp = arr[parentIndex];int childIndex = 2* parentIndex +1;while (childIndex < length){//定位到右孩子if(childIndex+1 < length && arr[childIndex+1]>arr[childIndex]){childIndex++;}if(temp > arr[childIndex]){break;}arr[parentIndex] = arr[childIndex];parentIndex = childIndex;childIndex = 2* childIndex+1;}arr[parentIndex] = temp;// System.out.println(Arrays.toString(arr));}

运行结果

在这里插入图片描述

复杂度及稳定性

堆排序是不稳定排序,其时间复杂度时O(nlog(2)n),空间复杂度为n+1;此外
算法是非稳定算法

冒泡排序

代码如下:

java">    public static void main(String[] args) {int [] arr = {345,23,79,54,67,666,23,78,2,22,985};bubbleSort(arr);}public static void  bubbleSort(int [] arr){for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length - i - 1; j++) {int temp = 0;if (arr[j] < arr[j+1]) {temp = arr[j];arr[j]=arr[j+1];arr[j+1] = temp;}}}StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i <arr.length; i++) {stringBuffer.append(",").append(arr[i]);}System.out.println(stringBuffer.toString());}

运行结果

在这里插入图片描述

复杂度分析及稳定性分析

冒泡算法的复杂度为O(n^2) 空间复杂度为O(1),该算法为稳定的算法>排序算法

快速排序

算法
在这里插入图片描述

java">    public static void main(String[] args) {int [] arr = {345,23,79,54,67,666,23,78,2,22,985};quickSort(arr,0,arr.length-1);StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i <arr.length; i++) {stringBuffer.append(",").append(arr[i]);}System.out.println(stringBuffer.toString());}public static void quickSort(int [] arr, int start,int end){if(start > end){return;}int midIndex = partition(arr, start, end);quickSort(arr,start,midIndex-1);quickSort(arr,midIndex+1,end);}private static int partition(int[] arr, int start, int end) {int right = end;int left = start;int midValue = arr[left];while (left != right){while (left<right && midValue < arr[right]){right --;}// arr[left] = arr[right];while (left<right && midValue >= arr[left]){left ++;}//  arr[right] = arr[left];if(left < right){int temp =0;temp = arr[left];arr[left] = arr[right];arr[right] = temp;}}arr[start] = arr[right];arr[right] = midValue;return right;}

运行结果

在这里插入图片描述

复杂度分析

时间复杂度

快速排序的一般时间复杂度为 O(nlog(2)n) ,最坏的时间复杂度为O(n^2);

空间复杂度

递归算法的空间复杂度 = 每次递归的空间复杂度O(1) * 递归深度, 因为堆栈的深度就是快速排序的空间复杂度位O(log(2)n),最坏也就是O(n)

稳定性

快速排序为不稳定算法

归并排序

先上代码

java">    public static void main(String[] args) {int [] arr = {345,23,79,54,67,666,23,78,2,22,985};mergeSort(arr, 0, arr.length - 1);for (int i : arr) {System.out.print(i + " ");}}public static void mergeSort(int[] arr, int left, int right) {if (left < right) {int mid = (left + right) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}}public static void merge(int[] arr, int left, int mid, int right) {int[] temp = new int[right - left + 1];int i = left;int j = mid + 1;int k = 0;while (i <= mid && j <= right) {if (arr[i] <= arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}while (i <= mid) {temp[k++] = arr[i++];}while (j <= right) {temp[k++] = arr[j++];}for (int p = 0; p < temp.length; p++) {arr[left + p] = temp[p];}}

运行结果
在这里插入图片描述

时间复杂度

从上面的代码来看,其归并的深度为log(2)n 而每次合并的时间复杂度都为n,所以综合下来其时间复杂度为 n*log(2)n;

空间复杂度

因为归并需要额外的空间数组,其大小n

稳定性

算法为稳定的算法>排序算法,相同元素不改变原来的位置。

桶排序

桶排序的基本思想可以说是与计数排序有异曲同工之妙,由于篇幅原因,需要了解算法的具体实现的小伙伴可以自己去翻阅资料。

总结

  • 本文带大家实战了常见的算法>排序算法,并给出了运行结果,其中采用 动态规划 思想的算法选择排序 ; 选择排序、冒泡排序和堆排序 都属于 贪心法,而 归并排序 采用了分治思想;希尔排序可以说是既采用了动态规划思想,又采用了分之思想快速排序既采用贪心算法,又吸收了分治思想
  • 对于不同场景我们可以采用不同的算法>排序算法,从时间复杂度来看,快排,归并,堆排序是响应速度最快的三种常见排序方法,但所占空间都比较高;从空间复杂度来看,冒泡,插入,简单选择排序是应用空间最小的排序方法,但响应时间有点慢;复杂为线性的算法>排序算法只有基数排序和桶排序,但该算法并不适合所有的应用场景,所以在实际应用大各位小伙伴要懂得权衡利弊,妥善处置。

http://www.ppmy.cn/ops/19258.html

相关文章

知识在人工智能中的核心作用:连接主义与符号主义的交融

知识在人工智能中的核心作用&#xff1a;连接主义与符号主义的交融 一、连接主义与深度学习的崛起二、感知与认知&#xff1a;AI的双眼与大脑三、知识的多元表示与处理四、符号主义与知识工程的实践五、知识在AI中的核心地位六、AI的具体应用案例分析七、知识图谱&#xff1a;认…

APP UI设计秉承哪些原则可以开发出更好的用户体验?

设计一个优秀的APP UI需要考虑多方面因素&#xff0c;以下是一些原则可以帮助你开发出更好的用户体验&#xff1a; 简洁性&#xff08;Simplicity&#xff09;&#xff1a;保持界面简洁清晰&#xff0c;避免过多的复杂元素和信息。简洁的设计能够减少用户的认知负荷&#xff0c…

【draw.io的使用心得介绍】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

Lagent AgentLego 智能体应用搭建-笔记六

本次课程由Lagent&AgentLego 核心贡献者樊奇老师讲解【Lagent & AgentLego 智能体应用搭建】课程 课程视频&#xff1a;https://www.bilibili.com/video/BV1Xt4217728/ 课程文档&#xff1a;https://github.com/InternLM/Tutorial/tree/camp2/agent 大语言模型的局限…

Oracle实践|快速了解内置函数之INSTR

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

Github 2024-04-20 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-20统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量非开发语言项目2Python项目2Swift项目2HTML项目1CSS项目1Go项目1C项目1C++项目1Rust项目1编程面试大学:成为软件工程师的全面学习计划 创建周期…

自动化测试框架对比

一、自动化测试框架对比 二、对比与选型 TestNG基于Java语言&#xff0c;具有强大的测试报告和日志功能&#xff0c;并支持并发测试和数据驱动测试。适用大型项目和复杂场景&#xff0c;更方便地管理和组织测试用例。在需要进行大规模、高并发的测试场景下&#xff0c;可以选择…

蛋糕购物商城

蛋糕购物商城 运行前附加数据库.mdf&#xff08;或使用sql生成数据库&#xff09; 登陆账号&#xff1a;admin 密码&#xff1a;123456 修改专辑价格时去掉&#xffe5;以及上传专辑图片 c#_asp.net 蛋糕购物商城 网上商城 三层架构 在线购物网站&#xff0c;电子商务系统 …