本ID技术干货公众号“java工会”,欢迎关注指正。

一、冒泡排序

1.算法介绍

设排序表长为n,从后向前或者从前向后两两比较相邻元素的值,如果两者的相对次序不对(A[i-1] > A[i]),则交换它们,其结果是将最小的元素交换到待排序序列的第一个位置,我们称它为一趟冒泡。下一趟冒泡时,前一趟确定的最小元素不再参与比较,待排序序列减少一个元素,每趟冒泡的结果把序列中最小的元素放到了序列的”最前面”。

2.算法实现

冒泡排序封装函数的代码如下

public void bubbleSort(int[] arr) {
int temp;//定义一个临时变量
   for(int i=0;i<arr.length-1;i++){//冒泡趟数
       for(int j=0;j<arr.length-i-1;j++){
//如果顺序不对,则交换两个元素
           if(arr[j+1]<arr[j]){
temp = arr[j];
               arr[j] = arr[j+1];
               arr[j+1] = temp;
           }
}
}
}

测试代码如下

public static void main(String[] args) {
Test t = new Test();
   int arr[] = new int[]{13,26,22,22,35,18};
   t.bubbleSort(arr);
   System.out.println(Arrays.toString(arr));
}

运行结果如下

[13, 18, 22, 22, 26, 35]

3.算法分析

冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1),它是一种稳定的排序算法。当然了,这也是非常基础的一种算法,一般找工作有些公司喜欢出笔试题。

下面我们来看看java中的Arrays.sort(int []a)方法是怎么实现的。


二、快速排序

java中Arrays.sort使用了两种排序方法,快速排序和优化的合并排序。

快速排序主要是对哪些基本类型数据(int,short,long等)排序, 而合并排序用于对对象类型进行排序。

使用不同类型的排序算法主要是由于快速排序是不稳定的,而合并排序是稳定的。这里的稳定是指比较相等的数据在排序之后仍然按照排序之前的前后顺序排列。对于基本数据类型,稳定性没有意义,而对于对象类型,稳定性是比较重要的,因为对象相等的判断可能只是判断关键属性,最好保持相等对象的非关键属性的顺序与排序前一直;另外一个原因是由于合并排序相对而言比较次数比快速排序少,移动(对象引用的移动)次数比快速排序多,而对于对象来说,比较一般比移动耗时。

1.实现原理

java1.7之后的版本,开始用双轴快排取代了以前的排序算法,现在只实现了8种基本数据类型性的双轴快排,对象的排序在1.7中还在用老式的,不过都标了过时,估计以后版本中就会被新的双轴快排取代了。

他的DualPivotQuicksort()方法,里边一共写了三种算法(不算改进版的插入排序话),对于大数组而且部分高度有序的用归并排序,其余的用双轴快排进行分割, 分割到足够小的时候用插入排序(主要是改进版的pair insertion sort)。

双轴快排的基本原理是取两个pivot,所有比pivot1小的放到最左边,比pivot2大的放到最右边,然后递归下去,就可以把两端的元素完成排序,之后处理中间部分,中间部分如果过大就继续递归用这种方式继续分割,如果不大,就用单轴分割对两部分递归调用下去。

2.实现代码

代码截取自jdk1.7中的Arrays类

/**
* Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
public static void sort(int[] a, int left, int right) {
// Use Quicksort on small arrays
   if (right - left < QUICKSORT_THRESHOLD) {
sort(a, left, right, true);
       return;
   } /*
    * Index run[i] is the start of i-th run
    * (ascending or descending sequence).
    */
   int[] run = new int[MAX_RUN_COUNT + 1];
   int count = 0; run[0] = left;    // Check if the array is nearly sorted
   for (int k = left; k < right; run[count] = k) {
if (a[k] < a[k + 1]) { // ascending
           while (++k <= right && a[k - 1] <= a[k]);
       } else if (a[k] > a[k + 1]) { // descending
           while (++k <= right && a[k - 1] >= a[k]);
           for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
           }
} else { // equal
           for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
if (--m == 0) {
sort(a, left, right, true);
                   return;
               }
}
} /*
        * The array is not highly structured,
        * use Quicksort instead of merge sort.
        */
       if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
           return;
       }
} // Check special cases
   if (run[count] == right++) { // The last run contains one element
       run[++count] = right;
   } else if (count == 1) { // The array is already sorted
       return;
   } /*
    * Create temporary array, which is used for merging.
    * Implementation note: variable "right" is increased by 1.
    */
   int[] b; byte odd = 0;
   for (int n = 1; (n <<= 1) < count; odd ^= 1);    if (odd == 0) {
b = a; a = new int[b.length];
       for (int i = left - 1; ++i < right; a[i] = b[i]);
   } else {
b = new int[a.length];
   } // Merging
   for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
           for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p] <= a[q]) {
b[i] = a[p++];
               } else {
b[i] = a[q++];
               }
}
run[++last] = hi;
       }
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
               b[i] = a[i]
);
           run[++last] = right;
       }
int[] t = a; a = b; b = t;
   }
}

3.源码分析

源码中的快速排序,主要做了以下几个方面的优化:

  1)当待排序的数组中的元素个数较少时,源码中的阀值为7,采用的是插入排序。尽管插入排序的时间复杂度为0(n^2),但是当数组元素较少时,插入排序优于快速排序,因为这时快速排序的递归操作影响性能。

  2)较好的选择了划分元(基准元素)。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).

源码中选择划分元的方法:

    当数组大小为 size=7 时 ,取数组中间元素作为划分元。int n=m>>1;(此方法值得借鉴)

    当数组大小 7<size<=40时,取首、中、末三个元素中间大小的元素作为划分元。

    当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。

  3)根据划分元 v ,形成不变式 v* (<v)* (>v)* v*

  普通的快速排序算法,经过一次划分后,将划分元排到素组较中间的位置,左边的元素小于划分元,右边的元素大于划分元,而没有将与划分元相等的元素放在其附近,这一点,在Arrays.sort()中得到了较大的优化。

最后,如果你有仍何开发上面的问题都可以和我交流沟通。欢迎关注微信公众号“java工会”。

java冒泡排序和快速排序的更多相关文章

  1. Java 冒泡排序与快速排序的实现

    冒泡排序   基本特点 (1)基于交换思想的排序算法  (2)从一端开始,逐个比较相邻的两个元素,发现倒序即交换.      (3)一次遍历,一定能将其中最大(小)的元素交换到其最终位置上 排序过程模 ...

  2. java冒泡排序和快速排序代码

    冒泡排序: package nicetime.com; //基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,// 让较大的数往下沉,较小的往上 ...

  3. Java冒泡排序与快速排序笔记

    public class Sort { public static void sort() { Scanner input = new Scanner(System.in); int sort[] = ...

  4. 使用JAVA直观感受快速排序与冒泡排序的性能差异

    初学算法,肯定会编写排序算法 其中两个最为有名的就是冒泡排序和快速排序 理论上冒泡排序的时间复杂度为O(N^2),快速排序的时间复杂度为O(NlogN) 下面本门使用JAVA,分别编写三段排序程序 对 ...

  5. 程序员必知的8大排序(三)-------冒泡排序,快速排序(java实现)

    程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...

  6. 牛客网Java刷题知识点之插入排序(直接插入排序和希尔排序)、选择排序(直接选择排序和堆排序)、冒泡排序、快速排序、归并排序和基数排序(博主推荐)

    不多说,直接上干货! 插入排序包括直接插入排序.希尔排序. 1.直接插入排序: 如何写成代码: 首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用 ...

  7. 2017.12.9 Java中的排序---冒泡排序、快速排序、选择排序

    //冒泡排序 public class demo{ public static void main(String[] args) { int[] sum={2,9,10,1,5,88}; System ...

  8. (十七)java冒泡排序和compareto

    java中的排序有:冒泡排序.快速排序.选择排序.插入排序和希尔排序,还有基数排序.鸡尾酒排序.桶排序.鸽巢排序.归并排序等.     冒泡排序法:利用双重for循环,重复走访要排序的数列,两两比较大 ...

  9. [C#][算法] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

    用菜鸟的思维学习算法 -- 马桶排序.冒泡排序和快速排序 [博主]反骨仔 [来源]http://www.cnblogs.com/liqingwen/p/4994261.html  目录 马桶排序(令人 ...

随机推荐

  1. hdu5556 Land of Farms

    我对于题目的一种理解 改造农场 1.建新农场 在空的点选 2.重建旧农场 选一个点属于这个农场的地方都要选 最后的农场都不能相连 所以枚举旧农场的个数并进行二分图匹配 #include<bits ...

  2. 用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传

    第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三 ...

  3. gprecoverseg导致的元数据库问题致使数据库无法启动以及修复

    一.现象描述 在一次执行gprecoverseg后发现数据库无法正常连接,现象如下: 执行gprecoverseg日志如下: gprecoverseg:mdw-:gpadmin-[INFO]:-Sta ...

  4. 第一节 JDK是什么?JRE是什么?JDK和JRE的区别?以及jdk安装和测试。

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Java语言作为静态面向对象编程语言的代表 ...

  5. Bzoj4566:[HAOI2016]找相同字符

    题面 Bzoj Sol 两个串拼在一起后求出后缀数组 然后显然的\(n^2\)暴力,就是直接枚举求\(LCP\) 又由于扫的时候是对\(height\)取\(min\) 那么可以用单调栈维护每一段的贡 ...

  6. 我的emacs考场配置

    豪华配置(复制的神犇的,已膜改) (global-set-key [f9] 'compile-file) (global-set-key [f10] 'gud-gdb) (global-set-key ...

  7. UVa11426 最大公约数之和(正版)

    题面 求\(\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}gcd(i, j)\) n<=4000000,数据组数T<=100 答案保证在64位带符号整数范围内(long ...

  8. 在不同环境下MD5加密相同字符串,密文不一样的问题

    这是昨天做一个接口对接时遇到的一个问题.下面是md5加密的算法 public static String md555(String plainText) throws UnsupportedEncod ...

  9. Django admin 组件 原理分析与扩展使用 之 sites.py (一)

    一 . 前言 Django 提供了admin 组件 为项目提供基本的管理后台功能(对数据表的增删改查). 本篇文章通过 admin源码 简单分析admin 内部原理 ,扩展使用方式,为以后进行定制和自 ...

  10. 【python学习笔记】10.充电时刻

    [python学习笔记]10.充电时刻 任何python都可以作为模块倒入 *.pyc:平台无关的经过编译的的python文件, 模块在第一次导入到程序中时被执行,包括定义类,函数,变量,执行语句 可 ...