• 排序算法


    初级排序算法:

    选择排序  从数组中选择最小元素,将它与数组的第一个元素交换位置。再从数组剩下的元素中选择出最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。
        特点:时间与输入数组的性质无关(已经很慢了),就算排好了也全走一遍
           数据移动少,每次移动俩。

    public class Selection<T extends Comparable<T>> extends Sort<T> {
    
        @Override
        public void sort(T[] nums) {
            int N = nums.length;
            for (int i = 0; i < N - 1; i++) {
                int min = i;
                for (int j = i + 1; j < N; j++) {
                    if (less(nums[j], nums[min])) {
                        min = j;
                    }
                }
                swap(nums, i, min);
            }
        }
    }

    冒泡排序  从左到右不断交换相邻逆序的元素,在一轮的循环之后,可以让未排序的最大元素上浮到右侧。在一轮循环中,如果没有发生交换,那么说明数组已经是有序的,此时可以直接退出。

    public class Bubble<T extends Comparable<T>> extends Sort<T> {
    
        @Override
        public void sort(T[] nums) {
            int N = nums.length;
            boolean isSorted = false;
            for (int i = N - 1; i > 0 && !isSorted; i--) {
                isSorted = true;
                for (int j = 0; j < i; j++) {
                    if (less(nums[j + 1], nums[j])) {
                        isSorted = false;
                        swap(nums, j, j + 1);
                    }
                }
            }
        }
    }

    插入排序  从a[0]开始,与它前面的元素做比较,满足小于等于则做交换(将当前元素插入到左侧已经排序的数组),使得插入之后左侧数组依然有序。
        特点:对部分有序的数组性能优越
           适合小规模数组

    public class Insertion<T extends Comparable<T>> extends Sort<T> {
    
        @Override
        public void sort(T[] nums) {
            int N = nums.length;
            for (int i = 1; i < N; i++) {
                for (int j = i; j > 0 && less(nums[j], nums[j - 1]); j--) {
                    swap(nums, j, j - 1);
                }
            }
        }
    }
    

      

    希尔排序  将h间隔内的数进行插入排序(跨着排),逐步减小h。其中h初始化为1,4,13,40(3*h+1)且满足N/3的最大值。每次h/3
        特点:数组越大,优势越明显。
           代码量小
           无需额外空间
          实际上是优化了的插入排序,减小低效交换次数加快速度

    public class Shell<T extends Comparable<T>> extends Sort<T> {
    
        @Override
        public void sort(T[] nums) {
    
            int N = nums.length;
            int h = 1;
    
            while (h < N / 3) {
                h = 3 * h + 1; // 1, 4, 13, 40, ...
            }
    
            while (h >= 1) {
                for (int i = h; i < N; i++) {
                    for (int j = i; j >= h && less(nums[j], nums[j - h]); j -= h) {
                        swap(nums, j, j - h);
                    }
                }
                h = h / 3;
            }
        }
    }
    

      

    归并排序  分为自顶向下与自底向上使用归并方法

    public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
    
        protected T[] aux;
    
    
        protected void merge(T[] nums, int l, int m, int h) {
    
            int i = l, j = m + 1;
    
            for (int k = l; k <= h; k++) {
                aux[k] = nums[k]; // 将数据复制到辅助数组
            }
    
            for (int k = l; k <= h; k++) {
                if (i > m) {
                    nums[k] = aux[j++];
    
                } else if (j > h) {
                    nums[k] = aux[i++];
    
                } else if (aux[i].compareTo(aux[j]) <= 0) {
                    nums[k] = aux[i++]; // 先进行这一步,保证稳定性
    
                } else {
                    nums[k] = aux[j++];
                }
            }
        }
    }
    

          自顶向下:递归分成小段排序,归并

    public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
    
        @Override
        public void sort(T[] nums) {
            aux = (T[]) new Comparable[nums.length];
            sort(nums, 0, nums.length - 1);
        }
    
        private void sort(T[] nums, int l, int h) {
            if (h <= l) {
                return;
            }
            int mid = l + (h - l) / 2;
            sort(nums, l, mid);
            sort(nums, mid + 1, h);
            merge(nums, l, mid, h);
        }
    }

          自底向上:先遍历,两两归并(最小的归并就是排序),子数组大小每次加倍。(不需要递归,代码量较少)

    public class Down2UpMergeSort<T extends Comparable<T>> extends MergeSort<T> {
    
        @Override
        public void sort(T[] nums) {
    
            int N = nums.length;
            aux = (T[]) new Comparable[N];
    
            for (int sz = 1; sz < N; sz += sz) {
                for (int lo = 0; lo < N - sz; lo += sz + sz) {
                    merge(nums, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1));
                }
            }
        }
    }

        特点:需要的额外空间与待排序数组大小N成正比(空间复杂度不佳)
           最差情形与一般情形时间复杂度相同:都为NlgN,在基于比较排序的算法中渐进最优。

    堆排序   应用优先队列对元素排序,建堆并且不断调整堆,不断取下最大值调整(递归)
        特点:同时最好地利用时间空间的排序算法
           代码简洁
           无法使用缓存

    快速排序  将待排的数组分为两个子数组,其中左子数组全小于中间元素,右子数组全大于中间元素。两个子数组分别排序
        特点:内循环简洁,不在内循环中移动数据,速度快
           比较次数较少,代码量少
           问题较多,较为脆弱
           偏爱随机性,排前打乱数组
          改进版快排----三向切分(适用于待排序的数组中存在大量重复数据,开销由线性对数降低到线性),三个指针分三部分。
      

           

  • 相关阅读:
    init-method,@postcontruct,afterPropertiesSet的先后顺序
    读写分离与分库分表,分布式事务面试题
    innerHTML的HTML居然必须大写..不可思议
    postgres/greenplum unnest(Array) 实现列转行
    AWS EBS磁盘挂载和卸载
    当npm 与淘宝镜像cnpm运行都很慢时候
    IntersectionObserver API 之学习
    vue之队列过渡组效果,后进先出坑点
    ele之vue3.0的form表单验证与重置
    vue3.0之DOM的$refs之运用
  • 原文地址:https://www.cnblogs.com/lvoooop/p/10728760.html
Copyright © 2020-2023  润新知