归并排序和快速排序效率比较(Java,数据量10w)

实验要求

1、归并排序和快速排序效率比较
2、数据量:3个序列:随机序列,顺序序列,逆序序列
(每个序列的数据量均为10w)

实验分析(涉及的问题)

1、文件(.txt文件)中数据的读取和写入(数据以空格间隔,每行10个数据)
2、归并排序和快速排序的算法设计
3、排序所用时间的计算

实验环境

语言:java
环境:IDEA

实验代码

在这里插入图片描述
MergeSort.java

//归并排序,(含读取和写文件,计算执行时间)
public class MergeSort {
    public int[] A;
    public MergeSort(int[] array) {
        this.A = array.clone();
    }
    public int[] SortResult()
    {
        sort(0, A.length - 1);
        return A;
    }
    public void sort(int low, int high) {

        if (low < high) {
            int mid = (low + high) / 2;
            //划分子序列
            sort(low, mid);
            sort(mid + 1, high);
            //合并
            merge(low, mid, high);
        }
    }

    public void merge(int low, int mid, int high) {
        // 声明新的数组,临时储存归并结果
        int[] B = new int[high - low + 1];
        int i = 0;
        //左边序列和右边序列起始下标
        int j = low;
        int k = mid + 1;
        //当有一个序列全部合并之后就结束
        while (j <= mid && k <= high) {
            if (A[j] <= A[k]) {
                B[i] = A[j];
                j++;
            } else {
                B[i] = A[k];
                k++;
            }
            i++;
        }
        // 如果左边序列还有剩余就全部放进临时数组
        while (j <= mid) {
            B[i] = A[j];
            i++;j++;
        }
        //如果有变序列还有剩余就全部放进临时数组
        while (k <= high) {
            B[i] = A[k];
            i++;k++;
        }
        //将临时数组拷贝到原数组相应的位置
        for (int t = 0; t < i; t++) {
            A[low + t] = B[t];
        }
    }
}

QuickSort.java

//快速排序
public class QuickSort {
    public int[] arr;

    public QuickSort(int[] array) {
        this.arr = array.clone();
    }

    public int[] SortResult() {
        sort(arr, 0, arr.length - 1);
        return arr;
    }

    public void sort(int[] arr, int left, int right) {
        int tmp = arr[(left+right)/2], i = left, j = right;
        while(i <= j) {
            while(arr[j]>tmp) j--;
            while(arr[i]<tmp) i++;
            if(i<=j) {
                int t = arr[i]; arr[i] = arr[j]; arr[j] = t;
                i++;
                j--;
            }
        }
        if(i<right) sort(arr,i, right);
        if(j>left) sort(arr,left, j);
    }
}

TimeCounter.java

import java.io.*;

//归并排序和快速排序效率比较
public class TimeCounter {
    static int size = 100001;//十万条数据
    static int[] array = new int[size];
    static int[] array_out=new int[size];

    public static void main(String[] args) {

        //时间变量(开始时间,结束时间)
        long QuickStart,QuickEnd,MergeStart,MergeEnd;

        /*******************************随机序列,读取一次***************************************/
        readFile("Random_sequence.txt");
        //快排,记录时间,并将排序结果写入txt
        QuickStart = System.currentTimeMillis();
        QuickSort quickSort1=new QuickSort(array);
        array_out=quickSort1.SortResult();
        QuickEnd = System.currentTimeMillis();
        writeFile("Random_quick_out.txt");
        //归排,记录时间,并将排序结果写入txt
        MergeStart = System.currentTimeMillis();
        MergeSort mergeSort1=new MergeSort(array);
        array_out=mergeSort1.SortResult();
        MergeEnd = System.currentTimeMillis();
        writeFile("Random_merge_out.txt");
        //进行时间的比较
        System.out.println("随机序列排序所用时间:");
        System.out.println("quick sort: " + (QuickEnd - QuickStart) + "毫秒");
        System.out.println("merge sort: " + (MergeEnd - MergeStart) + "毫秒");

        /*******************************顺序序列,读取一次***************************************/
        readFile("Sequential_sequence.txt");
        //快排,记录时间,并将排序结果写入txt
        QuickStart = System.currentTimeMillis();
        QuickSort quickSort2=new QuickSort(array);
        array_out=quickSort2.SortResult();
        QuickEnd = System.currentTimeMillis();
        writeFile("Sequential_quick_out.txt");
        //归排,记录时间,并将排序结果写入txt
        MergeStart = System.currentTimeMillis();
        MergeSort mergeSort2=new MergeSort(array);
        array_out=mergeSort2.SortResult();
        MergeEnd = System.currentTimeMillis();
        writeFile("Sequential_merge_out.txt");
        //进行时间的比较
        System.out.println("顺序序列排序所用时间:");
        System.out.println("quick sort: " + (QuickEnd - QuickStart) + "毫秒");
        System.out.println("merge sort: " + (MergeEnd - MergeStart) + "毫秒");

        /*******************************逆序序列,读取一次***************************************/
        readFile("Reverse_sequence.txt");
        //快排,记录时间,并将排序结果写入txt
        QuickStart = System.currentTimeMillis();
        QuickSort quickSort3=new QuickSort(array);
        array_out=quickSort3.SortResult();
        QuickEnd = System.currentTimeMillis();
        writeFile("Reverse_quick_out.txt");
        //归排,记录时间,并将排序结果写入txt
        MergeStart = System.currentTimeMillis();
        MergeSort mergeSort3=new MergeSort(array);
        array_out=mergeSort3.SortResult();
        MergeEnd = System.currentTimeMillis();
        writeFile("Reverse_merge_out.txt");
        //进行时间的比较
        System.out.println("逆序序列排序所用时间:");
        System.out.println("quick sort: " + (QuickEnd - QuickStart) + "毫秒");
        System.out.println("merge sort: " + (MergeEnd - MergeStart) + "毫秒");
    }

    //读取txt文件,存储到数组中
    public static void readFile(String input_pathname) {
        // 绝对路径或相对路径都可以
        // String pathname = "D:\\data\\Sequential_sequence.txt";
        // String pathname = "Sequential_sequence.txt";
        String pathname = input_pathname;
        try (FileReader reader = new FileReader(pathname);
             BufferedReader br = new BufferedReader(reader)) {
            int j = 0;
            String line;
            // 一次读入一行数据
            while ((line = br.readLine()) != null) {
                String[] s = line.split(" ");
                for (int i = 0; i < 10; i++) {
                    array[j] = Integer.parseInt(s[i]);
                    j++;
                }
            }
            reader.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //将排序好的序列写入文件
    public static void writeFile(String output_pathname) {
        File writeName = new File(output_pathname);
        try (FileWriter writer = new FileWriter(writeName);
             BufferedWriter out = new BufferedWriter(writer))
        {
            // 创建新文件,有同名的文件的话直接覆盖
            writeName.createNewFile();
            //将数组中的数据写入到文件中。每行各数据之间空格间隔,每行10个数
            for (int i = 0; i < array_out.length - 1; i++) {
                out.write(array_out[i] + " ");
                if ((i + 1) % 10 == 0) {   //一行够10个数就换行
                    out.write("\n");
                }
            }
            out.flush();// 把缓存区内容压入文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实验结果

在这里插入图片描述

难点

快速排序按照网上的写法,可能会遇到栈溢出的情况,解决办法:换代码

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
选择排序算法准则: 每种排序算法都各有优缺点。因此,在实用时需根据不同情况适当选用,甚至可以将多种方法结合起来使用。 选择排序算法的依据 影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的。相反,有时平均时间复杂度高的算法可能更适合某些特殊情况。同时,选择算法时还得考虑它的可读性,以利于软件的维护。一般而言,需要考虑的因素有以下四点: 1.待排序的记录数目n的大小; 2.记录本身数据量的大小,也就是记录中除关键字外的其他信息量的大小; 3.关键字的结构及其分布情况; 4.对排序稳定性的要求。 设待排序元素的个数为n. 1)当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短; 堆排序 : 如果内存空间允许且要求稳定性的, 归并排序:它有一定数量的数据移动,所以我们可能过与插入排序组合,先获得一定长度的序列,然后再合并,在效率上将有所提高。 2) 当n较大,内存空间允许,且要求稳定性 =》归并排序 3)当n较小,可采用直接插入或直接选择排序。 直接插入排序:当元素分布有序,直接插入排序将大大减少比较次数和移动记录的次数。 直接选择排序 :元素分布有序,如果不要求稳定性,选择直接选择排序 5)一般不使用或不直接使用传统的冒泡排序。 6)基数排序 它是一种稳定的排序算法,但有一定的局限性:   1、关键字可分解。   2、记录的关键字位数较少,如果密集更好   3、如果是数字时,最好是无符号的,否则将增加相应的映射复杂度,可先将其正负分开排序。
数据结构与算法 排序算法 内排序 八大基础排序 选择排序 简单选择排序 思想 每次选择最大的数插入到末尾中 做法 外层for循环控制次数 内层for循环找出最大的值的角标 找出最大角标后,进行交换 优化思路 同时获取最大值和最小值,然后分别插入数组的首部和尾部 堆排序 思想 使用大顶堆的思想来排序,每次建堆后交换 做法 总体:建堆-替换 建堆 只要左子树或右子树大于当前根节点,则替换 替换后会导致下面的子树发生了变化,因此同样需要进行比较,直至各个节点实现父>子这么一个条件(递归) 交换排序 冒泡排序 思想 每次俩俩交换,将最大值交换到末尾 做法 外层for控制循环次数 内层for控制比较次数 每次循环之后,比较次数都会减少一次 优化思路 如果一趟排序后没有发生位置变化,那么此时就是有序了 快速排序 思想 每次将比支点小的放在支点左边,比支点大的放在支点右边 做法 外循环while只要i和j不碰撞查找 内层两个while循环分别查找出比支点小的和比支点大的角标 如果i<=j满足条件,就交换 一趟排序后,支点的左边都比支点小,支点右边都比支点大 只要满足L<j,i0的条件查找出要插入的何时位置 退出内层while循环后就找到了合适的位置插入 优化思路 二分查找插入,找合适位置的时候使用二分查找算法 希尔排序 思想 用增量来将数组进行分隔,直到增量为1。底层干的还是插入排序干的活 做法 最外层for外循环控制增量的数量,每次/2 第二层for循环控制每次增量那组开始进行插入排序,直至完毕 第三层while循环找到要插入到哪个位置 归并排序 思想 将两个已排好序的数组合并成一个有序的数组 做法 递归拆分出两个有序的数组,从mid的位置开始拆分,递归出口:只有一个值的时候就不用拆分了 合并两个有序的数据 分别往两个数组填充已有序的数据 比较两个数组的值谁小,谁小就放到我们的数组中 如果比较完之后还有剩余的数据,那么用while直接添加到我们的总数组中 优化思路 当递归到规模足够小时,利用插入排序 归并前判断一下是否还有必要归并 只在排序前开辟一次空间 基数(桶)排序 思想 分配,回收(分配到不同的位置上,然后回收)..不断分配..回收来进行排序,直到有序 做法 分配一个[array.length][10列]的二维数组来装我们的元素 最外层for循环控制要分配和回收的次数(根据最大值) 将元素的个、十、百位依次放到桶子上(第一次就是放个位,第二次放十位) 依据每列回收桶子,两个for循环 外排序 查找算法 二分查找 分块查找 哈希查找 贪心算法 求最小生成树的Prim算法和Kruskal算法 爬山问题 回溯算法 n皇后问题 动态规划Dynamic Planning 应用 求最长公共子序列LCS 矩阵连乘问题 爬楼梯问题 找零问题 0-1背包问题 分治算法Divide and Conquer 应用:归并排序 其它 Rabin fingerprints 文件指纹算法 BitMap 位图算法 BloomFilter 布隆过

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿波茨地额佛鸽

鼓励鼓励 嘻嘻~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值