排序算法(Java版)

目录

  • 1、直接插入排序
  • 2、希尔排序
  • 3、直接选择排序
  • 4、堆排序
  • 5、冒泡排序
  • 6、快速排序
    • 6.1 递归实现
    • 6.2 非递归实现
  • 7、归并排序
    • 7.1 递归实现
    • 7.2 非递归实现
  • 8、性能分析

今天我们学习一种算法:排序算法(本文的排序默认是从小到大顺序)!!!

1、直接插入排序

算法原理: 每次将无序序列中的第一个插入到有序序列当中,使有序序列仍为有序,第一趟排序默认第一个元素是有序的,类比于生活中的摸牌,每次将新的排插入已有的牌当中。直接插入排序的算法原理很简单,我们只需要找到每个元素该插入到哪个位置即可。
在这里插入图片描述

代码实现:

    public void InsertSort(int[] array) {for (int i = 1; i < array.length; i++) {int tmp = array[i];int j = i - 1;for (; j >= 0; j--) {if (array[j] > tmp) {array[j + 1] = array[j];} else {array[j + 1] = tmp;break;}}array[j + 1] = tmp;}}

代码图解:
在这里插入图片描述

2、希尔排序

算法原理: 希尔排序又称缩小增量排序,原理是先选定一个数作为分组的组数,将数组进行分组,接着分别对每个组进行排序,每组排序好之后,缩小分组的组数,重复上述步骤,直到组数为1。对每个组进行排序,我们使用插入排序的方法进行排序。
在这里插入图片描述

代码实现:

    public void ShellSort(int[] array) {int gap = array.length;//分成gap组,对每一组进行插入排序while (gap > 1) {gap /= 2;shell(array, gap);}}//对每组进行插入排序public void shell(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i - gap;for (; j >= 0; j -= gap) {if (array[j] > tmp) {array[j + gap] = array[j];} else {array[j + gap] = tmp;break;}}array[j + gap] = tmp;}}

3、直接选择排序

算法原理: 每次待排序序列中选择最小的元素和待排序的第一个元素交换
代码实现:

    public 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;}}//交换minIndex下标和i下标的值int tmp = array[minIndex];array[minIndex] = array[i];array[i] = tmp;}}

4、堆排序

算法原理: 堆排序是借用堆这种数据结构来实现的一种排序算法,如果升排序,建立大根堆;如果排降序,建立小根堆 。建堆之后:
1、交换0下标元素和最后一个元素的值
2、然后重新将数组进行向下调整为大根堆
重复这两个步骤,直到全部有序
在这里插入图片描述

代码实现:

    public void HeapSort(int[] array) {//先创建大堆createBigHeap(array);int end = array.length - 1;while (end >= 0) {//交换int tmp = array[0];array[0] = array[end];array[end] = tmp;ShiftDown(array, 0, end);end--;}}public void createBigHeap(int[] array) {for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {ShiftDown(array, parent, array.length);}}public void ShiftDown(int[] array, int parent, int end) {int child = parent * 2 + 1;while (child < end) {if (child + 1 < end && array[child] < array[child + 1]) {child++;}if (array[child] > array[parent]) {//交换int tmp = array[parent];array[parent] = array[child];array[child] = tmp;parent = child;child = parent * 2 + 1;} else {break;}}}    

5、冒泡排序

算法原理: 遍历数组,每次比较相邻两个元素的大小,如果大的数字在前则交换两个元素的位置,这样就完成了一趟冒泡排序,此时最大的数到了最后,然后对前n-1个数进行相同的操作,直到有序。
代码实现:

    public void BubbleSort(int[] array) {for (int i = 0; i < array.length-1; i++) {for (int j = i; j < array.length - i - 1; j++) {if (array[j] > array[j + 1]) {//交换int tmp = array[j];array[j] = array[j+1];array[j+1] = tmp;}}}}

问题:如果遍历一遍数组已经有序了,就不用再继续比较下去了,因此对上面代码进行优化
优化后:

    public void BubbleSort(int[] array) {boolean flg = false;for (int i = 0; i < array.length - 1; i++) {for (int j = i; j < array.length - i - 1; j++) {if (array[j] > array[j + 1]) {//交换int tmp = array[j];array[j] = array[j+1];array[j+1] = tmp;flg = true;}}if (!flg) {break;}}}

6、快速排序

算法原理: 快速排序的基本思想就是:选定一个基准,通过一趟快速排序之后,能把数据分割为两部分,左边部分比基准的值小,右边的部分比基准的值大,接着再按照这个方法分别对基准左边部分和右边部分进行递归,重复这个步骤直到整个序列都有序。快速排序的最重要部分就是如何将序列分割成两部分,常见的分割方法有hoare法和挖坑法
Hoare法分割: 先选定一个基准(默认是第一个元素),定义left、right下标,left从序列最右边开始找比基准小的值(升序排序),找到之后停下来,接着让left从最左边开始找比基准大的值,找到之后停下来,将找到的这两个值交换,当left和right相遇时(left=right),交换基准的值和left/right下标的值,这样left/right下标左边的元素全都比left/right下标的值小,右边的元素都比它大,这样就分割好了。
图解:
在这里插入图片描述

挖坑法:
和Hoare法的区别是:挖坑法是边找边交换,如图
在这里插入图片描述

6.1 递归实现

代码实现:

    public void QuickSort(int[] arr) {quick(arr, 0, arr.length - 1);}public void quick(int[] arr, int left, int right) {//递归结束的条件if (left >= right) {return;}//进行分割int pio = partition(arr, left, right);quick(arr, 0, pio - 1);quick(arr, pio + 1, right);}

hoare法分割

    public int partition(int[] arr, int left, int right) {int tmp = arr[left];int i = left;while (left < right) {while (left < right && arr[right] >= tmp) {right--;}while (left < right && arr[left] <= tmp) {left++;}//交换int tmp = array[right];array[right] = array[left];array[left] = tmp;}//交换int tmp = array[i];array[i] = array[left];array[left] = tmp;return left;}

挖坑法分割

    public int partition(int[] arr, int left, int right) {int tmp = arr[left];while (left < right) {while (left < right && arr[right] >= tmp) {right--;}arr[left] = arr[right];while (left < right && arr[left] <= tmp) {left++;}array[right] = array[left];}arr[left] = tmp;return left;}

优化: 如果待排序序列是:1、2、3、4、5这种有序的序列,假如还是取第一个元素为基准,就会出现左边没有小于基准的值,如何让每次分割都是均匀分割?方法很简单,取序列最左边、最右边和中间位置的三个元素的中位数作为基准,再进行Hoare法或者挖坑法分割,此时每次都能均匀分割,如图
在这里插入图片描述

优化后:

    public void QuickSort(int[] arr) {quick(arr, 0, arr.length - 1);}public void quick(int[] arr, int left, int right) {//递归if (left >= right) {return;}//中位数的值作为基准int midIndex = midThreeIndex(arr, left, right);//交换int tmp = arr[left];arr[left] = arr[midIndex];arr[midIndex] = tmp;    int pio = partition(arr, left, right);quick(arr, 0, pio - 1);quick(arr, pio + 1, right);}public int partition(int[] arr, int left, int right) {int tmp = arr[left];int i = left;while (left < right) {while (left < right && arr[right] >= tmp) {right--;}while (left < right && arr[left] <= tmp) {left++;}swap(arr, right, left);}swap(arr, i, left);return left;}        

6.2 非递归实现

原理: 利用栈这个数据结构来实现。首先先对序列进行一次分割(Hoare法或者挖坑法都可以),将基准左边部分的left、right下标入栈,再将右边部分的left、right下标入栈,然后出栈两个元素作为新的left、right来进行分割,重复上述步骤,直到栈为空
在这里插入图片描述

代码实现:

    public void QuickSortNoRecursion(int[] arr) {Stack<Integer> stack = new Stack<>();int left = 0;int right = arr.length - 1;int pio = partition(arr, left, right);if (pio > left + 1) {stack.push(left);stack.push(pio - 1);}if (pio < right - 1) {stack.push(pio + 1);stack.push(right);}while (!stack.isEmpty()) {right = stack.pop();left = stack.pop();pio = partition(arr, left, right);if (pio > left + 1) {stack.push(left);stack.push(pio - 1);}if (pio < right - 1) {stack.push(pio + 1);stack.push(right);}}}

7、归并排序

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

7.1 递归实现

递归思路: 先将序列进行分解,直到分解为单个元素为一组,然后再进行合并。合并:开辟新的数组,新的数组存储的是合并之后且有序的子序列,再开辟的新数组的元素拷贝回原数组

    public void mergeSort(int[] arr) {merge(arr, 0, arr.length - 1);}public void merge(int[] arr, int left, int right) {if (left >= right) {return;}int mid = (left + right) / 2;//分解merge(arr, left, mid);merge(arr, mid + 1, right);//合并mergeFun(arr, left, mid, right);}//合并public void mergeFun(int[] arr, int left,int mid, int right) {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 (arr[s1] < arr[s2]) {tmp[k++] = arr[s1++];} else {tmp[k++] = arr[s2++];}}while (s1 <= e1) {tmp[k++] = arr[s1++];}while (s2 <= e2) {tmp[k++] = arr[s2++];}//此时tmp有序了,拷回到原数组for (int i = 0; i < k; i++) {arr[left + i] = tmp[i];}}

7.2 非递归实现

非递归省去了分解的步骤,直接对数组进行合并

    //非递归public void mergeSortN(int[] arr) {mergeN(arr);}//没有分解的过程private void mergeN(int[] arr) {int gap = 1;while (gap <= arr.length) {for (int i = 0; i < arr.length; i = i + 2 * gap) {int mid = i + gap - 1;if (mid >= arr.length) {mid = arr.length - 1;}int right = mid + gap;if (right >= arr.length) {right = arr.length - 1;}mergeFun(arr, i, mid, right);}gap *= 2;}}public void mergeFun(int[] arr, int left,int mid, int right) {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 (arr[s1] < arr[s2]) {tmp[k++] = arr[s1++];} else {tmp[k++] = arr[s2++];}}while (s1 <= e1) {tmp[k++] = arr[s1++];}while (s2 <= e2) {tmp[k++] = arr[s2++];}//此时tmp有序了,拷回到原数组for (int i = 0; i < k; i++) {arr[left + i] = tmp[i];}}

8、性能分析

性能包括:时间复杂度、空间复杂度、稳定性

排序算法平均时间复杂度空间复杂度稳定性
插入排序O(n^2)O(1)稳定
希尔排序O(和增量有关)O(1)不稳定
选择排序O(n^2)O(1)不稳定
堆排序O(n*logn)O(1)不稳定
冒泡排序O(n^2)O(1)稳定
快速排序O(n*logn)O(logn)不稳定
归并排序O(n*logn)O(n)稳定

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

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

相关文章

C++纯C实现贪吃蛇小游戏

公众号&#xff1a;编程驿站 #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <time.h>//描述蛇的节点信息 typedef struct SnakeNode {int x;int y; } Snode;//箱子&#xff1a;放置蛇的所有节点 Snode snakes[100]; //保存…

渗透思考题

一&#xff0c;尝试登录。 客户端对密码进行哈希处理并缓存密码hash&#xff0c;丢弃实际的明文密码&#xff0c;然后将用户名发送到服务器&#xff0c;发起认证请求 密文存储位置&#xff1a;数据库文件位于C:WindowsSystem32configsam&#xff0c;同时挂载在注册表中的HKLMSA…

C语言【文件操作 1】

文章目录 1.为什么使用文件2.文件是什么&#xff1f;2.1程序文件2.2数据文件 3.二进制文件和文本文件4.文件的打开和关闭4.1流和标准流流标准流 4.2文件指针4.3文件的打开和关闭 结语 1.为什么使用文件 很简单 长久的存储数据 如果没有文件&#xff0c;我们写程序所产生的数据…

商米-android-使用NFC读IC卡,身份证云解和IC卡同时兼容

商米介绍地址&#xff1a;https://www.sunmi.com/ 商米是一个提供手持PDA的一个很好的解决方案厂商&#xff0c; 也有其他的一些桌面设备。 其中商米提供的软件服务中&#xff0c;比较特别的是 身份证云解功能。 此处重点说明一下&#xff0c;身份证云解功能。 以往市面上的身…

Vue学习JSON.stringify()将Object类型转换成String类型

Vue学习JSON.stringify&#xff08;&#xff09;将Object类型转换成String类型 一、前言1、基本用法2、复杂对象转换3、过滤器函数4、序列化函数 一、前言 JSON.stringify() 是一个 JavaScript 函数&#xff0c;用于将 JavaScript 值转换为 JSON 字符串。它接受一个 JavaScrip…

深入探索MySQL视图

前言 在数据库的世界里&#xff0c;MySQL视图作为数据抽象的一把利剑&#xff0c;为我们提供了一种灵活而高效的方式来管理和查询数据。它不仅能够简化复杂的查询逻辑&#xff0c;还能在不改动底层数据结构的前提下&#xff0c;实现数据的定制化展示与访问控制。本文旨在深入解…

【小红书采集工具】根据搜索关键词批量采集小红书笔记,含笔记正文、笔记链接、发布时间、转评赞藏等

一、背景介绍 1.1 爬取目标 熟悉我的小伙伴都了解&#xff0c;我之前开发过2款软件&#xff1a; 【GUI软件】小红书搜索结果批量采集&#xff0c;支持多个关键词同时抓取&#xff01; 【GUI软件】小红书详情数据批量采集&#xff0c;含笔记内容、转评赞藏等&#xff0c;支持…

【C++】string类的使用①(默认成员函数 || 迭代器接口begin,end,rbegin和rend)

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; STL || C 目录 前言&#x1f308;关于string类&#x1f308;string类的成员函数&#x1f525;默认成员函数string类对象的构造(constructor)string类对象的析构string类对象的赋值运算符…

NPOI生成word浮动图标

1、NPOI版本2.7.0, net框架4.8 2、安装OpenXMLSDKToolV25.msi 3、先创建一个word文档&#xff0c;并设置图片为浮于文字之上 4、OpenXML显示的结果 5、实际代码如下&#xff1a; public class GenerateWordDemo {public GenerateWordDemo(){}//https://blog.fileformat.co…

js由那三部分组成

JavaScript 主要由三部分组成&#xff1a;ECMAScript、DOM&#xff08;文档对象模型&#xff09;和 BOM&#xff08;浏览器对象模型&#xff09;。 1、ECMAScript ECMAScript 是 JavaScript 的核心&#xff0c;描述了语言的基本语法&#xff08;变量、函数、条件语句、循环、…

前端笔记-day03

文章目录 01-初始CSS02-CSS引入方式03-标签选择器04-类选择器05-id选择器06-通配符选择器07-画盒子08-字体大小09-文字粗细10-字体倾斜11-行高12-行高垂直居中13-字体族14-font复合属性15-文本缩进16-文本对齐方式17-图片对齐方式18-文本修饰线19-文字颜色20-调试工具21-综合案…

Dual Aggregation Transformer for Image Super-Resolution论文总结

题目&#xff1a;Dual Aggregation Transformer&#xff08;双聚合Transformer&#xff09; for Image Super-Resolution&#xff08;图像超分辨&#xff09; 论文&#xff08;ICCV&#xff09;&#xff1a;Chen_Dual_Aggregation_Transformer_for_Image_Super-Resolution_ICCV…

IM 是什么?

在当今数字化的时代&#xff0c;即时通讯&#xff08;IM&#xff09;已经渗透到人们的日常生活和企业的工作环境中。IM技术的快速i发展为人们提供了一种高效、便捷的沟通方式&#xff0c;不仅推动了社会的信息化进程&#xff0c;也提升了企业的协同效率和竞争力。 作为企业级I…

【GD32】01-GPIO通用输入输出

GD32 闲话说在前头 这里又开一个系列啦。 原因就是之前买了立创开发板的9.9的GD32E230C8T6的板子&#xff0c;买都买了就跟着立创开发板学习一下&#xff08;属于是一次性支持了两个国产品牌了&#xff0c;立创和兆易创新&#xff09;。并且我还买了GD32F407VET6的板子&…

资金流分析下的企业供货关系强度模型

图技术 利用neo4j、networkx、dgl、python做图分析挖掘 【1】最短路径算法dijkstra 【2】基于networkx的隐性集团关系识别模型 【3】基于Neo4j的担保社群型态分析挖掘 【4】基于python求有向无环图中target到其他节点全路径 【5】有向图中任意两点的路径 【6】图基础入门 【7】…

项目管理中控制质量的工具与技术

项目管理中控制质量的工具与技术 控制质量的工具与技术包括多种方法&#xff0c;旨在确保产品或服务达到既定的质量标准。关于具体的工具格式和样式&#xff0c;以下是一些示例&#xff1a; 统计技术&#xff1a; 这是一种将质量控制要素的数据转化为实际控制手段的技术。通…

Visual Studio和Visual Studio Code适用于哪些编程语言

Visual Studio和Visual Studio Code都适用于多种编程语言&#xff0c;它们的适用编程语言如下&#xff1a; Visual Studio适用于&#xff1a; C#Visual Basic .NETF#CJavaScriptTypeScriptPythonHTML/CSSJava&#xff08;通过插件支持&#xff09; Visual Studio Code适用于…

Jtti:哪些方法可以降低美国CN2服务器的延迟?

降低美国CN2服务器的延迟可以采取多种方法&#xff0c;以下是一些常用的方法&#xff1a; 1.选择优质的网络提供商和服务商&#xff1a;选择具有高质量网络和优质服务的网络提供商和服务商是降低延迟的关键。确保您选择的网络提供商具有可靠的基础设施和优质的网络连接&#xf…

C++:关于圆形鱼眼半全景图转为等距圆柱投影图

C&#xff1a;空间坐标映射到球面坐标/全景图_如何将球体坐标映射到球面uv-CSDN博客 C&#xff1a;关于360全景图像和立方体6面全景图像的相互转换_彩色全景拆解正方体6个面-CSDN博客 之前记录了立方体和360全景之间的转换&#xff0c;这次记录下鱼眼图与360全景图之间的转换…

C++ STL的锁介绍

在 C Standard Template Library (STL) 中&#xff0c;有几个锁的实现&#xff0c;这些都位于 <mutex> 头文件。以下是一些常见的锁及其功能&#xff1a; std::mutex&#xff1a;最基本的互斥锁&#xff0c;不可递归使用。该锁提供了独占的非公平锁定能力。 std::mutex…