数据结构(Java实现)-排序


排序的概念
排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的
在这里插入图片描述
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。


插入排序
基本思想:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
在这里插入图片描述

在这里插入图片描述
直接插入排序的特性总结:

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

在这里插入图片描述
一个本身就稳定的排序 可以实现为不稳定
但是一个本身就不稳定的排序 不可能实现为稳定的排序


希尔排序( 缩小增量排序 )
希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算。我们就记为n^1.3
  4. 稳定性:不稳定

选择排序
基本思想:
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


选择排序的第二种写法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

有两个疑点
1.
在这里插入图片描述
2.当left等于right时,说明当前下标的左边已经排号,当前下标的右边也已经排好,那么当前下标的值一定是中间值
在这里插入图片描述
【直接选择排序的特性总结】

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

堆排序
它是通过堆来进行选择数据。
在这里插入图片描述

在这里插入图片描述

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

冒泡排序
在这里插入图片描述

在这里插入图片描述


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

在这里插入图片描述

在这里插入图片描述
上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,同学们在写递归框架时可想想二叉树前序遍历规则即可快速写出来,后序只需分析如何按照基准值来对区间中数据进行划分的方式即可。


Hoare版
在这里插入图片描述
在这里插入图片描述


挖坑法
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


快速排序优化:
在这里插入图片描述

三数取中法选key,目的:将待排序数组分开,不要只有左边或者只有右边
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


递归到小的子区间时,可以考虑使用插入排序。因为这时的区间元素已经趋近于有序
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


快速排序非递归形式
采用栈
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


快速排序总结

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(logN)
  4. 稳定性:不稳定

归并排序
基本思想
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


非递归形式实现归并排序
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


归并排序总结

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

海量数据的排序问题
外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序

  1. 先把文件切分成 200 份,每个 512 M
  2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
  3. 进行 2路归并,同时对 200 份有序文件做归并过程(磁盘IO读写),最终结果就有序了

排序算法复杂度及稳定性分析

在这里插入图片描述


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

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中
    在这里插入图片描述

在这里插入图片描述


基数排序
基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


桶排序


上述涉及的所有代码
Sort.java

import java.util.Arrays;
import java.util.Stack;/*** Created with IntelliJ IDEA.* Description:* User: Home-pc* Date: 2023-08-26* Time: 12:04*/
public class Sort {@Overridepublic String toString() {return "Sort{}";}public static void insertSort(int[] array ){for (int i =1; i < array.length; i++) {int temp=array[i];//记录当前的元素,准备随时插入,同时放置元素被覆盖掉int j=i-1;for (; j>=0; j--) {if(array[j]>temp){//当前j下标的元素后移array[j+1]=array[j];}else{break;}}array[j+1]=temp;//没有j下标的元素大,插入它的后面}}//public  static  void shell(int[] array,int gap){for (int i =gap; i < array.length; i++) {//这里的i++,可以针对每一个分组int temp=array[i];//记录当前的元素,准备随时插入,同时放置元素被覆盖掉int j=i-gap;for (; j>=0; j-=gap) {if(array[j]>temp){//当前j下标的元素后移array[j+gap]=array[j];}else{break;}}array[j+gap]=temp;//没有j下标的元素大,插入它的后面}}public static void shellSort(int[] array){int gap=array.length;while(gap>1){gap/=2;shell(array,gap);//这里在最后一定会进行一次gap=1的插入排序}}//public static void selectSort(int[] array){for(int i=0;i< array.length;i++){int minIndex=i;for (int j = i+1; j < array.length; j++) {if(array[j]<array[minIndex]){minIndex=j;}}swap(array,i,minIndex);}}private static void swap(int[] array,int i,int j){int temp=array[i];array[i]=array[j];array[j]=temp;}//public static void selectSort2(int[] array){int left=0;int right= array.length-1;while(left<right){int minIndex=left;int maxIndex=left;for (int i = left+1; i <=right; i++) {if(array[i]<array[minIndex]){minIndex=i;}if(array[i]>array[maxIndex]){maxIndex=i;}}swap(array,minIndex,left);if(left==maxIndex){maxIndex=minIndex;}swap(array,maxIndex,right);left++;right--;}}//public static void heapSort(int[] array){createBigHeap(array);int end= array.length-1;while(end>0){swap(array,end,0);shiftDown(array,0,end);end--;}}private static void createBigHeap(int[] array){for (int i = (array.length-1-1)/2; i>=0; i--) {shiftDown(array,i, array.length);}}private static void shiftDown(int[] array,int parent,int len){int child=parent*2+1;while(child<len){if(child+1<len && array[child]<array[child+1]){child=child+1;}if(array[child]>array[parent]){swap(array,child,parent);parent=child;child=parent*2+1;}else{break;}}}//public  static  void bubbleSort(int[] arrary){for (int i = 0; i < arrary.length-1; i++) {boolean flag=false;for (int j = 0; j < arrary.length-1-i; j++) {if(arrary[j]>arrary[j+1]){swap(arrary,j,j+1);flag=true;}}if(!flag){break;}}}//public static void quickSort(int[] array){quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end){if(start>=end){return;}//直接插入排序优化if(end-start+1<=10){insertSortForQuick(array,start,end);return;}//三数取中优化int mid=threeNum(array,start,end);swap(array,mid,start);int pivot=parttion(array,start,end);//求出基准值,依次为中间值划分序列quick(array,start,pivot-1);//左数quick(array,pivot+1,end);//右数}public static void insertSortForQuick(int[] array,int left,int right ){for (int i =left+1; i <=right; i++) {int temp=array[i];//记录当前的元素,准备随时插入,同时放置元素被覆盖掉int j=i-1;for (; j>=left; j--) {if(array[j]>temp){//当前j下标的元素后移array[j+1]=array[j];}else{break;}}array[j+1]=temp;//没有j下标的元素大,插入它的后面}}private static int parttion1(int[] array,int left,int right){int i=left;int temp=array[left];//拿这个值和其它元素比较while(left<right){while(left<right && array[right]>=temp){//找到右边第一个比temp小的值right--;}while(left<right && array[left]<=temp){//找到左边第一个比temp大的值left++;}swap(array,left,right);//交换这两个值}swap(array,left,i);//交换某个中间值和temp的值,使得temp为真正的中间值return left;//返回这个中间位置的下标}//private static int parttion(int[] array,int left,int right){int temp=array[left];while(left<right){while(left<right && array[right]>=temp){right--;}array[left]=array[right];while(left<right && array[left]<=temp){left++;}array[right]=array[left];}array[right]=temp;return left;}//优化:三数取中private static int threeNum(int[] array,int left,int right){int mid=(left+right)/2;if(array[left]<array[right]){if(array[mid]<array[left]){return left;}else if(array[mid]>array[right]){return right;}else{return mid;}}else{if(array[mid]<array[right]){return right;}else if(array[mid]>array[left]){return  left;}else{return mid;}}}//非递归实现public static void quickSortByStack(int[] array){Stack<Integer> stack=new Stack<>();stack.push(array.length-1);//这里先push的右边,后push的左边stack.push(0);while(!stack.empty()){int left=stack.pop();int right=stack.pop();if(left>=right){//成立,说明该区间排序结束continue;}int index=parttion(array,left,right);stack.push(right);stack.push(index+1);stack.push(index-1);stack.push(left);}}//归并private static void merge(int[] array,int left,int mid,int right){//两个有序组合并为一个有序组int s1=left;int e1=mid;int s2=mid+1;int e2=right;//看似拆分为了两组,实际是一直在一个数组中进行的操作int[] tmpArr=new int[right-left+1];//用于存放合并后的数组int k=0;while(s1<=e1&&s2<=e2){//if(array[s1]<=array[s2]){//将s1放入数组中tmpArr[k++]=array[s1++];}else{tmpArr[k++]=array[s2++];}}while(s1<=e1){tmpArr[k++]=array[s1++];}while(s2<=e2){tmpArr[k++]=array[s2++];}for (int i = 0; i <k; i++) {array[i+left]=tmpArr[i];//tmpArr数组的首元素的下标不一定为0,但一定为left}}private static void mergeSortFunc(int[] array,int left,int right){if(left>=right){//最小拆分组的数量为1return;}int mid=(left+right)/2;mergeSortFunc(array,left,mid);mergeSortFunc(array,mid+1,right);//递归拆分至最小组,准备排序后合并merge(array,left,mid,right);}public static void mergeSort1(int[] array){mergeSortFunc(array,0,array.length-1);}//非递归归并public static void mergeSort(int[] array){int gap=1;while(gap<array.length){for (int i = 0; i <array.length; i+=gap*2) {int left=i;int mid=left+gap-1;int right=mid+gap;//mid和right可能越界,这里我们将其归置到一个数组中if(mid>=array.length){mid=array.length-1;}if(right>=array.length){right=array.length-1;}merge(array,left,mid,right);}gap*=2;}}//计数排序public static void countArray(int[] array){int maxVal=array[0];int minVal=array[0];for (int i = 0; i <array.length; i++) {//找到数组里的最大值和最小值if(array[i]<minVal){minVal=array[i];}if(array[i]>maxVal){maxVal=array[i];}}//建立一个计数的数组int range=maxVal-minVal+1;int[] count=new int[range];//遍历数组,做计数统计for (int i = 0; i <array.length; i++) {int val=array[i];count[val-minVal]++;}//遍历计数数组,并重写array数组的元素int index=0;for (int i = 0; i < count.length; i++) {int val=count[i];while(val!=0){array[index++]=i+minVal;val--;}}}
}

测试代码

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;import java.util.Arrays;
import java.util.Random;/*** Created with IntelliJ IDEA.* Description:* User: Home-pc* Date: 2023-08-26* Time: 13:48*/
public class TestSort {public static void notOrderArray(int[] array){Random random=new Random();for (int i = 0; i < array.length; i++) {array[i]=random.nextInt(100);}}public static void testShellSort(int[] array){array=Arrays.copyOf(array,array.length);Sort.shellSort(array);System.out.println(Arrays.toString(array));}public static void testSelectSort(int[] array){array=Arrays.copyOf(array,array.length);Sort.selectSort(array);System.out.println(Arrays.toString(array));}public static void testSelectSort2(int[] array){array=Arrays.copyOf(array,array.length);Sort.selectSort2(array);System.out.println(Arrays.toString(array));}public static void testheapSort(int[] array){array=Arrays.copyOf(array,array.length);Sort.heapSort(array);System.out.println(Arrays.toString(array));}public static void testbubbleSort(int[] array){array=Arrays.copyOf(array,array.length);Sort.bubbleSort(array);System.out.println(Arrays.toString(array));}public static void testquickSort(int[] array){array=Arrays.copyOf(array,array.length);//long startTime=System.currentTimeMillis();Sort.quickSort(array);//long endTime=System.currentTimeMillis();System.out.println(Arrays.toString(array));//System.out.println("优化后排序时间"+(endTime-startTime));}public static void testquickSortByStack(int[] array){array=Arrays.copyOf(array,array.length);//long startTime=System.currentTimeMillis();Sort.quickSortByStack(array);//long endTime=System.currentTimeMillis();System.out.println(Arrays.toString(array));//System.out.println("优化后排序时间"+(endTime-startTime));}public static void testmergeSort(int[] array){array=Arrays.copyOf(array,array.length);//long startTime=System.currentTimeMillis();Sort.mergeSort(array);//long endTime=System.currentTimeMillis();System.out.println(Arrays.toString(array));//System.out.println("优化后排序时间"+(endTime-startTime));}public static void testcountArray(int[] array){array=Arrays.copyOf(array,array.length);//long startTime=System.currentTimeMillis();Sort.countArray(array);//long endTime=System.currentTimeMillis();System.out.println(Arrays.toString(array));//System.out.println("优化后排序时间"+(endTime-startTime));}public static void main(String[] args) {int[] array=new int[30];notOrderArray(array);System.out.println(Arrays.toString(array));testShellSort(array);notOrderArray(array);System.out.println(Arrays.toString(array));testSelectSort(array);notOrderArray(array);System.out.println(Arrays.toString(array));testSelectSort2(array);notOrderArray(array);System.out.println(Arrays.toString(array));testheapSort(array);notOrderArray(array);System.out.println(Arrays.toString(array));testbubbleSort(array);notOrderArray(array);System.out.println(Arrays.toString(array));testquickSort(array);notOrderArray(array);System.out.println(Arrays.toString(array));testquickSortByStack(array);System.out.println("我是分割线");notOrderArray(array);System.out.println(Arrays.toString(array));testmergeSort(array);System.out.println("我是分割线");notOrderArray(array);System.out.println(Arrays.toString(array));testcountArray(array);}
}
***

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


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

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

相关文章

【微服务部署】08-监控与告警

文章目录 1. PrometheusOperator1.1 优势1.2 配置脚本1.3 部署脚本 2. Granfana实现监控看板2.1 Granfana核心特性2.2 部署文件 3. prometheus-net收集自定义指标3.1 组件包3.2 使用场景 目前Kubernetes中最流行的监控解决方案是使用Prometheus和AlertManager 1. PrometheusOpe…

(超简单)将图片转换为ASCII字符图像

将一张图片转换为ASCII字符图像 原图&#xff1a; 效果图&#xff1a; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileWriter; import java.io.IOException;public class ImageToASCII {/*** 将图片转换为A…

React笔记(三)类组件(1)

一、组件的概念 使用组件方式进行编程&#xff0c;可以提高开发效率&#xff0c;提高组件的复用性、提高代码的可维护性和可扩展性 React定义组件的方式有两种 类组件&#xff1a;React16.8版本之前几乎React使用都是类组件 函数组件:React16.8之后&#xff0c;函数式组件使…

Linux CentOS7 系统中添加用户

在linux centOS7系统中&#xff0c;添加用户是管理员的基本操作。作为学习linux系统的基本操作&#xff0c;对添加用户应该多方面了解。 添加用户的命令useradd&#xff0c;跟上用户名&#xff0c;就可以快速创建一个用户。添加一些选项&#xff0c;可以设置更人性化的用户信息…

dbeaver离线安装clickhouse连接驱动

Clickhouse 数据库连接工具——DBeaver 主要介绍了Clickhouse 数据库连接工具——DBeaver相关的知识&#xff0c;希望对你有一定的参考价值。 Clickhouse 数据库连接工具——DBeaver 1.下载 DBeaver 和 连接驱动 https://dbeaver.io/files/dbeaver-ce-latest-x86_64-setup.…

清理docker镜像方法

首先stop ps -a里的容器&#xff0c;然后rm容器&#xff0c;最后再rmi镜像 先停止容器 rm容器 docker rmi 镜像 删除后可以发现已经不存在

【SpringSecurity】七、SpringSecurity集成thymeleaf

文章目录 1、thymeleaf2、依赖部分3、定义Controller4、创建静态页面5、WebSecurityConfigurerAdapter6、权限相关7、当用户没有某权限时&#xff0c;页面不展示该按钮 1、thymeleaf 查了下读音&#xff0c;leaf/li:f/&#xff0c;叶子&#xff0c;前面的单词发音和时间time一…

CNN 01(CNN简介)

一、卷积神经网络的发展 convolutional neural network 在计算机视觉领域&#xff0c;通常要做的就是指用机器程序替代人眼对目标图像进行识别等。那么神经网络也好还是卷积神经网络其实都是上个世纪就有的算法&#xff0c;只是近些年来电脑的计算能力已非当年的那种计算水平…

JavaScript -【第二周】

文章来源于网上收集和自己原创&#xff0c;若侵害到您的权利&#xff0c;请您及时联系并删除~~~ 理解什么是流程控制&#xff0c;知道条件控制的种类并掌握其对应的语法规则&#xff0c;具备利用循环编写简易ATM取款机程序能力 运算符语句综合案例 1. 运算符 算术运算符赋值运…

时间语义与窗口

时间语义 在Flink中&#xff0c;时间语义分为两种 &#xff1a; 处理时间和事件时间。时间语义与窗口函数是密不可分的。以窗口为单位进行某一段时间内指标统计&#xff0c;例如想要统计8点-9点的某个页面的访问量&#xff0c;此时就需要用到了窗口函数&#xff0c;这里的关键…

githubPage部署Vue项目

github中新建项目 my-web &#xff08;编写vue项目代码&#xff09; myWebOnline(存放Vue打包后的dist包里面的文件) 发布流程 &#xff08;假设my-web项目已经编写完成&#xff09;Vue-cli my-web vue.config.js文件中 const { defineConfig } require(vue/cli-service)…

【LeetCode】3. 无重复字符的最长子串

3. 无重复字符的最长子串&#xff08;中等&#xff09; 方法&#xff1a;滑动窗口 哈希表 思路 这道题主要用到思路是&#xff1a;滑动窗口 什么是滑动窗口&#xff1f; 其实就是一个队列,比如例题中的 abcabcbb&#xff0c;进入这个队列&#xff08;窗口&#xff09;为 ab…