冒泡、选择、插入、归并、希尔、快速排序效率比较代码


/*
 * 文 件 名:  Sort.java
 * 修改时间:  2012-12-27
 */
package sort;

import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

/**
 * 各种排序算法
 * 
 * @version [版本号, 2012-12-27]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class Sort
{
    
    /**
     * 主函数
     * 
     * @param args
     * @see [类、类#方法、类#成员]
     */
    public static void main(String[] args)
    {
        Scanner scanner = new Scanner(System.in);
        Random random = new Random();
        System.out.println("请输入排序的整数个数:");
        int n = scanner.nextInt();
        int[] array = new int[n];
        for (int i = 0; i < n; i++)
        {
            array[i] = random.nextInt(1000);
        }
        // 初始化完毕
        
        //        System.out.println(shellSort(array).toString());
        System.out.println(shell(array).toString());
        //        System.out.println(insert(array).toString());
        System.out.println(merge(array).toString());
        System.out.println(quickSort(array).toString());
        System.out.println(arraySort(array).toString());
        //        System.out.println(shell(array).toString());
        //        System.out.println(bubble(array).toString());
        //        System.out.println(choose(array).toString());
        //        System.out.println(insert(array).toString());
        //        int[] result = quickSort(array).result;
        //        for (int i = 0; i < result.length; i++)
        //        {
        //            System.out.print(result[i] + ",");
        //        }
    }
    
    /** 
     *  
     * @param iArray 
     */
    public static Result shellSort(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("网上希尔排序");
        int i, j, h = 1, temp;
        while (h <= n / 3)
            h = h * 3 + 1;
        while (h > 0)
        {
            for (i = h; i < n; i += h)
            {
                temp = arrayTemp[i];
                j = i;
                while (j >= h && arrayTemp[j - h] >= temp)
                {
                    arrayTemp[j] = arrayTemp[j - h];
                    j -= h;
                }
                arrayTemp[j] = temp;
            }
            h = (h - 1) / 3;
        }
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 冒泡排序
     * 
     * @param array
     * @see [类、类#方法、类#成员]
     */
    public static Result bubble(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("冒泡排序");
        result.count = n;
        for (int i = n - 1; i > 0; i--)
        {
            for (int j = 0; j < i; j++)
            {
                if (arrayTemp[j] > arrayTemp[j + 1])
                {
                    int temp = arrayTemp[j];
                    arrayTemp[j] = arrayTemp[j + 1];
                    arrayTemp[j + 1] = temp;
                    result.move++;
                }
                result.compare++;
            }
        }
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 选择排序算法
     * 
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result choose(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("选择排序");
        result.count = n;
        for (int i = 0; i < n - 1; i++)
        {
            int pos = i;
            for (int j = i + 1; j < n; j++)
            {
                if (arrayTemp[i] > arrayTemp[j])
                {
                    pos = j;
                }
                result.compare++;
            }
            if (pos != i)
            {
                int temp;
                temp = array[i];
                array[i] = array[pos];
                array[pos] = temp;
                result.move++;
            }
        }
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 插入排序算法
     * 
     * @param array
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result insert(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("插入排序");
        result.count = n;
        int temp, j;
        for (int i = 1; i < n; i++)
        {
            temp = arrayTemp[i];
            for (j = i - 1; j >= 0 && arrayTemp[j] > temp; j--)
            {
                arrayTemp[j + 1] = arrayTemp[j];
            }
            arrayTemp[j + 1] = temp;
        }
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 归并排序算法,使用递归实现
     * 
     * @param array
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result merge(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        int[] arrayExtra = new int[n];// 额外的数组
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("归并排序");
        result.count = n;
        result.space += n;
        merge(arrayTemp, 0, arrayTemp.length - 1, result, arrayExtra);
        result.result = arrayTemp;
        result.time = System.currentTimeMillis() - result.time;
        return result;
    }
    
    /**
     * 归并排序节约内存版,这种方法在递归过程中申请额外内存,可能造成内存 不足,但是速度和下面那种差不多
     */
    // private static void merge(int[] array, int start, int stop, Result
    // result) {
    // int n = stop - start + 1;
    // if (n > 1) {
    //
    // merge(array, start, start + n / 2 - 1, result);
    // merge(array, start + n / 2, stop, result);
    // int[] temp = new int[n];
    // result.space += n;
    // int l = start;
    // int r = start + n / 2;
    // for (int i = 0; i < n; i++) {
    // if (l == start + n / 2) {
    // temp[i] = array[r++];
    // } else if (r == stop + 1) {
    // temp[i] = array[l++];
    // } else if (array[l] > array[r]) {
    // temp[i] = array[r++];
    // } else if (array[l] < array[r]) {
    // temp[i] = array[l++];
    // }
    // result.compare++;
    // result.move++;
    // }
    // System.arraycopy(temp, 0, array, start, n);
    // result.move++;
    // }
    // }
    
    /**
     * 归并排序更节约内存版,该方法一次性申请一块和原数组同样大的内存,不用在递归过程中申请,可以节约内存
     */
    private static void merge(int[] array, int start, int stop, Result result, int[] arrayExtra)
    {
        int n = stop - start + 1;
        if (n > 1)
        {
            
            merge(array, start, start + n / 2 - 1, result, arrayExtra);
            merge(array, start + n / 2, stop, result, arrayExtra);
            int l = start;
            int r = start + n / 2;
            for (int i = start; i <= stop; i++)
            {
                if (l == start + n / 2)
                {
                    arrayExtra[i] = array[r++];
                }
                else if (r == stop + 1)
                {
                    arrayExtra[i] = array[l++];
                }
                else if (array[l] >= array[r])
                {
                    arrayExtra[i] = array[r++];
                }
                else if (array[l] <= array[r])
                {
                    arrayExtra[i] = array[l++];
                }
                result.compare++;
                result.move++;
            }
            System.arraycopy(arrayExtra, start, array, start, n);
            result.move++;
        }
    }
    
    /**
     * 原地归并算法。。。
     * 不需要额外数组,类似插入算法,但不是单个元素的移动,是整体移动,不知道效率如何 需要少量的额外内存
     * 在Java中这种方式的效率太低了,还不如一次性申请大内存好,如果有C++的内存反转的话 空间复杂度为O(1)
     */
    private static void merge(int[] array, int start, int stop, Result result)
    {
        int n = stop - start + 1;
        if (n > 1)
        {
            
            merge(array, start, start + n / 2 - 1, result);
            merge(array, start + n / 2, stop, result);
            int l = start;
            int r = start + n / 2;
            int index = r;
            while (l < r && r <= stop)
            {
                // 先找到左边的插入点l,右边的内存块需要查到该元素之前
                if (array[l] > array[r])
                {
                    // 再找到右边的区间r到index
                    while (index <= stop)
                    {
                        if (index == stop || array[index + 1] > array[l])
                        {
                            //这里是最重要的反转内存操作,由于Java语言的限制,只能使用最小临时内存区实现
                            //首先比较一下左边待移动的内存块和右边待移动的内存块的大小
                            int lSize = r - l;
                            int rSize = index - r + 1;
                            if (lSize > rSize)
                            {
                                int[] temp = new int[rSize];
                                result.space += rSize;
                                //将小内存块存入临时内存中
                                System.arraycopy(array, r, temp, 0, rSize);
                                //然后移动大的内存块
                                System.arraycopy(array, l, array, l + rSize, lSize);
                                //最后将临时内存中得数据还原
                                System.arraycopy(temp, 0, array, l, rSize);
                                result.move += 3;
                            }
                            else
                            {
                                int[] temp = new int[lSize];
                                result.space += lSize;
                                //将小内存块存入临时内存中
                                System.arraycopy(array, l, temp, 0, lSize);
                                //然后移动大的内存块
                                System.arraycopy(array, r, array, l, rSize);
                                //最后将临时内存中得数据还原
                                System.arraycopy(temp, 0, array, index - lSize + 1, lSize);
                                result.move += 3;
                            }
                            l += rSize;
                            r = ++index;
                        }
                        else
                        {
                            index++;
                        }
                    }
                }
                else
                {
                    l++;
                }
            }
        }
    }
    
    /**
     * 希尔排序,插入排序的改进版本
     * @param array
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result shell(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("希尔排序");
        result.count = n;
        //希尔排序算法,其实就是插入排序算法的改进版本,其中有个增量,插入排序其实就是增量为1的希尔排序
        //希尔排序增量从大到小最后减为1进行插入排序即可
        //先求出第一个增量
        int increment = 1;
        while (increment < n)
        {
            if (3 * increment + 1 > n)
            {
                break;
            }
            else
            {
                increment = 3 * increment + 1;
            }
        }
        while (increment >= 1)
        {
            //每条线都是从h开始,下一个元素为h+increment,直到最后一个元素索引小于n
            for (int i = increment; i < n; i++)
            {
                int temp = arrayTemp[i];
                int j;
                for (j = i - increment; j >= 0 && arrayTemp[j] > temp; j -= increment)
                {
                    arrayTemp[j + increment] = arrayTemp[j];
                }
                arrayTemp[j + increment] = temp;
            }
            increment = (increment - 1) / 3;
        }
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 快速排序算法
     * @param array
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result quickSort(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("快速排序");
        result.count = n;
        //这里是具体的算法
        quickSort(arrayTemp, 0, n - 1);
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 快速排序的递归算法,总是选取right索引处的值作为枢纽
     * @param array
     * @param left
     * @param right
     * @see [类、类#方法、类#成员]
     */
    private static void quickSort(int[] array, int left, int right)
    {
        if (left < right)
        {
            int partition = partition(array, left, right);
            quickSort(array, left, partition - 1);
            quickSort(array, partition + 1, right);
        }
    }
    
    /**
     * 划分算法,关键字为数组第一个元素
     * @param array
     * @param left
     * @param right
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static int partition(int[] array, int left, int right)
    {
        int i = left, j = right;
        int pivot = array[i];
        while (i < j)
        {
            while (i < j && array[j] >= pivot)
            {
                j--;
            }
            if (i < j)
            {
                array[i++] = array[j];
            }
            while (i < j && array[i] <= pivot)
            {
                i++;
            }
            if (i < j)
            {
                array[j--] = array[i];
            }
        }
        array[i] = pivot;
        return i;
    }
    
    /**
     * JAVA自带的排序算法
     * @param array
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Result arraySort(int[] array)
    {
        if (null == array)
        {
            throw new NullPointerException();
        }
        int n = array.length;
        int[] arrayTemp = new int[n];
        System.arraycopy(array, 0, arrayTemp, 0, n);
        Result result = new Result("java自带排序");
        result.count = n;
        Arrays.sort(arrayTemp);
        result.time = System.currentTimeMillis() - result.time;
        result.result = arrayTemp;
        return result;
    }
    
    /**
     * 求得归并排序n个元素所需的额外内存
     * 
     * @param n
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static int getMergeMemory(int n)
    {
        if (n <= 1)
        {
            return 0;
        }
        else
        {
            return n + getMergeMemory(n / 2) + getMergeMemory(n - n / 2);
        }
    }
    
    static class Result
    {
        String name;
        long time;
        long compare;
        long move;
        long count;
        int[] result;
        long space;// 额外内存开销
        
        public Result(String name)
        {
            this.name = name;
            time = System.currentTimeMillis();
            compare = 0;
            move = 0;
            space = 0;
        }
        
        /** {@inheritDoc} */
        
        @Override
        public String toString()
        {
            return name + "[额外内存=" + space + ",元素个数=" + count + ",比较次数=" + compare + ", 移动次数=" + move + ", 消耗时间="
                + time + "]";
        }
        
    }
}


不用说,归并排序的效率肯定最高,但是额外的内存开销也很大,本人机器最多能排1480万-1490万条数据,和机器内存以及虚拟机内存相关,时间大约在5秒-6秒,冒泡,选择和插入的效率就不用看了,数量级刚到10万时间已经突破30秒,再大的数量级肯定以指数级增长了。。

下面总结下:
1、冒泡、选择、插入排序算法都不需要额外的内存开销,但是效率很低,比较和移动的次数太多,导致排10W以上的数据时间很长,都在半分钟左右,排100W的数据估计可以等几个小时了。。
2、普通归并排序的效率极高,1500W的数据量排序,时间在5秒左右,但是需要额外的一倍内存。

3、使用Java不能实现原地归并排序,因为控制不了内存地址,无法做内存的反转,C++的原地归并比普通归并慢大约30倍,如果内存要求高,而时间要求不是很高的情况下,使用原地归并也是不错的选择。

4、希尔排序不需要额外内存,而且也没有递归,个人感觉是比较好的排序方式,大数据量排序性能也不错。

5、快速排序虽然没有额外内存,但是用到了递归,500W以上的数据量会造成堆栈溢出,而且在数据倒序情况下性能退化的厉害,不是很稳定,需要改进基准值的设置。

6、JAVA自带的排序算法是所有排序算法中性能最好的,他是改进的快速排序算法,而且当数据元素个数小于7时,使用了插入排序消除了一部分递归操作。2200W数据量才1800毫秒。。这是别的排序算法无法达到的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值