九大排序算法及耗时测试、适用场合

九大排序算法简单集合

本人刚学习完排序算法,看的是《数据结构与算法分析(Java描述版)(第四版)》,与C描述版还是有些不一样的地方,写下此博客与各位初学者分享,代码中已写好详细的注释,也分析了各种算法的适用场合,如有不懂可以留言。最后给出了Github上源代码获取网址,建议在IDE中边看边测试。第一次写,写得不好的地方请谅解。

  • 插入排序
    • 直接插入排序
    • 希尔排序
  • 选择排序
    • 直接选择排序
    • 堆排序
  • 交换排序
    • 冒泡排序
    • 快速排序
  • 归并排序
  • 基数排序
  • 外部排序

/*
 *         ┏┓      ┏┓+ +
 *           ┏━┛┻━━━━━━┛┻━┓ + +
 *           ┃       ┃ + + +
 *           ┃     ━      ┃ + + + +
 *           ┃ ████━████  ┃
 *           ┃            ┃ + +
 *           ┃     ┻      ┃
 *           ┃            ┃ +
 *           ┗━━┓      ┏━━┛
 *              ┃      ┃
 *              ┃      ┃ + + + +
 *              ┃      ┃     Code is far away from bug with the animal protecting
 *              ┃      ┃ +      神兽保佑,代码无bug
 *              ┃      ┃
 *              ┃      ┃  +
 *              ┃      ┗━━━━━━━┓ + +
 *              ┃              ┣━┓
 *              ┃              ┏━┛
 *              ┗━┓ ┓ ┏━━┳━┓ ┏━┛ + + + +
 *                ┃ ┫ ┫  ┃ ┫ ┫
 *                ┗━┻━┛  ┗━┻━┛+ + + +
 */

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * 多种排序算法集合
 * 为什么快排在实际使用中通常优于堆排序?
 * 局部性原理,越靠近的数据比较和交换用时越少,而且CPU的Cache中缓存了最近频繁读写的数据。
 * 在堆排中,每一个操作都是不利于程序的局部性原理的,每次元素间的比较、数的调整等,
 * 最大堆调整每次都从堆底拿元素换到堆顶然后又下滤下去,在堆底一般都比较小,很大可能再次下滤到底层,
 * 这个过程做了很多无用功,需要不断地跨度大地读写数据。
 * 反观快速排序和归并排序,利用分而治之的方法,元素间的比较都在某个段内,操作比较集中,局部性相当好。
 *
 * 快排<归并<堆排<希尔<<<插入<选择<冒泡
 *
 * @author Macer_YGG
 * @version V1.1
 * @date 2018/04/30 23:08
 */
public class SortDemo {
   
    /**
     * timer 计时用
     */
    private static long timer;

    /**
     * Simple insertion sort 直接插入排序
     * 每步将一个待排序的元素,按大小插入前面已经排序的序列中适当位置上,直到全部插入完为止
     * 时间复杂度O(n^2),空间复杂度O(1),稳定
     * 适用场合:数据量不大,对算法的稳定性有要求,且数据局部或者整体有序的情况,小规模如10个数平均时间最快,可以在快排中调用
     *
     * @param a   an array of Comparable items.
     * @param <T> 实现Comparable接口的类
     */
    public static <T extends Comparable<? super T>> void insertionSort(T[] a) {
        long start = System.currentTimeMillis();
        int j;
        T tmp;
//        从第二个元素开始,向前试探性插入
        for (int i = 1; i < a.length; i++) {
            if (a[i].compareTo(a[i - 1]) < 0) {
//                将当前元素暂存
                tmp = a[i];
//                向前比较,若符合要求则将比较项往右移存
                for (j = i; j > 0 && tmp.compareTo(a[j - 1]) < 0; j--) {
                    a[j] = a[j - 1];
                }
//                插入
                a[j] = tmp;
            }
        }
        timer = System.currentTimeMillis() - start;
    }

    /**
     * ShellSort 希尔排序
     * 是插入排序的一种又称"缩小增量排序"(Diminishing Increment Sort)
     * 使用简单的希尔增量序列,复杂的增量序列中Sedgewick 增量序列最坏时间复杂度达到O(n^1.3)
     * 时间复杂度取决于增量序列,空间复杂度O(1),不稳定!!!
     * 适用场合:数据量较大,不要求稳定性
     *
     * @param a   an array of Comparable items.
     * @param <T> 实现Comparable接口的类
     */
    public static <T extends Comparable<? super T>> void shellSort(T[] a) {
        long start = System.currentTimeMillis();
        T tmp;
        int j;
//        使用希尔增量序列
        for (int gap = a.length / 2; gap > 0; gap /= 2) {
//            里层用的是直接插入排序算法
            for (int i = gap; i < a.length; i++) {
                if (a[i].compareTo(a[i - gap]) < 0) {
                    tmp = a[i];
                    for (j = i; j >= gap && tmp.compareTo(a[j - gap]) < 0; j -= gap) {
                        a[j] = a[j - gap];
                    }
                    a[j] = tmp;
                }
            }
        }
        timer = System.currentTimeMillis() - start;
    }

    /**
     * SelectionSort 直接选择排序
     * 每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完
     * 时间复杂度O(n^2),空间复杂度O(1),不稳定
     * 适用场合:当数据量不大,且对稳定性没有要求的时候
     *
     * @param a   an array of Comparable items.
     * @param <T> 实现Comparable接口的类
     */
    public static <T extends Comparable<? super T>> void selectionSort(T[] a) {
        long start = System.currentTimeMillis();
//        第 i+1 个最小元素位置标记
        int minIndex;
        T tmp;
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值