JAVA 排序工具类

提供了以下排序:

  1. 冒泡排序
  2. 选择排序
  3. 插入排序
  4. 希尔排序
  5. 快速排序
  6. 归并排序
  7. 桶排序
  8. 堆排序

 
 

package com.xingej.algorithm.sort;import java.util.ArrayList;
import java.util.Collections;/*** 排序工具类* * @author erjun 2017年12月13日 上午8:38:22*/public class SortUtils {// 私有构造器,禁止外界创建对象private SortUtils() {}// --------1、冒泡排序------/*** * 冒泡排序核心:1、从数组的最后一个元素,开始比较;2、两两比较,满足条件的话,就需要进行位置的互换* * 实际生活中:小学时,需要根据身高进行座位排序,就可以使用冒泡排序进行。* */public static void bubbleSort(int[] arr) {int temp;// 4 3 2 1,按冒泡排序的话,需要进行3轮比较可以了for (int i = 0; i < arr.length - 1; i++) {// 每一轮比较,找出本轮的最小值for (int j = arr.length - 1; j > i; j--) {// 后面的/下面的水泡 小于 上面的水泡,就移位if (arr[j] < arr[j - 1]) {// java 是引用传递temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;}}}}// --------2、选择排序------/*** * 选择排序的核心:* * 扫描所有的元素,得到最小的元素,并将最小的元素与左边第一个元素进行交换。再次扫描除* * 第一位置的所有元素,得到最小的元素,与左边第二个元素进行交换。依次类推* * 选择排序是建立在冒泡排序的基础之上的,* * 冒泡排序的缺点,每一轮交换的次数太多了,为了解决这个问题,出现选择排序* * 解决思路,很明显,既然冒泡排序每一轮的交换次数太多,那就,每一轮,最多交换依次,就是说,每一轮只将最小值* * 找出来,进行交换,* * 按照这个思路,去写"选择排序"* */public static void selectSort(int[] arr) {int minIndex = 0; // 每次两两比较时,如a>b,那么minIndex就是b的下标int value;for (int i = 0; i < arr.length - 1; i++) {minIndex = i;value = arr[minIndex]; // 每一轮未排序元素的第一个值// 这个for,每一次,都会找出未排序元素的最小下标for (int j = i + 1; j < arr.length; j++) {if (arr[minIndex] > arr[j]) {minIndex = j;// 将最小下标赋值给minIndex}}// 将最小值与第一个元素,进行交换arr[i] = arr[minIndex];arr[minIndex] = value;}}// --------3、插入排序------/*** 插入排序,的思想跟冒泡排序和选择排序不同* * 使用场景很像打牌时,每抓到一个张牌,按照大小插入到"已经排序好"的牌里* * 实际应用场景:有排序好的元素,还有一些未排序的元素,这个时候可以考虑插入排序* * 其实,将待排序的元素,插入到已经排序好的元素时,* * 可以使用别的排序方法,来进行,不必循序查询比较排序,可以使用快速排序* * @param arr*/public static void insertSort(int[] arr) {// right表示,未排序的元素for (int right = 1; right < arr.length; right++) {int temp = arr[right]; // 做备份int left = right - 1;// left 表示: 左边已经排序好的元素// 比方说,左边已经排序好的元素有 1 2 4 6// 待排序元素为3,// 将3依次跟6,4,2,1进行比较,直到找到合适的位置,// 也就是,找到合适的数组下标leftwhile (left >= 0 && arr[left] > temp) {arr[left + 1] = arr[left];left--;}// 为什么left+1呢?// 因为,上面的while循环中,left 减 1 之后, 不满足循环条件的,// 因此,需要将temp值放到left+1的位置上去arr[left + 1] = temp;}}// --------4、希尔排序------public static void shellSort(int[] arr) {int left; // 左边下标,表示,已经排序好的元素int right; // 右边下标,表示,待排序元素/就是没有排序的元素int temp; // 临时存储int h = 1; // 初始间隔为1;// 计算最大间隔while (h < arr.length / 3) {h = 3 * h + 1;}while (h > 0) {// 表示循环待排序的元素for (right = h; right < arr.length; right++) {temp = arr[right]; // 先将待排序的元素,进行缓存一下left = right; //// 为什么是left>h-1,// 目前我认为是,保证arr[left-h] 得有值,不能为空,或者说,报空指针异常吧while (left > h - 1 && arr[left - h] >= temp) {arr[left] = arr[left - h];left = left - h;}// 这里,千万不要写成下面的形式, 不能再left-h,因为,上面的while()循环,已经减去了// arr[left - h] = temp;arr[left] = temp;}// 重新调整排序间隔h = (h - 1) / 3;}}// --------5、快速排序------public static void quickSort(int arr[]) {recQuickSort(arr, 0, arr.length - 1);}// 使用递归和划分技术进行快速排序private static void recQuickSort(int arr[], int left, int right) {int size = right - left + 1;if (size < 10) {insertSort(arr, left, right);} else {int median = medianof3(arr, left, right);int partition = partitionIt(arr, left, right, median);recQuickSort(arr, left, partition - 1);recQuickSort(arr, partition + 1, right);}}// 划分方法,返回分割点的索引private static int partitionIt(int arr[], int left, int right, int pivot) {int leftPtr = left;int rightPtr = right - 1;while (true) {// 从左往右找大于特定值的while (arr[++leftPtr] < pivot); // 循环结束,就代表,找到一个大于特定值的数据项// 从右向左找小于特定值while (arr[--rightPtr] > pivot);if (leftPtr >= rightPtr) {break; // 结束时,leftPtr = rightPtr} else {swap(arr, leftPtr, rightPtr); // 交换}}swap(arr, leftPtr, right - 1);return leftPtr;}// 找出中间值// 索引为left,right,以及中间值的 进行排序,private static int medianof3(int arr[], int left, int right) {int centerIndex = (left + right) / 2;if (arr[left] > arr[centerIndex]) {swap(arr, left, centerIndex);}if (arr[left] > arr[right]) {swap(arr, left, right);}if (arr[centerIndex] > arr[right]) {swap(arr, centerIndex, right);}swap(arr, centerIndex, right - 1);return arr[right - 1];}private static void insertSort(int arr[], int left, int right) {int in, out;int temp; // 临时缓存,待存储的元素for (out = left + 1; out <= right; out++) {temp = arr[out];in = out;while (in > left && arr[in - 1] >= temp) {arr[in] = arr[in - 1];in--;}arr[in] = temp;}}private static void swap(int arr[], int left, int right) {int temp = arr[left];arr[left] = arr[right];arr[right] = temp;}// --------6、归并排序------// 归并两个已经有序的数组// 首先将数组,拆分成两部分,左边做成有序的,同样,右边也做成有序的。// 将这两个有序的数组,组合生成第3个有序的数组,// 时间复杂度O(N*logN)// 缺点:消耗内存;public static void mergeSort(int arr[]) {// 生成临时的缓存数组,用于临时排序int[] workSpace = new int[arr.length];recMergeSort(arr, workSpace, 0, arr.length - 1);}// lowerBound,upperBound 全是数组下标private static void recMergeSort(int arr[], int workSpace[], int lowerBound, int upperBound) {if (lowerBound == upperBound) {return;} else {int mid = (lowerBound + upperBound) / 2;// 递归前半部分recMergeSort(arr, workSpace, lowerBound, mid);// 递归后半部分recMergeSort(arr, workSpace, mid + 1, upperBound);// 进行合并merge(arr, workSpace, lowerBound, mid + 1, upperBound);}}/*** * @param arr*            被排序的数组* @param workSpace*            临时缓存,进行排序的* @param lowPtr*            前半部分,最小下标* @param highPtr*            后半部分,最小下标* @param upperBound*            后半部分,最大下标*/private static void merge(int arr[], int workSpace[], int lowPtr, int highPtr, int upperBound) {int i = 0;int lowerBound = lowPtr;// 前半部分的最小下标,进行缓存int mid = highPtr - 1;int n = upperBound - lowerBound + 1;while (lowPtr <= mid && highPtr <= upperBound) {if (arr[lowPtr] < arr[highPtr]) {workSpace[i++] = arr[lowPtr++];} else {workSpace[i++] = arr[highPtr++];}}// 前半部分或者后半部分,可能还存在未排序的元素,需要写到workSpace里while (lowPtr <= mid) {workSpace[i++] = arr[lowPtr++];}while (highPtr <= upperBound) {workSpace[i++] = arr[highPtr++];}// 将排序好的元素数组workSpace,重新赋值到arr数组里for (i = 0; i < n; i++) {arr[lowerBound + i] = workSpace[i];}}// --------7、桶排序------/*** 使用场景:* * 1、桶排序,可使用于最大最小值相差较大的数据情况,如{2,100,200,198,3,87}* * 2、被排序的数据元素,最好分配均匀,否则可能会导致数据都集中到一个桶中,如{102,108,111,204,3000}* * 基本步骤:* * 1.找出待排序数组中的最大值max、最小值min* * 2.我们使用 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList存储。桶的数量为(max-min)/arr.length+1* * 3.遍历数组 arr,计算每个元素 arr[i] 放的桶* * 4.每个桶各自排序* * 5.遍历桶数组,把排序好的元素放进输出数组* */public static void bucketSort(int arr[]) {int max = Integer.MIN_VALUE; // 先赋值成最小值int min = Integer.MAX_VALUE;// 一次循环,将该数组的最大值,最小值求出来for (int i = 0; i < arr.length; i++) {max = Math.max(max, arr[i]);min = Math.min(min, arr[i]);}// 求桶数int bucketNum = (max - min) / (arr.length) + 1;// 初始化每个桶ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>();for (int i = 0; i < bucketNum; i++) {bucketArr.add(new ArrayList<>());}// 遍历数组,将每个元素放入桶中for (int i = 0; i < arr.length; i++) {int bucketIndex = (arr[i] - min) / (arr.length);bucketArr.get(bucketIndex).add(arr[i]);}// 对每个桶元素,进行排序for (int i = 0; i < bucketArr.size(); i++) {Collections.sort(bucketArr.get(i));}// 将已经排序好的元素,重新赋值到arr数组里int j = 0;// 遍历每个桶,将每个桶的元素,赋值到arr数组里for (int i = 0; i < bucketArr.size(); i++) {ArrayList<Integer> arrayList = bucketArr.get(i);for (Integer key : arrayList) {arr[j++] = key;}}}// --------8、堆排序------// 堆特点:// 1、它是完全的二叉树,除了树的最后一层节点不需要是满的,其他的每一层从左到右都完全是满的// 2、它常常是用一个数组来实现堆的// 3、堆中的每一个节点都满足的条件是,父节点的关键字要大于所有的子节点public static void heapSort(int arr[]) {int size = arr.length;Heap heap = new Heap(size);for (int i = 0; i < size; i++) {Node node = new Node(arr[i]);heap.insertAt(i, node);heap.incrementSize();// 数量递增}// 从最后一个元素的父节点开始向下调整,一直到根// 调整完后,就变成标准的堆了for (int j = size / 2 - 1; j >= 0; j--) {heap.trickleDown(j);}// 通过循环删除最大项,再把删除的数据,数组中的指定的位置,如从后往前方;// 结果就是从小到大排序for (int j = size - 1; j >= 0; j--) {Node biggestNode = heap.remove();// 取出最大的数据项heap.insertAt(j, biggestNode);}System.out.println("----打印排序后的堆----");heap.displayArray();}// 堆排序,// 堆是二叉树,因此,需要创建这个节点,来存储数据// 堆的特点:父节点的值要大于子节点,左右子节点大小无关系,不要求左子节点小于右子节点static class Node {private int iData;public Node(int key) {iData = key;}public int getKey() {return iData;}public void setKey(int id) {iData = id;}}// 创建堆static class Heap {private Node[] heapArray;private int maxSize;private int currentSize;public Heap(int mx) {maxSize = mx;currentSize = 0;heapArray = new Node[maxSize];}public boolean isEmpty() {return currentSize == 0;}// 插入指定的位置public void insertAt(int index, Node node) {heapArray[index] = node;}public void incrementSize() {currentSize++;}public Node remove() {Node root = heapArray[0];heapArray[0] = heapArray[--currentSize];// 把最后一个元素,赋值到根元素上trickleDown(0);// 开始向下调整return root;}// 向下调整public void trickleDown(int index) {int largerChild;Node top = heapArray[index];while (index < currentSize / 2) {int leftChild = 2 * index + 1;int rightChild = leftChild + 1;if (rightChild < currentSize && heapArray[leftChild].getKey() < heapArray[rightChild].getKey()) {largerChild = rightChild;} else {largerChild = leftChild;}if (top.getKey() >= heapArray[largerChild].getKey()) {break;}heapArray[index] = heapArray[largerChild];index = largerChild;}heapArray[index] = top;}// 树状的方式,显示堆public void displayHeap() {int nBlanks = 32;int itemsPerRow = 1;// 层数判断int column = 0;int j = 0;String dots = "-------------------------";System.out.println(dots + dots);while (currentSize > 0) {if (column == 0) {for (int k = 0; k < nBlanks; k++) {System.out.print(' ');}System.out.print(heapArray[j].getKey());if (++j == currentSize) {break;// 所有的数据项,全部显示完毕了}if (++column == itemsPerRow) {nBlanks /= 2;itemsPerRow *= 2;column = 0;System.out.println();} else {for (int k = 0; k < nBlanks * 2 - 2; k++) {System.out.print(' ');}}}}System.out.println("\n" + dots + dots);}// 以数组的方式,来显示堆public void displayArray() {for (int j = 0; j < maxSize; j++) {System.out.print(heapArray[j].getKey() + " ");}System.out.println();}}
}

 
 
 
 
 
测试用例:

package com.xingej.algorithm.sort;import org.junit.Before;
import org.junit.Test;public class SortTest {private int max = 20;private int[] arr = new int[max];// 初始化数组@Beforepublic void initArray() {for (int i = 0; i < max; i++) {arr[i] = (int) (Math.random() * 100 + 1);}System.out.println("------排序前-----");show(arr);}// -----打印输出/*** 打印输出数组* * @param arr*/private void show(int[] arr) {for (int i = 0; i < max; i++) {System.out.print(arr[i] + " ");}System.out.println();}// -----冒泡排序@Testpublic void testByBubbleSort() {SortUtils.bubbleSort(arr);System.out.println("------排序后-----");show(arr);}// -----选择排序@Testpublic void testBySelectionSort() {SortUtils.selectSort(arr);System.out.println("------排序后-----");show(arr);}// -----插入排序@Testpublic void testByInsertSort() {SortUtils.insertSort(arr);System.out.println("------排序后-----");show(arr);}// -----希尔排序@Testpublic void testByShellSort() {SortUtils.shellSort(arr);System.out.println("------排序后-----");show(arr);}// -----快速排序@Testpublic void testByQuickSort() {SortUtils.quickSort(arr);System.out.println("------排序后-----");show(arr);}// -----归并排序@Testpublic void testByMergeSort() {SortUtils.mergeSort(arr);System.out.println("------排序后-----");show(arr);}// -----桶排序@Testpublic void testByBucketSort() {SortUtils.bucketSort(arr);System.out.println("------排序后-----");show(arr);}// -----堆排序,时间复杂度是O(logN)@Testpublic void testByHeapSort() {SortUtils.heapSort(arr);}}

代码已经上传到了git上
https://github.com/xej520/xingej-algorithm

 
 







本文转自故新51CTO博客,原文链接: http://blog.51cto.com/xingej/2056881,如需转载请自行联系原作者

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

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

相关文章

js中null,undefined,false,0,'',[],{}判断方法

目录 1.数据类型 2.JSON字符串 3.数字类型 4.非的布尔值 5.与非比较 一、单独判断 1.null 2.undefined 3.0 4.“” 5.判断undefined、null与NaN: 因为获取到数据的不确定性&#xff0c;常常会导致一些异常情况&#xff0c;使得页面报错&#xff0c;往往要兼容这些异…

【GIS风暴】30米分辨率地表覆盖数据GlobeLand30原始数据集简介及下载地址

数据集预览&#xff1a; GlobeLand30是30米空间分辨率全球地表覆盖数据&#xff0c;目前可供下载使用的有3年的数据&#xff1a;2000-2010-2020&#xff0c;本文主要讲述GlobeLand30的官网下载地址和数据集简介。 数据处理方法、成果数据下载&#xff1a; 【ArcGIS风暴】ArcGI…

Git之解决git stash pop多次产生的文件冲突问题

1、问题 我们用git命令一般拉取线上代码的时候&#xff0c;本地修改了&#xff0c;我们一般先git stash下&#xff0c;接下来git pull, 然后git stash pop下&#xff0c;但是我新增了文件&#xff0c;没有添加到本地git(也就是没有git add file这个新增加的文件)&#xff0c;然…

记一次意外

今天尝试给同一个对象绑定多个事件: document.getElementById("a").οnfοcus function(){ alert("1") }.οnclick function(){ alert("2") } 发现弹出2&#xff0c;改变focus和click的顺序后依旧如此&…

一、基础折线图详解《手把手教你 ECharts 数据可视化详解》

注&#xff1a;本系列教程需要对应 JavaScript 、html、css 基础&#xff0c;否则将会导致阅读时困难&#xff0c;本教程将会从 ECharts 的官方示例出发&#xff0c;详解每一个示例实现&#xff0c;从中学习 ECharts 。 ECharts 官方示例&#xff1a;https://echarts.apache.o…

NLog自定义Target之MQTT

NLog是.Net中最流行的日志记录开源项目(之一)&#xff0c;它灵活、免费、开源官方支持文件、网络(TCP、UDP)、数据库、控制台等输出社区支持Elastic、Seq等日志平台输出实时日志需求在工业物联网等特定场景下需要实时获取日志信息工业物联网领域常用的是mqtt协议那我们就使用NL…

2016-1-27

2019独角兽企业重金招聘Python工程师标准>>> 1.前端的三大技能:1.1.描述网页内容html 1.2.描述网页样式css 1.3.描述网页行为js2.html和jsp区别在于静态和动态..bootsharp是目前比较火爆的css..angular是目前比较火爆的js.3.单点登陆(SSO):登陆一次就可以访问所有相…

【ArcGIS风暴】ArcGIS生成GlobeLand30土地利用数据集中国区域行列号shp格式对照图(附shp下载)

效果预览: 本文主要讲述了在ArcGIS中生成GlobeLand中国区域对照行列号的shp格式矢量数据,用途在于将自己的研究区跟行列号矢量图层直接叠加显示,快速找出自己所需要的图幅号,便于快速下载数据。同时为了方便使用,本文提供了对照图的下载。 文章目录 1. 创建文件数据库2. 创…

Android 节操视频播放器jiecaovideoplayer自定义播放音频使用:屏蔽全屏按钮,增加倒计时,当前时间/总时间

一、屏蔽全屏按钮 找到JCVideoPlayerStandard.java文件中的代码&#xff1a; private void fixAudio() {if (SrcType.equalsIgnoreCase("Audio")) {//如果是音频&#xff0c;始终显示coverImageView//thumbImageView.setVisibility(View.VISIBLE);coverImageView.se…

Android之Dialog提示Unable to add window -- token is not valid; is your activity running?

1、问题 Dialog奔溃提示Unable to add window -- token android.os.BinderProxy@b251dbc is not valid; is your activity running? 2、解决办法 传递context到dialog的时候,要记得先判断状态是不是isFinishing或者isDestroyed状态,这个时候就不要再去show相关的dialog了,…

nagios监控haproxy(借助脚本)

nagios监控haproxy&#xff08;借助脚本&#xff09; 修改后的脚本如下&#xff08;需添加指示灯的状态&#xff09; # vi haproxy.sh #!/bin/bash Portnetstat -ntpl | grep haproxy | awk -F[:" "] {print $5} if [ $Port "1080" ];then echo "OK …

一、Qt初尝试,做一个QT计算器《QT 入门到实战》

学习目标 了解 qt 的基本信息了解 qt 的下载及安装了解创建一个基本 qt 项目的流程了解信号与槽通过示例了解信号与槽的设置与编写了解控件添加的方式了解控件如何使用代码获取其文本了解控件如何使用代码设置其文本使用 connect 自定义信号与槽了解使用样式修饰控件外观了解使…

VS C#语言获取输入名称的汉语拼音简拼码和全拼码完整案例教程

结果预览: 扩展阅读: SQL语言获取拼音码:SQL Server编写函数获取汉字的拼音码(简拼) 文章目录 1. 拼音码类编写2. 界面设计3. 前端调用4. 结果展示1. 拼音码类编写 打开Visual Studio,新建一个Winform项目,再添加一个类文件,命名为PYM。 键入如下代码: using Syst…

iOS duplicate symbol for architecture arm64 解决办法

导致这个问题的原因有多种&#xff1a; 1.重复定义了const常量。 2.多个第三方库同时用到了某个函数库。 暂时列举这几种&#xff0c;以后遇到了其他原因再加。转载于:https://www.cnblogs.com/zhanglinfeng/p/5987077.html

WPF 实现星空效果

本文经原作者授权以原创方式二次分享&#xff0c;欢迎转载、分享。原文作者&#xff1a;普通的地球人原文地址&#xff1a;https://www.cnblogs.com/tsliwei/p/6282183.htmlGithub地址&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers效果前阵子看到ay的蜘蛛网效…

data类型的Url的格式

data类型的Url的格式 一、data类型的简介 所谓"data"类型的Url格式&#xff0c;是在RFC2397中提出的&#xff0c;目的对于一些“小”的数据&#xff0c;可以在网页中直接嵌入&#xff0c;而不是从外部文件载入。例如对于img这个Tag&#xff0c;哪怕 这个图片非常非…

C语言试题八十之统计单词个数

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 终端输入一…

SSIS 执行变量中的脚步输出列顺序与SQL查询列顺序不同

这个问题是朋友遇到的&#xff0c;做一个SSIS的程序将数据导入到txt。然后再用Oracle的工具导入到Oracle。但是在SSIS中执行变量脚步的时候&#xff0c;发现输出的列名称跟查询的列名称完全不同。比如Schema_id在查询的第三列&#xff0c;但是输出的时候到了第6列。 如图&#…

【ArcGIS风暴】ArcGIS自定义坐标系统案例教程---以阿尔伯斯投影(Albers)为例

在实际工作中,经常需要进行矢量数据或栅格数据的投影转换工作,但有时候ArcGIS中恰恰没有我们需要的坐标系,此时,就需要我们自定义坐标系。本文以阿尔伯斯投影(Albers)为例,讲解自定义投影的一般过程及注意事项。 文章目录 1. 确定投影名称2. 选择投影坐标系及修改参数4.…

C语言试题八十一之利用递归函数调用方式,将所输入的5个字符,相反顺序打印

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 利用递归函…