Java排序算法之冒泡排序

来源:互联网 发布:淘宝店铺类目怎么选 编辑:程序博客网 时间:2024/06/04 00:55

Java排序算法之冒泡排序

交换类排序主要是通过两两比较待排元素的关键字,若发现与排序要求相逆,则“交换”
之。冒泡排序是交换类排序的一种。本篇文章讲解以下内容:

  • 基本思想
  • 源码
  • 源码解析
  • 算法原理
  • 效率分析

冒泡排序的基本思想

基本处理思想是通过对相邻两个数据的比较及其交换来达到排序的目的。
首先,将 n 个元素中的第一个和第二个进行比较,如果两个元素的位置为逆序,则交换两个元素的位置;进而比较第二个和第三个元素关键字,如此类推,直到比较第 n-1 个元素和第 n 个元素为止;
上述过程描述了起泡排序的第一趟排序过程,在第一趟排序过程中,我们将关键字最大的元素通过交换操作放到了具有 n 个元素的序列的最一个位置上。
然后进行第二趟排序,在第二趟排序过程中对元素序列的前 n-1 个元素进行相同操作,其结果是将关键字次大的元素通过交换放到第 n-1 个位置上。一般来说,第 i 趟排序是对元素序列的前 n-i+1 个元素进行排序,使得前 n-i+1 个元素中关键字最大的元素被放置到第 n-i+1 个位置上。排序共进行 n-1 趟,即可使得元素序列按关键字有序。

源码

package com.algorithm.sorting;/** * 冒泡排序 * @author Administrator * */public class BubbleSort {    public static void BubbleSort(int[] arr) {        System.out.print("要排序的数组:");        for (int a = 0; a < arr.length; a++) {            System.out.print(arr[a] + "\t");        }        System.out.println("");        int temp;// 临时变量        for (int i = 0; i < arr.length - 1; i++) { // 表示排序次数,一共arr.length-1次。            for (int j = arr.length - 1; j > i; j--) {                if (arr[j] < arr[j - 1]) {//"<",代表正序即从小到大;">"代表逆序即从大到小                    temp = arr[j];                    arr[j] = arr[j - 1];                    arr[j - 1] = temp;                }            }            System.out.print("第" + (i + 1) + "次排序结果:");            for (int a = 0; a < arr.length; a++) {                System.out.print(arr[a] + "\t");            }            System.out.println("");        }        System.out.print("最终排序结果:");        for (int a = 0; a < arr.length; a++) {            System.out.print(arr[a] + "\t");        }    }    public static void main(String[] args) {    int array[]={100, 20, 30,-1,99,53};     BubbleSort(array);    }}

源码解析

首先看正序的整个过程:

要排序的数组:100  20  30  -1  99  53  第1次排序结果:-1  100 20  30  53  99  第2次排序结果:-1  20  100 30  53  99  第3次排序结果:-1  20  30  100 53  99  第4次排序结果:-1  20  30  53  100 99  第5次排序结果:-1  20  30  53  99  100 最终排序结果:-1   20  30  53  99  100 

再看逆序的整个过程:

要排序的数组:100  20  30  -1  99  53  第1次排序结果:100 99  20  30  -1  53  第2次排序结果:100 99  53  20  30  -1  第3次排序结果:100 99  53  30  20  -1  第4次排序结果:100 99  53  30  20  -1  第5次排序结果:100 99  53  30  20  -1  最终排序结果:100  99  53  30  20  -1  

算法执行过程(正序):

  • 比较相邻的两个数据,如果第二个数小,就交换位置。
  • 从后向前两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置,这样第一个最小数的位置就排好了。
  • 继续重复上述过程,依次将第2.3…n-1个最小数排好位置。

算法原理

  • 首先将第一个数据与第二个数据进行比较,如果是逆序(即arr[j]>arr[j+1)则交换之,然后比较第二个数据和第三个数据,依此类推,直到第n-1个数据和第n个数据进行过比较为止。上述过程称为冒泡排序的第一趟处理,第一趟处理的结果使得最大的数据被安置在最后一个元素的位置上。然后进行第二趟处理,即对前n-1个数据进行上述的处理,第二趟处理的结果是使次大的数据被安置在倒数第二个数据位置上。
  • 一般地,冒泡排序的第i趟是从arr[0]到arr[n-i]依次比较相邻两个元素的关键字,并在逆序时交换相邻的数据,其结果是将这n-i+1个数据中最大的交换到n-i的位置上。整个排序过程需要进行n-1趟处理,第n-1趟处理使倒数第二的数据安置在第二个数据位置上,这时整个排序过程就已完成。

效率分析

空间效率:仅使用一个辅存单元(temp)。
时间效率:假设待排序的元素个数为 n,则总共要进行 n-1 趟排序,对 j 个元素的子序
列进行一趟起泡排序需要进行 j-1 次关键字比较。由此,起泡排序的总比较次数为

i=nn(j1)=(n)(n1)2

因此,起泡排序的时间复杂度为O(n2)

补充数据结构的知识:

在计算机资源中,最重要的就是时间与空间。评价一个算法性能的好坏,实际上就是评价算法的资源占用问题。

时间复杂性

一旦去掉表示算法运行时间中的低阶项和首项常数,就称我们是在度量算法的渐进时间复杂度(渐进时间复杂度(asymptotic complexity) ),简称 时间复杂度.
为了进一步说明算法的时间复杂度,定义 Ο、Ω、Θ符号。

Ο符号

比如时间复杂度为 O(n2)
这个符号可以解释为:只要当排序元素的个数大于某个阈值N时,那么对于某个常量c > 0,运行时间最多为cn2 。也就是说Ο符号提供了一个运行时间的上界。

Ω符号

Ο符号给出了算法时间复杂度的上界,而Ω符号在运行时间的常数因子范围内给出了时间复杂度的下界。
Ω符号可以解释为:如果输入大于等于某个阈值 N,算法的运行时间下限是 f(n)的 c 倍,其中 c 是一个正常数,则称算法的时间复杂度是Ω(f(n))的。Ω的形式定义与Ο符号对称。

Θ符号

Ο符号给出了算法时间复杂度的上界,Ω符号给出了时间复杂度的下界,而θ给出了算法时间复杂度的精确阶。
Θ符号可以解释为:如果输入大于等于某个阈值N,算法的运行时间在下限c1 f(n)和上限
c2 f(n)之间(0<c1c2 ),则称算法的时间复杂度是Θ(f(n))阶的。
我们评价算法的运行时间是通过分析在一定规模下算法
执行基本操作的次数来反映的,并且由于我们只对大规模问题的运行时间感兴趣,所以是使
用算法的渐进时间复杂度 T(n)来度量算法的时间性能的。Ο、Ω、Θ符号分别定义了时间复
杂度的上界、下界以及精确阶。

空间复杂性

算法使用的空间定义为:为了求解问题的实例而执行的操作所需要的存储空间的数目,但是它不包括用来存储输入实例的空间。

算法优化

  1. 针对问题:
    数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。比如源码中逆序的排序过程。
  2. 方案:
    设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
    这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
    优化后的源码
    /*     * 优化后写法     */    public static void BubbleSort1(int [] arr){        System.out.print("要排序的数组:");        for (int a = 0; a < arr.length; a++) {            System.out.print(arr[a] + "\t");        }        System.out.println("");           int temp;//临时变量           boolean flag;//是否交换的标志           for(int i=0; i<arr.length-1; i++){   //表示排序次数,一共arr.length-1次。               flag = false;               for(int j=arr.length-1; j>i; j--){                   if(arr[j] > arr[j-1]){                       temp = arr[j];                       arr[j] = arr[j-1];                       arr[j-1] = temp;                       flag = true;                   }               }               if(!flag) break;               System.out.print("第" + (i + 1) + "次排序结果:");                for (int a = 0; a < arr.length; a++) {                    System.out.print(arr[a] + "\t");                }                System.out.println("");           }           System.out.print("最终排序结果:");            for (int a = 0; a < arr.length; a++) {                System.out.print(arr[a] + "\t");            }          }

优化后的排序过程:

要排序的数组:100  20  30  -1  99  53  第1次排序结果:100 99  20  30  -1  53  第2次排序结果:100 99  53  20  30  -1  第3次排序结果:100 99  53  30  20  -1  最终排序结果:100  99  53  30  20  -1  

总结:冒泡排序是比较重要的。一般面试都会问的。有必要掌握的。写博客是为了帮助开发者学习使用技术,同时巩固自己所学技术。如果此篇博客有助于您的学习,那是我的荣幸!如果此篇博客有任何瑕疵,请多多指教!在此感谢您的学习和指教!

原创粉丝点击