java 交换排序之(冒泡排序、快速排序)

2016年上班第一天,闲来无事,先写篇博文来结束今天。我们大家都知道java的排序算法很多,接下来我就先看看java最常用的几种排序算法的思想源码附上。(本文所有排序只针对值排序,关于对象排序问题待续.....)

1.插入排序(直接插入排序、二分法插入排序、表插入排序、shell排序)

2.选择排序(直接选择排序、堆排序)

3.交换排序(冒泡排序、快速排序)

4.分配排序(基数排序)

5.归并排序(内排序、外排序)


一、java冒泡排序实现(大家最喜欢也是最简单的排序算法,但是性能不是那么ok 当排序数组很大是性能就很低了)

冒泡排序算法实现思想:

    //算法分析:

    一次比较相邻的两个数,将大数放在前面、小数放在后面(小数放在前面、大数放在后面)。首先比较第一个和第二     个,满足条件互换位置。然后第二个和第三个比较。直到倒数第二个和最后一个比较。得到一个最大或者最小的数放    在最后完成第一轮比较。一次进行第二轮比较、第三轮直到结束。

   //冒泡排序算法:(实现源码)

    public static void maopaoSort(int[] arr){
            int temp;
            for(int i = 0;i < arr.length; i++){
                for(int j = 0; j < arr.length-1-i; j++ ){
                    if(arr[j] < arr[j+1]){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
    }

二、java交换排序之快速排序

    //算法分析:

    快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

(1) 分治法的基本思想
     分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

(2) 实例分解

    快速排序是对冒泡排序的一种该进(两种排序都是属于交换排序),通过一趟排序将原有的排序数组分成独立的两个部分。其中一部分的数据比另外一部分的数据都要小。然后再按照此方法对刚划分的两部分进行同样的分割。以此达到整个数组变成有序的序列。

    假设需要排序的数组是A[0]......A[N-1],首先任意选取一个数据(通常选择A[0])作为关键数据然后把所有比它小的数都放在前面,所有比它大的数都放在它后面。这整个过程称为一趟快速排序(因此我们可以把一趟快速排序写成一个独立的方法。方便重复调用)

    (1)设置两个变量i,j,排序开始的时候i=0,j=N-1.

    (2)以第一个数据A[0]作为关键数据,赋值给key,即key=A[i]。

    (3)从j(j = j-1 )开始向前搜索,找到第一个小于key的值,让该值与key进行交换。

    (4)从i(i = i+1)开始向后搜索,找到第一个大于key的值,让该值与key交换。

    (5)重复(3)、(4)不,直到i=j。

    列如:需要排序的数组A=[49,38,65,97,76,13,27]初始关键数据为A[0]=49,经过第一趟快速排序后所有比49小的放在了49 的前边,比49大的都放在了49的后边。因此经过第一趟排序后的A=[27, 38, 13, 49, 76, 97, 65]记录关机数据在经过第一轮快速排序后的位置i=3,因此A数组被分为A1=[27, 38, 13]、A0=[49]、A2=[76, 97, 65]三个部分。

package cn.bsxy;
/**
 * 快速排序实现源码
 * @author smartluobo
 *
 */

public class QuickSort {
    
    /**
     *
     * @a a需要进行排序的数组
     * @i i排序的其实位置关键数据的在数组中的位置,第一次调用i = 0
     * @j j需要进行排序终止位置。第一次调用是j=a.length-1
     * @return 返回经过一趟快速排序后关键数据的位置
     */

    public int partition(int[] a, int i, int j){//根据关键数据分割需要排序的数组并返回关键数据在分割后的位置
        int key = a[i];//临时变量用于存储关键数据
        while(i < j){
            while(i < j && a[j] >= key)//找出第一个比key小的数执行j--并将其赋值给a[i]
                j--;//执行j = j-1操作
                a[i] = a[j];//将a[j]的值赋值给a[i]
            

            while(i < j && a[i] <= key)//找出第一个比key大的数执行i++并将其赋值给a[j]
                i++;//执行i = i+1
                a[j] = a[i];//把该值赋值给a[j]
        }
        a[i]=key;//完成一趟快速排序后将选择的关键数据放在分割点上
        return i;//返回关键数据在经过一趟快速排序后的位置
    }

    
    public void sort(int[] a, int i, int j){
        if(i < j){
            int n = partition(a ,i ,j);//记录返回的关键数据在经过一趟快速排序后的位置
            sort(a,i,n-1);//对左边部分进行递归调用。依次完成分割
            sort(a,n+1,j);//对右边部分进行递归调用。依次完成分割
        }
    }
    
    public static void main(String[] args) {
        int[] a = {49,38,65,97,76,13,27};
        new QuickSort().sort(a, 0, a.length-1);
        for (int i : a) {
            System.out.print(i+"\t");
        }
    }
}

三、性能测试

    package cn.bsxy;

import java.util.Random;

/**
 *
 * @author smartluobo
 * 测试java交换排序的冒泡排序和快速排序两种方法的性能
 */

public class SortTest {
    /**
     * 完成一趟快速排序
     * @param a 需要排序的数组
     * @param i 起始位置,第一次为0
     * @param j 结束位置,一般为数组的长度-1 a.length-1
     * @return
     */

    public int partition(int[] a,int i,int j){
        int key = a[i];
        while(i < j){
            while(i < j && a[j] <= key)
                j--;
            a[i] = a[j];
            while(i < j && a[i] >= key)
                i++;
            a[j] = a[i];
        }
        a[i] = key;
        return i;
    }
    
    /**
     * 快速排序方法实现。递归调用该方法完成数组的排序
     * @param a
     * @param i
     * @param j
     */

    public void sort(int[] a, int i, int j){
        if(i < j){
            int n = partition(a,i,j);
            sort(a,i,n-1);
            sort(a,n+1,j);
        }
    }
    
    /**
     * 冒泡排序方法实现
     * @param a 需要排序的数组
     */

    public static void maopaoSort(int[] a){
        int temp;
        for(int i = 0; i< a.length;i++){
            for(int j = 0;j<a.length-i-1;j++){
                if(a[j] < a[j+1]){
                    temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
        }
    }
    
    /**
     * 创建一个长度很长的无序数组
     * @return
     */

    public static int[] createRandom(){
        int[] a = new int[18000];
        Random random = new Random();
        int b;
        for(int i = 0;i < a.length;i++){
            b = random.nextInt(100000);
            a[i] = b;
        }
        return a;
    }
    
    public static void main(String[] args) {
        int[] a = createRandom();        
        int[] b = a;//将a数组赋值给b是为了保证两个排序方法对完全一样的两个数组进行排序
        long maopaoStart = System.currentTimeMillis();
        maopaoSort(b);//使用冒泡排序法对生成的数组进行排序
        long maopaoEnd = System.currentTimeMillis();
        System.out.println("maopaoStart:"+maopaoStart+", maopaoEnd"+maopaoEnd+"快速排序法用                                时:"+(maopaoEnd-maopaoStart));
        long start = System.currentTimeMillis();
        new SortTest().sort(a, 0, a.length-1);//使用快速排序方法对生成的数组排序
        long end = System.currentTimeMillis();
        System.out.println("start:"+start+", end"+end+"快速排序法用时:"+(end-start));
//        int k = 0;
//        for (int i : a) {
//            k++;
//            System.out.print(i+"\t");
//            if(k%100 == 0){
//                System.out.println();
//            }
//        }

//   经打印测试冒泡排序和快速排序都能正常排序需要排序的数组

    }
}

运行以上代码打印台输出为:

maopaoStart:1456461874561, maopaoEnd1456461874976  快速排序法用时:415
start:1456461874977, end:1456461875059   快速排序法用时:82

经过多次测试后发现快速排序的速度比冒泡排序快 4~5倍。缺点是快速排序使用递归调用,当数组的长度足够大时,会出现内存溢出的情况.....具体解决方案还望各位大神给出宝贵意见.





   



 

你可能感兴趣的:(java,冒泡排序,sort)