目录

排序

排序的应用

排序简介

排序的分类

排序算法的好坏评判

冒泡排序法

思路分析

代码实现

选择排序法

思路分析

代码实现

插入排序

思路分析

代码实现

希尔排序

思路分析

代码演示

归并排序法

思路分析

代码演示

快速排序

思路分析

代码实现

堆积排序法

思路分析

代码实现

基数排序法

思路分析

代码演示

八大排序稳定性总结


排序

排序的应用

在信息时代的发展下 随着大时代和人工智能(Artificial Intelligence,AI)技术的普及和应用,企业所拥有的的数据量成倍数的增长,排序算法更是成为了不可或缺的重要工具之一

 那么排序会应用到什么地方呢?

例如我们要去消费! 怎么消费?今天想去买个手机 那么我们要先打开购物平台,来搞一部iPhone14来耍一耍

他们之间有一种筛选方式就为价格排序,我们来考虑优先价格的优势下靠谱的店家,再来点个外卖,他们之间的价格也可以形成排序 不单单是价格,销量、评分、星级的评比都会使用到排序

                                 

再来往深处走一走,我们平时玩的游戏的场景也会遇到排序问题,在游戏中,需要处理多边形模型中隐藏面消除的过程中,不管场景中的多边形有没有挡住其他的多边形,只要按照从后面到前面的顺序的游戏中光栅化图形就可以正确的显示出所有课件的图形,其实就是可以沿着观察方向,按照多边形的深度信息对它们进行排序处理,这样就能形成我们可以看到的3D效果


 那么我们以下开始正文


排序简介

在排序的过程中,数据的移动方式可分为“直接移动”和“逻辑移动”

直接移动:直接移动是直接交换存储数据的位置;

  逻辑移动:逻辑移动并不会移动数据的存储位置,仅改变指向这些数据的辅助指针的值;

优劣性:直接移动会浪费许多时间进行数据的移动,而逻辑移动只要改变辅助指针指向的位置就能轻易达到排序的目的

数据在进行排序后会有以下好处:

·数据较容易阅读

·数据有利于统计与整理

·可大幅减少数据查找的时间


排序的分类

排序按照执行使用的内存种类区可分为以下两种方式:

·内部排序:排序的数据量小,可以全部加载到内存中进行排序

·外部排序:排序的数据量大,无法一次性全部加载到内存中进行排序,而必须借助硬盘进               行排序

分享一个冷知识

我们所知计算机中有以下存储类型,他们类似一个金字塔形状,首先运行速度是缓存区>内存>硬盘,但是存储大小缓存区<内存<硬盘

排序算法的好坏评判

        ·算法的稳定与否

        ·时间复杂度

        ·空间复杂度

是的 我们又回到了之前的内容,复杂度,如果对于复杂度理解还是比较浅薄的话 时间复杂度(点击即可进入博客)https://guobinglin.blog.csdn.net/article/details/125949648?spm=1001.2014.3001.5502  空间复杂度(点击即可进入博客)https://guobinglin.blog.csdn.net/article/details/127146252?spm=1001.2014.3001.5502

我们又可以串联起来之前的内容,这幅图中少了一项基数排序法,基数排序法属于高级排序,是一个稳定算法,时间复杂度最坏为O(N+R),空间复杂度为O(R)


冒泡排序法

思路分析

冒泡排序又称交换排序法,是从观察水中气泡变化构思而成,原理是从第一个元素开始,比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较,就仿佛气泡逐渐从水底上升到水面上一样

 

 

大概思路就是这样 我们只是简单的绘画一下 以下动图为一个数组完整的交换过程

代码实现

public class Main {public static void main(String[] args) {int[] arr=new int[]{6,5,9,7,2,8};int i=0;int j=0;System.out.println("排序前");for(i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}System.out.println();for (i = 0; i < arr.length - 1 ; i++) {for (j = 0; j < arr.length - i - 1; j++){if(arr[j]>arr[j+1]){int tmp=arr[j];arr[j]=arr[j+1];arr[j+1]=tmp;}}}System.out.println("排序后");for(i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}System.out.println();}
}

以上代码是未改进前的冒泡排序,他有一个缺点,就是不管数据是否已排序完成都会固定的执行n(n-1)/2次,我们仔细分析一下,在动图中,如果他有一次遍历没有发生任何的数据交换,那么代表已经有序了,我们来改进一下代码

public class Main {public static void main(String[] args) {int[] arr=new int[]{6,5,9,7,2,8};int i=0;int j=0;boolean fly;System.out.println("排序前");for(i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}System.out.println();for (i = 0; i < arr.length - 1 ; i++) {fly=false;for (j = 0; j < arr.length - i - 1; j++){if(arr[j]>arr[j+1]){fly=true;int tmp=arr[j];arr[j]=arr[j+1];arr[j+1]=tmp;}}if(!fly){break;}}System.out.println("排序后");for(i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}System.out.println();}
}

这样改进后会有概率使我们算法的时间复杂度大大降低 !


选择排序法

思路分析

选择排序法为在所有数据中,当从小到大排序,就设定一个哨兵去找出这个数组中的最小值,然后将这位最小值请到第一位,依次向后找第二位第三位,当从大到小排序那么理所应当就是去找最大值了

再来一幅动图理解一下全过程

代码实现

public class Main1 {public static void main(String[] args) {int[] arr=new int[]{9,7,5,3,4,6};System.out.println("排序前");for (int i = 0; i < arr.length; i++) {System.out.print(arr[i]+" ");}System.out.println();for (int i = 0; i <arr.length ; i++) {int min=i;for (int j = i; j <arr.length ; j++) {if(arr[j]<arr[min]){min=j;}}if(min!=i){int tmp=arr[min];arr[min]=arr[i];arr[i]=tmp;}}System.out.println("排序后");for (int i = 0; i <arr.length ; i++) {System.out.print(arr[i]+" ");}System.out.println();}
}

运行结果


插入排序

思路分析

插入排序法是将数组中的元素,逐一与已排序好的数据进行比较,前两个元素先排序好,再将第三个元素插入适当的位置,所以这三个元素仍然是已排序好的,接着再将第四个元素加入,重复此步骤,直到排序完成为止;

以下为动图

代码实现

 public static void main(String[] args) {int[] arr=new int[]{9,7,5,3,4,6};int j=0;System.out.println("排序前");for (int i = 0; i < arr.length; i++) {System.out.print(arr[i]+" ");}System.out.println();for (int i = 1; i < arr.length; i++) {int tmp=arr[i];for (j = i-1; j >=0 ; j--) {if(tmp<arr[j]){arr[j+1]=arr[j];}else {break;}}arr[j+1]=tmp;}System.out.println("排序后");for (int i = 0; i < arr.length; i++) {System.out.print(arr[i]+" ");}}

运行结果


希尔排序

思路分析

希尔排序可以减少插入排序法中的数据搬移的次数,以加速排序的进行,排序的原则是将数据区分成特定间隔的几块小区块,以插入排序拍完区块内的数据后再渐渐减少间隔的距离

(1)首先,将数据分为两块小区块即为Y=N/2(N为数组的长度)//划分不一定为2,指数最好,但是为了计算方便 我们习惯使用选择2 故一开始的话Y=8/2 Y=4

(2)区分完成后我们可以得到分为了四个区块 他们内容分别为:(63、45)(92、71)(27、58)(26、7) 再分别使用插入排序法排序成 (45、63)(71、92)(27、58)(7、26),在队列中的数据排序为下图

(3)接着继续缩小间隔为(8/2)/2,如图所示

(4)再继续使用插入排序,得到以下结果

 (5)再以((8/2)/2)/2继续进行插入排序 最后我们可以得到结果为:

代码演示

 /*** 排序* @param data*/public static void shell(int[] data){int i;//扫描次数int j;//j来定位比较的元素int k=1;//打印计数int tmp;//暂存int jmp=data.length/2;//间距位while(jmp!=0){for (i=jmp;i<data.length;i++){tmp=data[i];j=i-jmp;while(j>=0&&tmp<data[j]){data[j+jmp]=data[j];j=j-jmp;}data[jmp+j]=tmp;}jmp=jmp/2;}}/*** 打印数组中内容* @param data*/public static void printData(int[] data){for (int i = 0; i <data.length ; i++) {System.out.print(data[i]+"  ");}System.out.println();}public static void main(String[] args) {int[] data=new int[]{63,92,27,26,45,71,58,7};System.out.println("排序前");printData(data);shell(data);System.out.println("排序后");printData(data);}


归并排序法

思路分析

合并排序工作原理是针对已排序好的两个或两个以上的数列通过合并的方式,将其合成一个大的且已排好序的数列

步骤如下

(1)将N个长度为1的键值,成对的合并成N/2个长度为2的键值组

(2)将N/2个长度为2的键值组,成对的合并成N/4个长度为4的键值组

(3)将键值组不断的合并,直到合并为一组长度为N的键值组为止

代码演示

public static int[] sortArray(int[] nums) {mergeSort(nums,0,nums.length-1);return nums;}public static void mergeSort(int[] arr, int left, int right) {if (left < right) {int mid = left + ((right - left) >> 1);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[] temparr = new int[right -left + 1];int temp1 = left, temp2 = mid + 1;int index = 0;//对应第二步,比较每个指针指向的值,小的存入大集合while (temp1 <= mid && temp2 <= right) {if (arr[temp1] <= arr[temp2]) {temparr[index++] = arr[temp1++];} else {temparr[index++] = arr[temp2++];}}//对应第三步,将某一小集合的剩余元素存到大集合中if (temp1 <= mid) System.arraycopy(arr, temp1, temparr, index, mid - temp1 + 1);if (temp2 <= right) System.arraycopy(arr, temp2, temparr, index, right -temp2 + 1);     //将大集合的元素复制回原数组System.arraycopy(temparr,0,arr,0+left,right-left+1);}public static void printData(int[] data){for (int i = 0; i <data.length ; i++) {System.out.print(data[i]+"  ");}System.out.println();}public static void main(String[] args) {int[] data=new int[]{36,16,41,72,52,98,63,25};System.out.println("排序前");printData(data);sortArray(data);System.out.println("排序后");printData(data);}


快速排序 

思路分析

快速排序也称分割交换排序法,是目前公认的最佳的排序法,先会在数据中找到一个虚拟的中间值,并按此中间值将所有打算排序的数据分为两部分,其中小于中间值的放在左边,大于中间值的放在右边,再以同样的方式分别处理左右两边的数据,直到排序完为止,具体操作如下:

1.先假设K的值为第一个中间值

2.从左向右找出中间值K,使得Ki<K

3.从右向左找出中间值K,使得Kj>K

4.如果i<j,那么交换Ki与Kj的值,并且回到步骤2

5.若i>=j,则将K与Kj做交换,并且以j为基点分割成左右部分,然后再 针对左右两边重复步骤1到步骤5,直到左边边值=右半边值为止

步骤如下:

因为i<j,所以交换两个下标的值

再次重复步骤2

因为i<j,所以交换两个下标的值

继续重复步骤2

经过以上的步骤,可以将小于K的数据放在左半部,大于K的数据放在右半部,按照上述排序过程,对左右分为两部分再进行分别排序

排序算法的核心就是如何利用基准数将记录分区,这里我们主要介绍一种容易理解的方法,利用双指针思想进行元素交换。 还有一种挖坑填坑的思想,暂不做介绍

代码实现

class Solution {public int[] sortArray (int[] nums) {quickSort(nums,0,nums.length-1);return nums;}public void quickSort (int[] nums, int low, int hight) {if (low < hight) {int index = partition(nums,low,hight);quickSort(nums,low,index-1);quickSort(nums,index+1,hight);}}public int partition (int[] nums, int low, int hight) {int pivot = nums[low];int start = low;while (low < hight) {while (low < hight && nums[hight] >= pivot) hight--;while (low < hight && nums[low] <= pivot) low++;if (low >= hight) break;swap(nums, low, hight);}//基准值归位swap(nums,start,low);return low;}public void swap (int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}public class Main {public static void main(String[] args) {Solution solution=new Solution();int[] elem=new int[]{35,10,42,3,79,12,62,18,51,23};System.out.println("排序前");System.out.println(Arrays.toString(elem));solution.sortArray(elem);System.out.println("排序后");System.out.println(Arrays.toString(elem));}
}


堆积排序法

思路分析

堆积排序是选择排序的改进版,他可以减少选择排序法中的比较次数,进而减少排序时间,堆积排序其实是利用到了二叉树的技巧,它是通过对技术来完成排序的,而要实现这种二叉树,我们还需要利用到最大堆和最小堆,也被称为大堆和小堆

我们来介绍一下大堆和小堆的特征:

大堆:

·他是一个完全二叉树(满二叉树也可)

·所有根节点的值大于等于左右节点的值

·树根的值为堆积树中的 最大值

小堆:

·他是一个完全二叉树(满二叉树也可)

·所有根节点的值小于等于左右节点的值

·树根的值为堆积树中的 最小值

我们对大堆和小堆已经有了一个基本的了解, 我们下面来实现一下堆积排序法思路

首先建立堆积树,我们按照大堆来实现,所以说 我们最后得到的结果会使从小到大的排序

大堆积树

将57从树根返回并删除,重现建立堆积树,这边我们要提到一点,如果要删除树根的话,我们的操作是要先将完全二叉树的最后一个节点与树根的值做交换,我们再返回并删除最后一个节点,再将树根的值看做新加入的元素换到左右子树中较小的一端,依次比较直到找到合适的位置或到叶子

将43从树根删除,重新建立堆积树

将40从树根删除,重新建立堆积树

将34从树根删除,重新建立堆积树

将19从树根删除,重新建立堆积树

将17从树根删除,重新建立堆积树

将14从树根删除,重新建立堆积树

将4从树根删除,我们可以得到的排序是

代码实现

class Solution1 {public int[] sortArray(int[] nums) {int len = nums.length;int[] a = new int[len + 1];for (int i = 0; i < nums.length; ++i) {a[i+1] = nums[i];}//下沉建堆for (int i = len/2; i >= 1; --i) {sink(a,i,len);}int k = len;//排序while (k > 1) {swap(a,1,k--);sink(a,1,k);}for (int i = 1; i < len+1; ++i) {nums[i-1] = a[i];}return nums;}public void sink (int[] nums, int k,int end) {//下沉while (2 * k <= end) {int j = 2 * k;//找出子节点中最大或最小的那个if (j + 1 <= end && nums[j + 1] > nums[j]) {j++;}if (nums[j] > nums[k]) {swap(nums, j, k);} else {break;}k = j;}}public void swap (int nums[], int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}}
public class Main2 {public static void main(String[] args) {Solution solution=new Solution();int[] elem=new int[]{34,19,40,14,57,17,4,43};System.out.println("排序前");System.out.println(Arrays.toString(elem));solution.sortArray(elem);System.out.println("排序后");System.out.println(Arrays.toString(elem));}
}


基数排序法

思路分析

基数排序法使用的思路非常简单,而且与之前的排序法大不相同,它并不需要元素直接的比较来确定位置,而是属于一种分配模式排序方式,我们直接看图就可以理解它的思路

原始数据如下

将每个整数按其个位数字放到列表中

将每个整数按照其十位数字放到列表中

 合并后成为:

将每个整数按照其百位数字放到表中

合并后成为:

如此一来我们便完成了排序,是不是很神奇

代码演示

class Solution3{public  void radixSort(int[] data) {int maxBin = maxBin(data);List<List<Integer>> list = new ArrayList<List<Integer>>();for (int i = 0; i < 10; i++) {list.add(new ArrayList<Integer>());}for (int i = 0, factor = 1; i < maxBin; factor *= 10, i++) {for (int j = 0; j < data.length; j++) {list.get((data[j] / factor) % 10).add(data[j]);}for (int j = 0, k = 0; j < list.size(); j++) {while (!list.get(j).isEmpty()) {data[k] = list.get(j).get(0);list.get(j).remove(0);k++;}}}}//计算数组里元素的最大位数public  int maxBin(int[] data) {int maxLen = 0;for (int i = 0; i < data.length; i++) {int size = Integer.toString(data[i]).length();maxLen = size > maxLen ? size : maxLen;}return maxLen;}}
public class Main3 {public static void main(String[] args) {Solution3 solution=new Solution3();int[] elem=new int[]{59,95,7,34,60,168,171,259,372,45,88,133};System.out.println("排序前");System.out.println(Arrays.toString(elem));solution.radixSort(elem);System.out.println("排序后");System.out.println(Arrays.toString(elem));}}


八大排序稳定性总结

稳定:插入排序,冒泡排序,归并排序,基数排序,希尔排序

不稳定:选择排序,快速排序,堆积排序

《数据结构》八大排序(详细图文分析讲解)相关推荐

  1. 八大排序 —— 详细图文讲解

    文章目录 排序的概念 常见的排序算法 冒泡排序 堆排序 插入排序 希尔排序(缩小增量排序) 选择排序 快速排序 划分 一.Hoare版本 二.挖坑法 三.前后指针 整体排序--递归 优化 针对选key ...

  2. 八大排序算法稳定性分析

    八大排序算法稳定性分析 稳定性定义: 排序前后两个相等的数相对位置不变,则算法稳定. 稳定性的好处: 从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用. 各排序算法的稳 ...

  3. 八大排序算法图文讲解

    排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 常见的内部排序算法有:插入排序.希尔排序. ...

  4. 【数据结构排序算法系列】数据结构八大排序算法

    排序算法在计算机应用中随处可见,如Windows操作系统的文件管理中会自动对用户创建的文件按照一定的规则排序(这个规则用户可以自定义,默认按照文件名排序)因此熟练掌握各种排序算法是非常重要的,本博客将 ...

  5. 冒泡和快速排序的时间复杂度_八大排序算法性能分析及总结

    一.排序算法说明 排序的定义:对一个无序的序列进行排序的过程. 输入:n个数:a1,a2,a3,-,an. 输出:n个数的排列:a1,a2,a3,-,an,使得a1<=a2<=a3< ...

  6. 数据结构——八大排序(全)

    目录 排序的基本概念和分类 排序算法的稳定性 内排序和外排序 1. 时间性能 2.辅助空间 3.算法的复杂性 4.排序用到的结构体和函数 冒泡排序 排序原理 代码 代码1 代码2(正宗的冒泡排序) 代 ...

  7. 支持向量机(SVM)----超详细原理分析讲解

    文章目录 支持向量机(SVM) 直观的本质理解 几个基础概念 决策超平面的求解(SVM模型的推导) 最大硬间隔的寻找与公式构建 拉格朗日乘数法的应用 使用对偶问题求解 一个小例子(求解决策超平面与决策 ...

  8. 数据结构——八大排序

    插入排序 基本思想 插入排序的直观理解就是:整理扑克牌.当我们玩扑克牌时,常常把7放到6和9之间.插入排序的基本思想就是把待排序的记录按其大小逐个插入到已经排好序的有序序列中,知道所有的记录插入完为止 ...

  9. 八大排序算法稳定性分析,原来稳定性是这个意思...

    点击上方蓝字"轮子工厂"关注公号 后台回复"我要造轮子"获取100本经典图书 稳定性定义: 排序前后两个相等的数相对位置不变,则算法稳定. 稳定性得好处: 从一 ...

最新文章

  1. 2015最流行的Android组件、工具、框架大全
  2. Redhat Enterprise linux 5 的安装
  3. Access2007及以后的版本中的数据库连接字符串
  4. Elasticsearch 实现自定义排序插件
  5. POJ 2227 The Wedding Juicer——堆的应用——Pku2227
  6. Devuan Jessie beta 释出
  7. java+中的final关键字有哪些用法_Java中的Final关键字用法汇总及简单示例
  8. 打败 Python、JS、C# 成最受欢迎编程语言,是时候掌握 Rust 了吗?
  9. 后端 消息 转发_springCloud 后端使用webSocket向前端推送消息
  10. Lesson 08 for Plotting in R for Biologists
  11. 智能水表营收管理系统
  12. 批处理for循环命令初步学习
  13. NAND Flash底层原理,SLC MLC TLC比较
  14. 管家婆的验证服务器失败,管家婆登陆提示“连接服务器失败”怎么办
  15. 构造函数,静态关键字,静态代码块,构造代码块,局部代码块
  16. git+vimdiff 一次关闭所有文件
  17. 简单理解SpringMVC的三层结构顺序MCV以及ModelAndView的使用
  18. 12个在线网站测速工具——web性能
  19. Unity3D图集图片裁剪
  20. MFC+OpenGL三维绘图(一)——简单绘图平台的搭建与实现图像的旋转、缩放

热门文章

  1. 【软件安装】远程桌面软件系列
  2. 开个新栏目,起个恬淡的名字
  3. stm32学习开发记录:OLED——I2C
  4. **图片元信息Exif**
  5. 2019秋招备战复习篇
  6. Linux 查看ip没有ens33解决方法
  7. 【Docker镜像文件加载原理生产中重新制作并提交镜像文件案例演示】
  8. win7电脑怎么提升开机速度?
  9. JAVA代理模式与动态代理模式
  10. 关键字搜索软件_高效搜索神器,你选listary还是火柴?