`
newspringwork
  • 浏览: 101348 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

常用排序算法的Java实现

 
阅读更多

最近在看一些代码优化相关的东西,下午看到排序这块,常用的排序方式有冒泡排序、选择排序、快速排序等,这里记录下这三种排序的Java实现。最后附有2个测试这几种排序方式的时间的代码

一、几种常用排序方式介绍

1.冒泡排序

以升序排序为例,将序列看成一排竖着的气泡,最后一个元素与倒数第二个元素进行比较,小的往前移,再将倒数第二个元素与倒数第三个元素比较,依次类推,第一轮比较后,最小的就到了位置1,同样第二轮比较后第二小的到了位置二~

#PopSortDemo.java

 

/**
 * 冒泡排序
 * 
 * @author admin
 *
 */
public class PopSortDemo implements Sorted {
	public void sort(int[] array) {
		for (int i = 0; i < array.length; i++) {
			for (int j = array.length - 1; j > i; j--) {
				if (array[j] < array[j - 1]) {
					SortUtil.exchange(array, j, j-1);
				}
			}
		}
	}
}

总结:

 

1). 需要比较的次数和数组长度有关[1+2+3+4~+(n-1)

2). 需要排序数组长度越长,效率下降明显:n为10时需要比较45次,但n为100时比较次数直线上升到4950次,相差100多倍

 

2.冒泡排序(改进算法)

针对冒泡算法,如果有一轮没有发生交换,说明每个相邻位置不需要交换,即每个位置已经排好了,后面就可以不用继续了

#PopSortImproveDemo.java

 

/**
 * 冒泡排序算法(改进):如果有一轮没有发生交换,说明位置已经排好了,后面就可以不用继续了
 * @author admin
 *
 */
public class PopSortImproveDemo implements Sorted {
	public void sort(int[] array) {
		boolean changed = true;
		for (int i = 0; i < array.length && changed; i++) {
			changed = false;
			for (int j = array.length - 1; j > i; j--) {
				if (array[j] < array[j - 1]) {
					changed = true;
					SortUtil.exchange(array, j, j - 1);
				}
			}
		}
	}
}

总结:

 1). 需要比较的次数和数组长度有关,最多比较[1+2+3+4~+(n-1)] 次,最少比较[n-1]次(初始就是有序的)

  

3.选择排序

先找出最小的数,放到第一个,找出后面数中,第二小的,放到第二个,以此类推。

/**
 * 选择排序
 * 
 * @author admin
 *
 */
public class SelectSortDemo implements Sorted {
	public void sort(int[] array) {
		int pos;
		for (int i = 0; i < array.length; i++) {
			pos=i;
			for (int j = i + 1; j < array.length; j++) {
				if (array[pos] > array[j]) {
					pos=j;
				}
			}
			if(pos!=i) SortUtil.exchange(array, pos, i);
		}
	}
}

 总结:

1). 比较次数和冒泡排序算法相同

2). 之前一直把选择排序记成冒泡排序,实际有区别的(*+﹏+*)~@

 

4.快速排序

选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分

/**
 * 快速排序:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分
 * @author admin
 *
 */
public class QuickSortDemo implements Sorted {

	public void sort(int[] array) {
		sort(array, 0, array.length - 1);
	}

	/**
	 * 递归调用排序:排序基准位置前后子数组
	 * 
	 * @param array
	 * @param start
	 * @param end
	 */
	public void sort(int[] array, int start, int end) {
		if (start < end) {
			int pos = findMiddle(array, start, end);
			sort(array, start, pos - 1);
			sort(array, pos + 1, end);
		}
	}

	/**
	 * 获取基准元素位置
	 */
	public int findMiddle(int[] array, int start, int end) {
		int temp = array[start];
		while (start < end) {
			// 结束位置递减,直到找到第一个比标准位置值小的
			while (start < end && array[end] >= temp) {
				end--;
			}
			// 基准位置交换到end
			array[start] = array[end];
			// 开始位置递增,直到找到第一个比标准位置值大的
			while (start < end && array[start] <= temp) {
				start++;
			}
			// 基准位置交换到start
			array[end] = array[start];
		}
		// 记录基准位置值
		array[start] = temp;
		return start;
	}
}

 总结:

1) 速度比较快,当然前提是基准位置找的好\(`▽′)/

2) 最差的情况,需要找[n-1]次基准位置,找基准位置的过程中总共循环比较[1+2+3+4~+(n-1)]次

 

二、排序方式时间测试

几种排序的时间复杂度

排序法

最差时间分析 平均时间复杂度 稳定度 空间复杂度
冒泡排序 O(n2) O(n2) 稳定 O(1)
快速排序 O(n2) O(n*log2n) 不稳定 O(log2n)~O(n)
选择排序 O(n2) O(n2) 稳定 O(1)
二叉树排序 O(n2) O(n*log2n) 不一顶 O(n)

插入排序

O(n2) O(n2) 稳定 O(1)
堆排序 O(n*log2n) O(n*log2n) 不稳定 O(1)
希尔排序 O O 不稳定 O(1)

这里直接测试每种排序方式消耗的时间,采用两种方式:一种是每次排序都重新设置数组每个元素的值,第二种是不同的排序方式排序同一个数组

2. 不同排序方式,不同的数组

>测试代码:

 

/**
 * 排序测试,每种排序方式对不同随机数组排序多次,取平均时间
 * 
 * @author admin
 *
 */
public class RandomSortTest {
	private static Logger log = LogManager.getLogger();

	public static void main(String[] args) {
		// 87, 76, 65, 51, 43, 31, 23, 17, 6, 3
		// 6, 17, 23, 31, 43, 51, 65, 76, 87, 3
		// 3, 6, 17, 23, 31, 43, 51, 65, 76, 87
		// 数组长度 & 数组元素随机生成的最大值 & 每种排序方式测试次数
		int len = 100000, numMax = 10000,sortTypeCount = 10;
		// 待排序数组
		int[] arr = new int[len];
		// 排序类
		Sorted sorter = null;
		// 循环调用多个排序方法,每次调用getSorter()会返回不同的排序方法
		while ((sorter = getSorter()) != null) {
			long time = 0;
			for (int i = 0; i < sortTypeCount; i++) {
				// 给每个数组元素设置随机值
				SortUtil.insertRandomNumber(arr, numMax);
				// 排序,并返回排序时间
				time += SortUtil.testSortTime(arr, sorter);
			}
			log.info("排序方法[{}],平均[{}/{}]耗时{}ms", sorter.getClass().getSimpleName(), time, sortTypeCount, time / sortTypeCount);
		}
	}

	/**
	 * 排序方式:1、快速排序;2、选择排序;3、冒泡排序;4、冒泡排序(改进)
	 */
	private static int sortType = 1;

	private static Sorted getSorter() {
		Sorted sorter = null;
		// 1、快速排序;2、选择排序;3、冒泡排序;4、冒泡排序(改进)
		switch (sortType++) {
		case 1:
			sorter = new QuickSortDemo();
			break;
		case 2:
			sorter = new SelectSortDemo();
			break;
		case 3:
			sorter = new PopSortDemo();
			break;
		case 4:
			sorter = new PopSortImproveDemo();
			break;
		default:
			break;
		}
		return sorter;
	}
}

 

>测试结果(len=10W):

 

2017-03-22 22:30:11.214 [main] INFO  - 排序方法[QuickSortDemo],平均[92/10]耗时9ms
cn.tinyf.demo.sort.RandomSortTest
2017-03-22 22:30:38.408 [main] INFO  - 排序方法[SelectSortDemo],平均[27182/10]耗时2718ms
cn.tinyf.demo.sort.RandomSortTest
2017-03-22 22:33:04.408 [main] INFO  - 排序方法[PopSortDemo],平均[145987/10]耗时14598ms
cn.tinyf.demo.sort.RandomSortTest
2017-03-22 22:35:26.352 [main] INFO  - 排序方法[PopSortImproveDemo],平均[141931/10]耗时14193ms
cn.tinyf.demo.sort.RandomSortTest
>测试结果(len=30):
2017-03-22 23:10:35.963 [main] INFO  - 排序方法[QuickSortDemo],耗时33843纳秒
cn.tinyf.demo.sort.SortTest
2017-03-22 23:10:35.964 [main] INFO  - 排序方法[SelectSortDemo],耗时85253纳秒
cn.tinyf.demo.sort.SortTest
2017-03-22 23:10:35.964 [main] INFO  - 排序方法[PopSortDemo],耗时224286纳秒
cn.tinyf.demo.sort.SortTest
2017-03-22 23:10:35.965 [main] INFO  - 排序方法[PopSortImproveDemo],耗时166954纳秒
cn.tinyf.demo.sort.SortTest
 
 3. 不同排序方式,相同的数组

 

>测试代码:

 

/**
 * 排序测试,针对相同的数组排序
 * 
 * @author admin
 *
 */
public class SortTest {

	private static Logger log = LogManager.getLogger();

	public static void main(String[] args) {
		// 数组长度,数组元素随机生成的最大值
		int len = 100000, numMax = 10000;
		// 源数组
		int[] src = new int[len];
		// 待排序数组
		int[] arr = new int[len];
		// 给每个数组元素设置随机值
		SortUtil.insertRandomNumber(src, numMax);
		// 排序类
		Sorted sorter = null;
		// 循环调用多个排序方法,每次调用getSorter()会返回不同的排序方法
		while ((sorter = getSorter()) != null) {
			long time = 0;
			// 设置待排序数组
			System.arraycopy(src, 0, arr, 0, len);
			// 排序,并返回排序时间
			time += SortUtil.testSortTime(arr, sorter);
			log.info("排序方法[{}],耗时{}ms", sorter.getClass().getSimpleName(), time);
		}
	}

	/**
	 * 排序方式:1、快速排序;2、选择排序;3、冒泡排序;4、冒泡排序(改进)
	 */
	private static int sortType = 1;

	private static Sorted getSorter() {
		Sorted sorter = null;
		// 1、快速排序;2、选择排序;3、冒泡排序;4、冒泡排序(改进)
		switch (sortType++) {
		case 1:
			sorter = new QuickSortDemo();
			break;
		case 2:
			sorter = new SelectSortDemo();
			break;
		case 3:
			sorter = new PopSortDemo();
			break;
		case 4:
			sorter = new PopSortImproveDemo();
			break;
		default:
			break;
		}
		return sorter;
	}
}
 >测试结果(len=10W): 
2017-03-22 22:28:38.228 [main] INFO  - 排序方法[QuickSortDemo],耗时13ms
cn.tinyf.demo.sort.SortTest
2017-03-22 22:28:40.854 [main] INFO  - 排序方法[SelectSortDemo],耗时2625ms
cn.tinyf.demo.sort.SortTest
2017-03-22 22:28:55.803 [main] INFO  - 排序方法[PopSortDemo],耗时14949ms
cn.tinyf.demo.sort.SortTest
2017-03-22 22:29:10.574 [main] INFO  - 排序方法[PopSortImproveDemo],耗时14770ms
cn.tinyf.demo.sort.SortTest
 3.小结
  • 数组元素比较多时快速排序效率比较高
 三、附件

#Sorted接口

public interface Sorted {
	void sort(int[] array);
}

 #SortUtil工具类

/**
 * 排序工具类
 * 
 * @author admin
 *
 */
public class SortUtil {

	/**
	 * 交换数组两个位置元素值
	 * 
	 * @param array
	 * @param pos1
	 * @param pos2
	 */
	public static void exchange(int[] array, int pos1, int pos2) {
		int temp = array[pos1];
		array[pos1] = array[pos2];
		array[pos2] = temp;
	}

	/**
	 * 随机数生成器
	 */
	private static Random random = new Random();

	/**
	 * 深层随机数
	 * 
	 * @param max
	 *            最大值
	 * @return
	 */
	public static int randomInteger(int max) {
		return random.nextInt(max);
	}

	/**
	 * 使用随机数设置数组每个位置的元素值
	 * 
	 * @param arr
	 * @param randomMax
	 */
	public static void insertRandomNumber(int[] arr, int randomMax) {
		for (int i = 0; i < arr.length; i++) {
			arr[i] = SortUtil.randomInteger(randomMax);
		}
	}

	/**
	 * 测试排序时间
	 * 
	 * @param arr
	 * @param sorter
	 * @return
	 */
	public static long testSortTime(int[] arr, Sorted sorter) {
		long start = System.currentTimeMillis();
		sorter.sort(arr);
		return System.currentTimeMillis() - start;
	}

	/**
	 * 数组反序
	 * 
	 * @param array
	 */
	public static void reverse(int[] array) {
		for (int i = array.length / 2 - 1; i >= 0; i--) {
			exchange(array, i, array.length - 1 - i);
		}
	}
}

 

分享到:
评论

相关推荐

    常用排序算法Java实现

    这里我们主要关注Java实现的七大经典排序算法:冒泡排序、插入排序、选择排序、希尔排序、快速排序、归并排序以及堆排序。 1. 冒泡排序(Bubble Sort): 冒泡排序是最简单的排序方法之一,它通过重复遍历待排序的...

    常用排序算法java演示

    本文将深入探讨标题"常用排序算法java演示"中涉及的知识点,包括排序算法的原理、Java实现方式以及其在实际应用中的图形演示。 首先,让我们逐一了解几种常见的排序算法: 1. **冒泡排序(Bubble Sort)**:这是一...

    常用排序算法的java实现(冒泡、插入、选择、希尔、归并、快排)

    本篇文章将详细讲解标题中提到的六种常见排序算法的Java实现。 1. **冒泡排序**:冒泡排序是最基础的排序算法之一,它通过不断交换相邻的逆序元素来逐渐将较大的元素“浮”到数组的前端。在Java中,冒泡排序的基本...

    常用各种排序算法Java的实现_差不多了__.rar

    本资源"常用各种排序算法Java的实现_差不多了__.rar"显然是一个包含了各种经典排序算法Java实现的压缩文件,对于学习和理解这些算法的开发者来说极具价值。 首先,我们来概述一下常见的排序算法: 1. 冒泡排序:是...

    常用排序算法Java

    以上就是Java中实现的一些常用排序算法,它们各有优缺点,适用于不同的场景。理解并熟练掌握这些排序算法,有助于优化代码性能,提高编程能力。在实际开发中,应根据具体需求选择合适的排序算法,以达到最佳的效率和...

    常用的排序算法(java实现),附带一个PPT动画演示、详解了其中三种

    这里我们主要关注Java实现的排序算法,并结合一个PPT的动画演示来探讨其中的插入排序、直接插入排序和希尔排序。 首先,让我们深入理解插入排序。插入排序是一种简单的排序算法,其基本思想是将未排序的元素逐个...

    Java实现常用排序算法

    虽然树形选择排序和堆排序在这次实现中未涵盖,但理解这四种排序算法的基本原理和Java实现方式对于提升编程技能至关重要。 首先,让我们来看看插入排序。插入排序是一种简单直观的排序算法,它的工作原理类似于人们...

    常用排序算法分析与实现(Java版)

    ### 常用排序算法分析与实现(Java版) #### 插入排序 **1. 直接插入排序** 直接插入排序是一种简单的排序方法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并...

    常用排序算法JAVA版

    这个名为"常用排序算法JAVA版"的压缩包文件很可能包含了Java实现的各种经典排序算法,如冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等。 1. **冒泡排序**:是最简单的排序算法之一,通过不断交换...

    JAVA写的6种内部排序算法简单实现

    以上就是六种常用的内部排序算法在Java语言中的实现。理解这些排序算法的原理和性能特点,有助于在实际编程中选择合适的排序方法,提高程序效率。对于面试或者笔试,熟练掌握这些算法将大大提高你的竞争力。在实践中...

    常用排序算法总结(含Java代码)

    冒泡排序和快速排序是两种基础但广泛使用的数据排序算法。冒泡排序由于其简单直观的特性,易于理解和实现,而快速排序则以其较高的效率在数据量较大时展现出优势。 首先,让我们来看冒泡排序算法。冒泡排序通过重复...

    常用排序算法源码下载(Java实现)

    常用排序算法的Java实现源码,包括冒泡排序,快速排序,直接插入排序,希尔排序,直接选择排序,堆排序,归并排序,基数排序,计数排序。

    八大排序算法总结(含Java实现源代码)

    在计算机科学中,排序算法是数据处理的重要组成部分,它们用于将一组无序的数据按照特定顺序进行排列。这里我们将深入探讨八大排序算法,并结合Java语言来理解它们的实现原理。 1. 冒泡排序(Bubble Sort) 冒泡...

    Java常用排序算法源码

    在编程领域,排序算法是计算机科学中的核心概念,特别是在Java这样的高级编程语言中。排序算法是用来组织和优化数据结构的关键工具,使得数据按照特定规则(如升序或降序)排列。以下是对Java中几种常见排序算法的...

    常用排序算法实现(java)

    本资源提供了五种经典的排序算法的Java实现,包括选择排序(Selection Sort)、插入排序(Insertion Sort)、希尔排序(Shell Sort)、归并排序(Merge Sort)以及快速排序(Quick Sort)。 1. **选择排序**:选择排序是一种...

    Java常用排序算法程序员必须掌握的8大排序算法Java开

    学习资料如"Java常用排序算法程序员必须掌握的8大排序算法Java开发Java经验技巧共16页.pdf"可以提供详细的讲解和示例,帮助你更好地理解和实践这些算法。同时,这些排序算法不仅限于Java,也广泛应用于Python、C语言...

    Java常用8大排序算法

    ### Java常用八大排序算法详解 #### 一、直接插入排序 **基本思想:** 直接插入排序的基本思路是在要排序的一组数中,假设前面 (n-1) [n&gt;=2] 个数已经排好顺序,现在要把第 n 个数插入到前面的有序数列中,使得这 ...

    常用排序算法小结(附Java实现)

    这篇博客“常用排序算法小结(附Java实现)”提供了一种深入理解并掌握常见排序算法的途径,尤其对于Java开发者来说非常实用。文章可能涵盖了如冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等多种经典...

    Java常用排序算法&程序员必须掌握的8大排序算法+二分法查找

    本资料包聚焦于"Java常用排序算法"和"程序员必须掌握的8大排序算法",并深入探讨了"二分法查找"这一高效搜索技术。 首先,我们来看八大排序算法。这些算法包括: 1. **冒泡排序**:最简单的排序方法,通过不断交换...

Global site tag (gtag.js) - Google Analytics