直接插入排序(Java)

简介: 直接插入排序(Java)

文章汇总归纳整理于:算法竞赛学习之路[Java版]

直接插入排序的基本思想

  • 每次从未排序的子序列中取出一个待排序的记录按其关键字大小插入前面已排好序的子序列,直到全部记录插入完成
  • 假设在排序过程中,待排序表 L[1…n] 在某次排序过程中的某一时刻状态如下:
  • 要将元素 L[i] 插入已有序的子序列 L[1…i-1],需要执行以下操作:
  • 1)查找出 L[i] 在 L[1…i-1] 中的插入位置k。
  • 2)将 L[k…i-1] 中的所有元素依次后移一个位置。
  • 3)将 L[i] 复制到 L[k]。
  • 为了实现对 L[1…n] 的排序,可以将 L[2]~L[n] 依次插入前面已排好序的子序列,初始 L[1] 可以视为是一个已排好序的子序列。
  • 上述操作执行 n-1 次就能得到一个有序的表。
  • 插入排序在实现上通常采用就地排序(空间复杂度为O(1)),在从后向前的比较过程中,需要反复把已排序的元素逐步向后挪位,为新元素提供插入空间。

直接插入排序的排序过程

直接插入排序的代码实现

P2676 [USACO07DEC]Bookshelf B 为例,实现直接插入排序

// package 直接插入排序;
import java.io.*;
public class Main {
    // 快读快写
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static void main(String[] args) {
        int n = readInt(); // 奶牛的个数
        // 由于 1≤B≤S<2,000,000,007 使用 long
        long b = readLong(); // 书架的高度
        long[] hs = new long[n]; // 每个奶牛的高度
        // 读入每个奶牛的高度
        for (int i = 0; i < n; i++) {
            hs[i] = readLong();
        }
        // 插入排序(从小到大排序)
        for (int i = 1; i < n; i++) {
            long hi = hs[i]; // 当待插入有序子序列的数据
            int idx = i - 1;
            // 查找插入位置
            while (idx >= 0 && hs[idx] > hi) {
                hs[idx+1] = hs[idx];
                idx--;
            }
            // 将数据插入(退出循环前会 -- 一次,所以idx+1)
            hs[idx+1] = hi;
        }
        // 查看排序后的数据
        // for ( int i=0; i<n; i++ ) {
        //     out.println(hs[i]);
        // }
        // 塔中奶牛的数目尽量少,且所有奶牛的身高和必须不小于书架的高度
        // 所以从后向前遍历,直到奶牛的身高和大于等于书架高
        int cnt = 0; // 最少要多少头奶牛叠成塔,才能够到书架顶部
        int h_sum = 0; // 当前奶牛的身高和
        for ( int i=n-1; i>=0; i-- ) {
            h_sum += hs[i]; // 塔中奶牛的身高和增加
            cnt++; // 塔中奶牛的数目++
            // 如果奶牛的身高和大于等于书架高,退出循环
            if ( h_sum >= b ) {
                break;
            }
        }
        out.print(cnt);
        out.flush();
    }
    // 读入长整型整数
    static long readLong() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (long) in.nval;
    }
    // 读入整数
    static int readInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int) in.nval;
    }
}

直接插入排序算法的性能分析

  • 空间效率:仅使用了常数个辅助单元,因而空间复杂度为O(1)。
  • 时间效率:
  • 在排序过程中,向有序子表中逐个地插入元素的操作进行了 n-1 趟,每趟操作都分为比较关键字和移动元素,而比较次数和移动次数取决于待排序表的初始状态。
  • 在最好情况下,表中元素已经有序,此时每插入一个元素,都只需比较一次而不用移动元素,因而时间复杂度为O(n)。
  • 在最坏情况下,表中元素顺序刚好与排序结果中的元素顺序相反(逆序),总的比较次数达到最大,总的移动次数也达到最大,总的时间复杂度为O(n2)。
  • 平均情况下,考虑待排序表中元素是随机的,此时可以取上述最好与最坏情况的平均值作为平均情况下的时间复杂度,总的比较次数与总的移动次数均约为n2/4。
  • 因此,直接插入排序算法的时间复杂度为O(n2)。
  • 稳定性:由于每次插入元素时总是从后向前先比较再移动,所以不会出现相同元素相对位置发生变化的情况,即直接插入排序是一个稳定的排序方法。
相关文章
|
算法 Java 索引
java基础算法系列(四)(直接插入排序以及二分插入讲解)
java基础算法系列(四)(直接插入排序以及二分插入讲解)
|
算法 Java
Java实现直接插入排序
插入排序 简单来说,就是将要排序的元素,分为两部分,一部分为有序表,一部分为无序表,每次从无序表中取出一个元素插入到有序表中。
113 0
Java实现直接插入排序
Java课后练习 对应冒泡排序、直接选择排序、直接插入排序进行选择调用,手动输入一组数字(空格隔开)转为数组 最后排序前后结果
Java课后练习 对应冒泡排序、直接选择排序、直接插入排序进行选择调用,手动输入一组数字(空格隔开)转为数组 最后排序前后结果
Java课后练习 对应冒泡排序、直接选择排序、直接插入排序进行选择调用,手动输入一组数字(空格隔开)转为数组 最后排序前后结果
|
存储 搜索推荐 算法
数据结构 | 排序算法总结——(一)直接插入排序(附Java实现代码)
数据结构 | 排序算法总结——(一)直接插入排序(附Java实现代码)
|
搜索推荐 算法 Java
插入排序(直接插入排序)java代码实现(注释详细 简单易懂)
插入排序(直接插入排序)java代码实现(注释详细 简单易懂)
138 0
|
人工智能 Java
Java使用二分插入排序竟然和直接插入排序速度比较
 Java使用二分插入排序竟然和直接插入排序速度比较 之前测试过Python使用二分插入排序竟然比直接插入排序快99倍! 现在测试下 Java,Linux测试结果如下: javac test.java java testInsertSort total milliseconds:15769InsertSortWithBinarySerach total milliseconds:15657 更正下,上面的数据在一台虚拟机上测试的,所以样本不够,理论上,这两个算法的速度应该是有倍数差别的。
1289 0
|
9天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
38 6
|
24天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
22天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####