zoukankan      html  css  js  c++  java
  • 排序算法

    排序算法

    常用排序算法的理解及示例代码:冒泡排序、插入排序、选择排序、归并排序、快速排序、二叉树排序

    分析算法

    1. 内存消耗:是否是原地排序算法。指空间复杂度为 O(1) 的算法
    2. 稳定性:是否是稳定的排序算法。等值元素排序后次序不变,为稳定的排序算法
    3. 执行效率:时间复杂度,最好、最坏、平均或均摊

    冒泡排序

    相邻元素根据大小交换位置,每次遍历将一个元素放到合适的位置上

    1. 是否原地排序:原地排序
    2. 是否稳定:控制相邻元素大小相等时不做交换,则为稳定排序
    3. 时间复杂度:(O(n^2))
    4. 设置标志位,优化算法,避免已经有序后还在做无用循环
    public static void bubble(int[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            boolean traverse = true;//是否还需要遍历的标志
            for (int j = 0; j < a.length - i - 1; j++) {
                if (a[j] > a[j + 1]) {
                    traverse = false;
                    int temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                }
                if (traverse) break;
            }
        }
    }
    

    插入排序

    总是取无序区第一个元素,有序区由大向小与该元素比较,比该元素大则后移一位,最终让出合适位置

    1. 是否原地排序:原地排序
    2. 是否稳定:控制后面出现的元素插入到前面相同元素的后面,则为稳定排序
    3. 时间复杂度:(O(n^2))
    public static void insert(int[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            int x = a[i + 1];
            int j = i;
            for (; j >= 0; j--) {
                if (a[j] > x) a[j + 1] = a[j];//比 x 大后移一位
                else break;//找到合适位置
            }
            a[j + 1] = x;//循环中多减了一次 1
        }
    }
    

    选择排序

    依次遍历每个位置,与后续元素比较,比该位小的换到该位

    1. 是否原地排序:原地排序
    2. 是否稳定:不是稳定排序
    3. 时间复杂度:(O(n^2))
    public static void select(int[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j] < a[i]) {
                    int temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                }
            }
        }
    }
    

    归并排序

    原数组分成两部分,递归得到 length 个数组,每个数组中一个元素

    两两数组合并,递归得出排序结果

    1. 是否原地排序:非原地排序,空间复杂度较高,(O(n))
    2. 是否稳定:稳定
    3. 时间复杂度:(O(nlogn))
    public static void sort(int[] a, int left, int right) {
        if (left >= right) return;
        int mid = left + (right - left >> 2);//取中间元素
        sort(a, left, mid);
        sort(a, mid + 1, right);
        merge(a, left, mid, right);
    }
    
    public static void merge(int[] a, int left, int mid, int right) {
        int[] temp = new int[right - left + 1];
        int l = left, r = mid + 1, count = 0;
        // 比较两部分放入大小,小元素放入数组
        while (l <= mid && r < right) {
            temp[count++] = a[l] < a[r] ? a[l++] : a[r++];
        }
        // 两部分个数不一样时,将长的部分剩余元素加入数组
        while (l > mid && r <= right) temp[count++] = a[r++];
        while (l <= mid && r > left) temp[count++] = a[l++];
        // 复制给原数组
        for (int i = 0; i < temp.length; i++) {
            a[left + i] = temp[i];
        }
    }
    

    快速排序

    设置头尾指针,选取一个元素作为中点

    先从尾指针向前找比中点小的,移到头指针,头指针后移一位

    再从头指针向后找比中点大的,移到尾指针,尾指针前移一位

    指针相遇时,得到中点位置,保证了该位置左边元素小,右边元素大

    递归执行头结点到中点 -1、中点 +1 到尾结点两段元素的排序

    1. 是否原地排序:原地排序
    2. 是否稳定:不稳定
    3. 时间复杂度:(O(nlogn))
    public static void quick(int[] a, int left, int right) {
        if (left >= right) return;
        int i = left, j = right;
        int x = a[left];
        while (i < j) {
            while (i < j && a[j] >= x) j--;
            if (i < j) a[i++] = a[j];
            while (i < j && a[i] <= x) i++;
            if (i < j) a[j--] = a[i];
        }
        a[i] = x;
        quick(a, left, i - 1);
        quick(a, i + 1, right);
    }
    

    二叉树排序

    左小右大生成二叉树,中序遍历得出的结果有序

    1. 是否原地排序:非原地排序
    2. 是否稳定:控制相等时放在右结点,则为稳定排序
    3. 时间复杂度:(O(n))
    public static void treeSort(int[] a) {
        TreeNode tree = new TreeNode();
        for (int i : a) {//生成树
            tree.add(i);
        }
        List<Integer> list = tree.inOrder();//中序遍历
        for (int i = 0; i < list.size(); i++) {
            a[i] = list.get(i);//装回数组 
        }
    }
    
    static class TreeNode {//静态内部类,可在静态方法中实例化
        TreeNode left, right;
        Object value;
    	// 左小右大生成二叉树树
        public void add(Object o) {
            if (value == null) {
                value = o;
            } else {
                if ((int) o < (int) value) {
                    left = (left == null) ? new TreeNode() : left;
                    left.add(o);
                } else {
                    right = (right == null) ? new TreeNode() : right;
                    right.add(o);
                }
            }
        }
    	// 中序遍历得出的结果有序	
        public List<Integer> inOrder() {
            List<Integer> list = new ArrayList<>();
            if (left != null) list.addAll(left.inOrder());
            list.add((int) value);
            if (right != null) list.addAll(right.inOrder());
            return list;
        }
    }
    
  • 相关阅读:
    as3工程和flex工程的区别
    Timer的repeatCount和currentCount的区别
    mouseChildren为false后,
    flex编译时,会把trace语句也编译进去
    stage和root的区别
    flex编译时,会把trace语句也编译进去
    水瓶座(1.202.19)更多星座运程
    如何更改titleWindow组件上的title字体大小?
    转贴关于AsWing和MXML 选项
    Eclipse中的文本编辑器使用技巧
  • 原文地址:https://www.cnblogs.com/cadecode/p/12492745.html
Copyright © 2011-2022 走看看