zoukankan      html  css  js  c++  java
  • 排序算法(1) --- 直接插入排序及改进

    • 直接插入排序

    直接插入排序就是每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。比较简单就直接上代码了。

    • 代码

    public static <T extends Comparable<? super T>> void insertionSort(T[] a) {
            int j;
            
            for (int i = 1; i < a.length; i++) {
                T tmp = a[i];
                for (j = i; j > 0 && tmp.compareTo(a[j-1]) < 0; j--) {
                    a[j] = a[j-1];
                }
                a[j] = tmp;
            }
        }
    • 二叉查找插入排序

    又之前的代码可以看出,直接插入排序的时间复杂度为O(n2),而且还可以看出,每次有新数据往里插的时候,都是从最后开始往前遍历,因为之前的数据已经是排好序的了,所以,我在查找应该插哪的时候,就可以使用二叉查找法来定位。这也是我看JDK源码Arrays.sort()方法时发现的。

    • 代码

    • 对于基本数据类型
    public static void insertionSortWithBinary1(Object[] a) { // 对于基本数据类型,不需要实现Comparator接口
            int lo = 0;
            int hi = a.length;
            int start = 1; // 未排序的开始下标
            
            for ( ; start < hi; start++) {
                Comparable pivot = (Comparable) a[start]; 
    
                int left = lo;
                int right = start;
                
                // 使用二分查找算法
                while (left < right) {
                    int mid = (left + right) >>> 1; // >>>是无符号右移一位,就相当于除以2
                    if (pivot.compareTo(a[mid]) < 0) 
                        right = mid;
                    else
                        left = mid + 1;
                }
               
                int n = start - left;  // 需要移动的位数
                switch (n) {
                    case 2:  a[left + 2] = a[left + 1]; // 如果是只需要移动1位或者2位,就直接移
                    case 1:  a[left + 1] = a[left];
                             break;
                    default: System.arraycopy(a, left, a, left + 1, n); // 如果超过两位就调用这个方法,因为是naive方法执行很快
                }
                a[left] = pivot; // 插入
            }
        }
    • 对于复杂数据类型,例如类
    public static <T extends Comparable<? super T>> void insertionSortWithBinary2(T[] a) {
            int lo = 0;
            int hi = a.length;
            int start = 1; // 未排序的开始下标
            
            for ( ; start < hi; start++) {
                T pivot =  a[start]; 
    
                int left = lo;
                int right = start;
                
                // 使用二分查找算法
                while (left < right) {
                    int mid = (left + right) >>> 1; // >>>是无符号右移一位,就相当于除以2
                    if (pivot.compareTo(a[mid]) < 0) // compare是传递过来的Comparator的自定义比较方法
                        right = mid;
                    else
                        left = mid + 1;
                }
               
                int n = start - left;  // 需要移动的位数
                switch (n) {
                    case 2:  a[left + 2] = a[left + 1]; // 如果是只需要移动1位或者2位,就直接移
                    case 1:  a[left + 1] = a[left];
                             break;
                    default: System.arraycopy(a, left, a, left + 1, n); // 如果超过两位就调用这个方法,因为是naive方法执行很快
                }
                a[left] = pivot; // 插入
            }
            
        }
    • 测试

    class Person implements Comparable<Person> {
        private String name;
        public Person(String name) {
            this.name = name;
        }
        @Override
        public int compareTo(Person o) {
            return this.name.compareTo(o.name);
        }
        public String toString() {
            return this.name;
        }
    }
    
    public static void main(String[] args) {
            Integer[] a = new Integer[]{1,23,234,234,22,1,-1,0,3};
            Person[] p1 = new Person[]{ new Person("Tom"), new Person("Alice") };
            System.out.println("直接插入排序测试(基本数据类型):");
            insertionSort(a);
            for (int i : a) {
                System.out.print(i + " ");
            }
            System.out.println();
            
            System.out.println("直接插入排序测试(类):");
            insertionSort(p1);
            for (Person p : p1) {
                System.out.print(p + " ");
            }
            System.out.println();
            
            Integer[] b = new Integer[]{1,23,234,234,22,1,-1,0,3};
            System.out.println("二叉查找插入排序测试(基本数据类型):");
            insertionSortWithBinary1(b);
            for (int i : b) {
                System.out.print(i + " ");
            }
            System.out.println();
            
            Person[] p2 = new Person[]{ new Person("Tom"), new Person("Alice") };
            System.out.println("二叉查找插入排序测试(类):");
            insertionSort(p2);
            for (Person p : p2) {
                System.out.print(p + " ");
            }
            
        }
    • 结果

     

  • 相关阅读:
    vim /home/yuanyc/.bashrc export LC_ALL=zh_CN.UTF-8
    mongodb
    关于RegisterClass和CreateWindow
    c++中sqlite中文路径创建数据库失败的问题
    Layered Window 透明窗体的实现总结
    c++单列模式与线程安全
    Windows下API Hook 技术
    COM编程大致梳理
    关于c++多态
    几个多字节和UNICODE及UTF-8之间相互转化的函数
  • 原文地址:https://www.cnblogs.com/yangtong/p/6906278.html
Copyright © 2011-2022 走看看