栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

排序方法总纲

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

排序方法总纲

排序方法
内部排序: 数据全部加载进内存,
外部排序: 数据量过大, 无法全部加载进内存, 需要借助外存来进行排序

内部排序
插入排序: 直接插入排序, 希尔排序
选择排序: 简单选择排序, 堆排序
交换排序: 冒泡排序, 快速排序
归并排序:
基数排序:

算法的时间复杂度
基本介绍
时间频度: 一个算法花费的时间与算法中语句执行的次数成正比, 那个算法中语句执行次数越多, 它花费的时间也就越多, 一个语句执行的次数称之为语句频度或者时间频度, 记为T(n).
忽略常数项(也就是看循环)
忽略低次项
忽略系数
也就是说T(n)不同, 但是时间复杂度可能相同.
T(n) -> f(n) -> O(f(n))
常见的时间复杂度大小梯队
O(1)
冒泡排序

import java.util.Arrays;

public class Maopao {
    public static void main(String[] args) {
        int[] arr = {3,4,5,6,8,7};
        int temp = 0;
        for (int i = 1; i <= arr.length-1; i++){  //第一层循环表示第几趟,
            for (int j = 0; j < arr.length-i; j++){  //length-i, 这里的i 表示到了倒数的第i个元素, 就不需要再和后面的数比较了, 因为要么是数组的最后, 要么是上一趟冒出来的最大值.
                if (arr[j] > arr[j+1]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
            System.out.println("第"+i+"趟排序后为:");
            System.out.println(Arrays.toString(arr));
        }

        //优化写法
        int temp1 = 0;
        boolean flag = false;  //判断该趟是否有发生换位, 默认没有
        for (int i = 1; i <= arr.length-1; i++){  //第一层循环表示第几趟,
            for (int j = 0; j < arr.length-i; j++){  //length-i, 这里的i 表示到了倒数的第i个元素, 就不需要再和后面的数比较了, 因为要么是数组的最后, 要么是上一趟冒出来的最大值.
                if (arr[j] > arr[j+1]){
                    temp1 = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp1;
                    flag = true;
                }
            }
            System.out.println("第"+i+"趟排序后为:");
            System.out.println(Arrays.toString(arr));
            if (flag){
                flag = false;
            }else{
                break;
            }
        }
    }
}

选择排序
思想: 第一次从arr[0]~到arr[n-1]中选取最小值, 与arr[0]交换, 第二次从arr[1]~arr[n-1]中选取最小值, 与arr[1]交换,以此类推

import java.util.Arrays;

public class Xuanze {
    public static void main(String[] args) {
        int[] arr = {1,2,4,3,5,6};

        for (int i = 0; i < arr.length-1; i++){  //永远都是拿前面的一个做预设的min, 所以要length-1. 因为只用到倒数第二个的位置
            int minIndex = i;
            int min = arr[i];
            for (int j = i+1; j < arr.length; j++){  //永远都是拿预设的min和它之后的每一个数比较, 冲突则改min
                if (min > arr[j]){
                    min = arr[j];
                    minIndex = j;
                }
            }
            if (minIndex != i){  //如果min不是预设的, 位置交换
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
            System.out.println("第"+(i+1)+"趟排序后:");
            System.out.println(Arrays.toString(arr));
        }

        //没法像冒泡一样做优化. 因为选择排序一定要执行到最后一趟才能完全确定是不是排序完成.
        //不像冒泡, 只要有一次没有发生位置的交换就是排序好了. 

    }
}

插入排序
基本思路
把n个元素看成一个有序表和一个无序表, 开始时, 有序表中只有一个元素, 而无序表中有n-1个元素, 每次从无序表中拿出第一个元素, 把他的排序码和依次与有序表的排序码进行比较, 将他插入到有序表的适当位置.

import java.util.Arrays;

public class Charu {
    public static void main(String[] args) {
        int[] arr = {2,1,5,3,0};

        for (int i = 1; i< arr.length; i++){  //从无序表的第一个找到最后一个
            int wuxu1 = arr[i];  //每一次都先取出无序表的第一个数据
            int youxuIndex = i-1;  //每一次都从有序表的最后一个数据开始判断
            while(youxuIndex >= 0 && wuxu1 < arr[youxuIndex]){
                arr[youxuIndex+1] = arr[youxuIndex];
                youxuIndex--;
            }
            arr[youxuIndex+1] = wuxu1;
            System.out.println("第"+i+"趟排序后为:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

简单的插入排序有缺陷, 当后面的数越小, while循环的次数就越多
希尔排序, 也是一种插入排序, 但是效率更高, 也叫缩小增量排序
希尔排序: 交换法+移动法
这里我直接就只有移位法, 移位法来的好理解的多, 因为本来就是直接插入法的一种优化, 如果不知道直接插入法是怎么一回事, 确实理解起来会很困难. 但是如果直到了直接插入法的缺点在哪里之后, 就很容易理解希尔排序为什么要这么做.

public class Shell {
    public static void main(String[] args) {
        int[] arr = {9,8,7,6,5,4,3,2,1,0};

        int count = 0;
        for (int gap = arr.length/2; gap > 0; gap /= 2){
            //其实这里就是直接插入排序
            for (int i = gap; i < arr.length; i++){  //确保每一次都是拿到的该组的无序表的第一个元素, 或者更准确的说是, 先拿到每一组的无序表的第一个数
                int j = i;
                int temp = arr[i];
                if (arr[i] < arr[i-gap]){
                    while(j-gap >=0 && temp < arr[j-gap]){
                        //移动
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    //每一次出这个while就说明temp已经找到了位置. 准确的说是在temp对应的组中找到了正确的位置
                    arr[j] = temp;
                }
            }
            System.out.println("第"+(++count)+"趟之后的排序是"+ Arrays.toString(arr));
        }
    }
}

快速排序
思路
快速排序是冒泡排序的一种优化, 本质上也是交换排序
也是元素之间相互比较 , 然后交换位置
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

public class Kuaisu {
    public static void main(String[] args) {
        int[] arr = {5,6,89,45,1,0,32,54,88,412,986,4,2,6};

        kuaisupaixu(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));

    }

    static public void  kuaisupaixu(int[] arr, int left, int right){
        int l = left;
        int r = right;  //冒泡是以i和i+1来进行判断并交换, 但是快排使用的是l和r
        int jishu = arr[(right+left)/2];  //基数
        int temp = 0; //交换容器
        while(l < r){    //如果没有交汇或者相遇, l和r继续前进
            while(arr[l] < jishu){
                l += 1;
            }
            while(arr[r] > jishu){
                r -= 1;
            }
            if (l >= r){   //l和r一旦相遇或者交汇, 就意味着一轮的结束, 
                break;
            }
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
            if (arr[l] == jishu){
                r -= 1;
            }
            if (arr[r] == jishu){
                l += 1;
            }
        }
        if (l == r){
            l += 1;
            r -= 1;
        }
        if (left < r){
            kuaisupaixu(arr, left, r);
        }
        if (right > l){
            kuaisupaixu(arr, l, right);
        }
    }
}

归并排序
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,归并排序对序列的元素进行逐层折半分组,然后从最小分组开始比较排序,合并成一个大的分组,逐层进行,最终所有的元素都是有序的
由归并排序的这种分治思想可以知道
归并排序的归并次数永远都是arr.lenght-1次. 也即是数据的个数减一
所以归并排序是一种效率很好的排序.

public class Guibing {
    public static void main(String[] args) {
        int[] arr = {8,5,7,6,2,4,3,1,0};
        int[] tempArr = new int[arr.length];
        fenAndzhi(arr, 0, arr.length-1, tempArr);
        System.out.println("归并排序之后为:"+ Arrays.toString(arr));

    }

    //分+治的算法
    //用于递归
    static public void fenAndzhi(int[] arr , int left, int right , int[] tempArr){
        if (left < right){
            int mid = (left+right)/2;
            //向左递归
            fenAndzhi(arr, left, mid, tempArr);
            //向右递归
            fenAndzhi(arr, mid+1, right, tempArr);
            //治
            zhi(arr, left, right, mid, tempArr);
        }
    }
    //治的算法
    static public void zhi(int[] arr , int left , int right , int mid, int[] tempArr){
        int i = left;  //左子集的开始索引
        int j = mid +1;  //右子集的开始索引
        int t = 0; //占存数组的开始索引

        while (i <= mid && j <= right){
            if (arr [i] <= arr[j]){
                tempArr[t] = arr[i];
                i++;
                t++;
            }else{
                tempArr[t] = arr[j];
                j++;
                t++;
            }
        }

        //有一边会剩数
        while (i <= mid){
            tempArr[t] = arr[i];
            t++;
            i++;
        }
        while (j <= right){
            tempArr[t] = arr[j];
            t++;
            j++;
        }

        //分治思想: 其实每一次都是前面的两个先治, 顺序向后
        //所以temp的数据可以直接替换arr的数据
        //例如这里治的顺序就是(0~1)(2~3)(0~3)(4~5)(6~7)(4~7)(0~7)
        t = 0;
        int l = left;  //确定放在arr的哪里
        while (l <= right){
            arr[l] = tempArr[t];
            l++;
            t++;
        }

    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/459629.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号