排序算法时间复杂度的分析java语言描述

1.    题目分析
本次实验目的是掌握选择排序、冒泡排序、归并排序、快速排序、插入排序的算法原理。以及以及比较这四种算法的时间复杂度以及空间复杂度。
2.    选择排序
算法分析:


代码实现:

/**
     * select_sort:选择排序  
     * @author chenxi  
     * @param arr:待排序的数组
     */
    public static void selectSort(int arr[]) {
        for(int x=0;x<arr.length-1;x++)  //最后一个数不用在自己和自己进行比较了,n-1轮
        {
            for(int y=x+1;y<arr.length;y++)
            {
                if(arr[x]>arr[y])
                {
                    int temp=arr[x];
                    arr[x]=arr[y];
                    arr[y]=temp;                
                }
            }
        }
    }

3.    冒泡排序
算法分析:相邻的两个元素进行比较,如果符合条件就换位,这样第一轮,最大的数会在最后面,长度在依次递减
 
代码实现:

/**
     * bubbleSort:冒泡排序算法
     * @author chenxi  
     * @param arr:需要排序的数组
     */
    public static void bubbleSort(int arr[]) {
         int len = arr.length;
            for (int i = 0; i < len - 1; i++) {
                for (int j = 0; j < len - 1 - i; j++) {
                    if (arr[j] > arr[j+1]) {        // 相邻元素两两对比
                        int temp = arr[j+1];        // 元素交换
                        arr[j+1] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
        }

4.    归并排序
算法分析:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾


 代码实现:

//归并排序
    public static void mergeSort(int arr[]) {
        sort(arr,0,arr.length-1);
    }
    private static void sort(int[] arr,int start,int end){
        if(start<end){
            int mid = (start+end)/2;
            sort(arr,start,mid);//左边归并排序,使得左子序列有序
            sort(arr,mid+1,end);//右边归并排序,使得右子序列有序
            merge(arr,start,mid,mid+1,end);//将两个有序子数组合并操作
        }
    }
    private static void merge(int[] arr,int start1,int end1,int start2,int end2){
        // 建立辅助数组
        int len=end2-start1+1;
        int[] temp=new int[len];
        int i = start1;//左序列指针
        int j = start2;//右序列指针
        int t = 0;//临时数组指针
        while (i<=end1 && j<=end2){   
            // 将小的放入辅助数组
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        //若左序列此时还有有剩余的,将左边剩余元素填充进temp中
        while(i<=end1){
            temp[t++] = arr[i++];
        }
        //若右序列此时还有有剩余的,将右序列剩余元素填充进temp中
        while(j<=end2){
            temp[t++] = arr[j++];
        }
        t=0;
        //将temp中的元素全部拷贝到原数组中
        while(start1 <= end2){
            arr[start1++] = temp[t++];
        }
    }

5.    快速排序
算法分析:
 
 
 
代码实现:

//快速排序
    public static void quickSort(int arr[]) {
        sort1(arr, 0, arr.length-1);
    }
    /**
     * 将数组的某一段元素进行划分,小的在左边,大的在右边
     */
    public static int divide(int[] a, int start, int end){
        //每次都以最右边的元素作为基准值
        int base = a[end];
        //start一旦等于end,就说明左右两个指针合并到了同一位置,可以结束此轮循环。
        while(start < end){
            while(start < end && a[start] <= base)
                //从左边开始遍历,如果比基准值小,就继续向右走
                start++;
            //上面的while循环结束时,就说明当前的a[start]的值比基准值大,应与基准值进行交换
            if(start < end){
                //交换
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
                //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值右边),因此右边也要同时向前移动一位
                end--;
            }   
            while(start < end && a[end] >= base)
                //从右边开始遍历,如果比基准值大,就继续向左走
                end--;
            //上面的while循环结束时,就说明当前的a[end]的值比基准值小,应与基准值进行交换
            if(start < end){
                //交换
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
                //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值左边),因此左边也要同时向后移动一位
                start++;
            }   

        }
        //这里返回start或者end皆可,此时的start和end都为基准值所在的位置
        return end;
    }

    /**
     * 排序
     */
    public static void sort1(int[] a, int start, int end){
        if(start > end){
            //如果只有一个元素,就不用再排下去了
            return;
        } 
        else{
            //如果不止一个元素,继续划分两边递归排序下去
            int partition = divide(a, start, end);
            sort1(a, start, partition-1);
            sort1(a, partition+1, end);
        }   
    }

6.    插入排序
算法分析:将当前元素和左边的元素比较,若当前元素小,就交换两者,也就相当于插入
 
代码实现:

/**
     * insertionSort:插入排序 
     * @author chenxi  
     * @param arr
     */
    public static void insertionSort(int[] arr) {
        int len = arr.length;
        for (int i = 1; i < len; i++) {
            // j表示当前元素的位置,将其和左边的元素比较,若当前元素小,就交换,也就相当于插入
            // 这样当前元素位于j-1处,j--来更新当前元素,j一直左移不能越界,因此应该大于0
            for(int j=i; j>0 && arr[j]<arr[j-1];j--){
                int temp = arr[j];// 元素交换
                arr[j] = arr[j-1];
                arr[j-1] = temp;
            }
        }
    }

7.    测试代码以及运行结果
测试代码:

/**
     * 
     * random:用于产生随机样本的函数  
     * @author chenxi  
     * @param n:样本规模
     * @return
     */
    public static ArrayList<int []> random(int n) {
        ArrayList<int []> arrs=new ArrayList<>();
        Random random=new Random();
        for(int i=0;i<20;i++) {
            int arr[]=new int[n];
            for(int j=0;j<arr.length;j++) {
                arr[j]=random.nextInt(100);
            }
            arrs.add(arr);
        }
        return arrs;
    }
    /**
     * paixu:封装的排序方法发   
     * @author chenxi  
     * @param n:样本规模
     * @param key:采用的排序方法
     */
    public static void paixu(int n,int key) {
        ArrayList<int []> arrs=random(n);
        if(key==1) {
            //排序开始时获得一次当前系统的毫秒值
            long start=System.currentTimeMillis();
            for(int i=0;i<arrs.size();i++) {
                int arr[]=arrs.get(i);
                SortedUtil.selectSort(arr);
            }
            //排序结束时获得一次当前系统的毫秒值
            long end=System.currentTimeMillis();
            //计算排序所花的时间
            System.out.println("选择排序所花时间:"+(end-start)+"ms");
        }
        if(key==2) {
            long start=System.currentTimeMillis();
            for(int i=0;i<arrs.size();i++) {
                int arr[]=arrs.get(i);
                SortedUtil.bubbleSort(arr);
            }
            long end=System.currentTimeMillis();
            System.out.println("冒泡排序所花时间:"+(end-start)+"ms");
        }
        if(key==3) {
            long start=System.currentTimeMillis();
            for(int i=0;i<arrs.size();i++) {
                int arr[]=arrs.get(i);
                SortedUtil.mergeSort(arr);
            }
            long end=System.currentTimeMillis();
            System.out.println("归并排序所花时间:"+(end-start)+"ms");
        }
        if(key==4) {
            long start=System.currentTimeMillis();
            for(int i=0;i<arrs.size();i++) {
                int arr[]=arrs.get(i);
                SortedUtil.quickSort(arr);
            }
            long end=System.currentTimeMillis();
            System.out.println("快速排序所花时间:"+(end-start)+"ms");
        }
        if(key==5) {
            long start=System.currentTimeMillis();
            for(int i=0;i<arrs.size();i++) {
                int arr[]=arrs.get(i);
                SortedUtil.insertionSort(arr);
            }
            long end=System.currentTimeMillis();
            System.out.println("插入排序所花时间:"+(end-start)+"ms");
        }
    }
package www.domian;
public class Test {
    public static void main(String[] args) {
        int j=10;
        while(j<=100000) {
            System.out.println("数据规模为"+j+"数据样本为20:");
            for(int i=1;i<6;i++) {
                SortedUtil.paixu(j, i);
            }
            j*=10;
        }
    }
}

运行结果:
测试结果一:(不够准确)
     
          
测试结果二:(比结果一稍微准确一些)


8.    算法复杂度分析及经验归纳

排序算法时间复杂度比较

排序方法

数据规模 

选择排序

冒泡排序

归并排序

快速排序

插入排序

10

0

0

0

0

1

100

4

5

1

1

2

1000

16

43

3

2

38

10000

858

6588

75

46

2283

100000

110127

785963

762

3339

287059

上表是对测试结果二进行了整理,由上图表格可以看出随着数据规模的增大,排序算所用的时间越长。数据规模的大小与排序的时间也有一定的关系,如图:

在较大的数据规模下,归并排序和快速排序比其他排序明显要快的多。所以建议在大数据规模下尽量使用归并排序或者快速排序,对于小数据规模建议使用其他数据结构较为简单的排序。
    注:以上测试数的结果与电脑配置配置有关,此次实验分别用了两台不同配置的电脑进行测试,数据分析时取了一组较为准确的运行结果,但是会存在误差。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值