简单算法之9种排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单算法之9种排序相关的知识,希望对你有一定的参考价值。

甭管什么,笔者就喜欢凑个9。这次,关于排序的算法还是9种,小结一下。排序的算法,尽管有很多的方法例子,但这次是自己总结的,挺有意思算法希望大家喜欢。直接上代码楼,以下算法,都经过笔者亲测,并修改使之有效(粘贴可用)。

package com.css.java.learning.massbag;
import java.util.Arrays;
/**算法:
 * 排序相关小结
 * @author Red_ant
 * 20181119
 */
public class OrderMethod {
    /*1、冒泡排序
     * 通过相邻两个元素比较的方式,依次选出合适的元素放到
     * 数组的第i位。
     */
    public static int[] bubbleSort(int[] nums){
        int num = 0;
        for (int i = 0; i < nums.length -1; i++) {
            for (int j = 0; j < nums.length - 1 - i; j++) {//两两比较,符合条件的元素居于前面
                if(nums[j] > nums[j + 1]){
                    num = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = num;
                }
            }
        }
        return nums;
    }
    /*2、选择排序
     * 每一趟从待排序列,选择最小的元素放到已排序好的序列末尾,剩下的为待排序序列,
     * 重复上述步骤,直至完成。
     */
    public static int[] selectSort(int[] nums){
        int num = 0;
        for (int i = 0; i < nums.length -1; i++) {
            int index = i;
            for (int j = i + 1; j < nums.length; j++) {//选择合适的元素,直接放到数组的第i位
                if(nums[index] > nums[j]){
                    index = j;
                }
                if(index != i){
                    num = nums[i];
                    nums[i] = nums[index];
                    nums[index] = num;
                }
            }
        }
        return nums;
    }
    /*3、选择排序:堆排序
     * 堆排序是一种树形结构选择排序
     * 堆排序需要两个过程,建立堆,堆顶与堆最后一个元素交换位置。所以堆排序有两个函数组成:
     * 建堆的***函数,反复调用***函数实现排序的函数
     * 基本思路:
     * 将序列建成一个堆,根据升序降序选择大顶堆或小顶堆
     * 将堆顶元素与末尾元素交换,将最大元素沉到数组末端
     * 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
     */
    public static int[] HeapSorts(int[] nums){
        //建立大顶
        for (int i = nums.length/2 - 1; i >= 0; i--) {
            //从第一个非叶子节点从下至上,从右至左调整结构
            suitHeap(nums, i, nums.length);
        }
        //调整堆结构,交换堆顶元素与 末尾元素
        for (int j = nums.length - 1; j > 0; j--) {
            exchangeNum(nums, 0, j);//交换堆顶元素与末尾元素
            suitHeap(nums, 0, j);
        }
        return nums;
    }

    private static void exchangeNum(int[] nums, int i, int i2) {
        int index = nums[i];
        nums[i] = nums[i2];
        nums[i2] = index;
    }
    private static void suitHeap(int[] nums, int i, int length) {
        int index = nums[i];//取出当前元素
        for (int j = i*2 + 1; j < length; j = j*2+1) {
            //从i节点的左节点开始,即2i+1处
            if(j+1 < length && nums[j] < nums[j+1]){
                //如果,左子节点小于右子节点,j指向右子节点
                j++;
            }
            if(nums[j] > index){
                //如果子节点大于父节点,将子节点赋值给父节点
                nums[i] = nums[j];
                i = j;
            }else{
                break;
            }
        }
        nums[i] = index;//将index值放到最终位置
    }

    /*4、java Arrays排序
     * 该方法是Arrays类的静态方法,在需要对数组进行排序时,非常好用
     */
    public static int[] ArraySort(int[] nums){
        Arrays.sort(nums);
        return nums;
    }
    /*5、插入排序:直接插入排序
     * 将数组分为两部分,将后部分元素逐一与前部分元素比较
     * 然后依据比较结果进行移动元素
     */
    public static int[] insertSort(int[] nums){
        //从头部第一个当做已经排序好的,把后面的一个一个的插入到已经排序好的列表中
        for (int i = 1; i < nums.length; i++) {
            int j;
            int index = nums[i];//index为待插入的元素
            for (j = i; j > 0 && index < nums[j - 1]; j--) {
                nums[j] = nums[j -1];
            }
            nums[j] = index;
        }
        return nums;
    }

    /*6、插入排序:希尔排序
     * 建堆,对顶与堆的最后一个元素进行排序
     * 希尔排序是插入排序的一种,先取一个小于n的整数作为第一个增量,把文件的全部记录分组。
     * 所有距离为d1的倍数的记录放在同一个组中,先在各组内进行直接插入排序。实际上是一种分组插入排序的方法。
     */
    public static int[] shellSrot(int[] nums){
        int index = nums.length/2;
        while (index >= 1) {
            for (int i = index; i < nums.length; i++) {
                if(nums[i] < nums[i - index]){
                    int j;
                    int x = nums[i];//当前待插入的元素
                    nums[i] = nums[i - index];
                    for (j = i - index; j >= 0 && x < nums[j]; j = j-index) {
                        nums[j + index] = nums[j];
                    }
                    nums[j + index] = x;//插入元素
                }
            }
            index = index/2;
        }
        return nums;
    }
    /*7、交换排序:快速排序
     * 基本思想:
     * A选择一个基准元素,通常选择第一个元素或最后一个元素
     * B通过一趟排序将待排序的记录分割成独立的两部分:记录均值比基准元素值小,元素值比基准元素值大
     * C此时基准元素在排序好的正确位置
     * D分别对这两部分记录,用同样的方法继续进行排序,直到整个序列有序。
     */
    public static int[] quickSort(int[] nums, int...is){
        int low,hight;
        if(is.length == 0){
            low = 0;
            hight = nums.length - 1;
        }else{
            low = is[0];
            hight = is[1];
        }
        if(low < hight){//判断,让递归函数退出,否则无限循环
            int middle = getMiddle(nums, low, hight);
            quickSort(nums, 0, middle - 1);//基准元素小
            quickSort(nums, middle + 1, hight);//比基准元素大
        }
        return nums;
    }
    //获取,均值
    private static int getMiddle(int[] nums, int low, int hight) {
        int index = nums[low];//选择基准元素
        while (low < hight) {
            //从hight开始,找出比基准小的,与low换位置
            while (low < hight && nums[hight] >= index) {
                hight--;
            }
            nums[low] = nums[hight];
            //从low开始找比基准大,放到之前hight空出来的位置上
            while (low < hight && nums[low] <= index) {
                low++;
            }
            nums[hight] = nums[low];
        }
        //此时low = hight是基准元素的位置,也是空缺的位置
        nums[low] = index;
        return low;
    }
    /*
     * 8、归并排序
     * 基本思想:
     * 归并排序是,将两个或两个以上有序表合并成一个新的有序表。
     * 即把待排序的序列分为若干个子序列,每个子序列是有序的,然后再把有序序列合并成整体有序序列
     */
    public static int[] mergeSort(int[] nums){
        sortmerge(nums, 0, nums.length - 1);
        return nums;
    }
    private static void sortmerge(int[] nums, int i, int j) {
        if(i >= j){
            return;
        }
        //找出中间索引
        int middle = (i + j)/2;
        //对左边数组进行递归
        sortmerge(nums, i, middle);
        //对右边数组进行递归
        sortmerge(nums, middle + 1, j);
        //合并数组
        merge(nums, i, middle, j);
    }
    private static void merge(int[] nums, int i, int middle, int j) {
        //创建临时中间量数组
        int[] tmpArr = new int[nums.length];
        //右数组第一个元素索引
        int mid = middle + 1;
        //记录临时数组索引
        int second = i;
        //缓存左侧数组第一个元素的索引
        int tmp = i;
        while (i <= middle && mid <= j) {
            //从两个数组中取出最小的放到临时数组中
            if(nums[i] <= nums[mid]){
                tmpArr[second++] = nums[i++];
            }else{
                tmpArr[second++] = nums[mid++];
            }
        }
        //剩余部分依次放入临时数组
        while (mid <= j) {
            tmpArr[second++] = nums[mid++];
        }
        while (i <= middle) {
            tmpArr[second++] = nums[i++];
        }
        //将临时数组中内容,拷贝到原数组中
        while (tmp <= j) {
            nums[tmp] = tmpArr[tmp++];
        }
    }
    /*9、基数排序(桶)
     * 将数组中的所有元素按照元素中最长的位数进行统一格式,不足位数的前面补充0
     * 然后,一次比较每一位的数字,得到最终的比较结果
     * 基本思想:
     * A遍历找出最大的数(确定最大的数是几)
     * B开辟临时数组,用于中间过程的计算
     * C用一个count数组统计原数组中某一位(从低位向高位统计)相同的数据出现的次数;
     * D用一个start数组计算原数组中某一位(从最低位向最高位计算)相同数据出现的位置;
     * E将桶中数据从小到大用临时数组收集起来;
     * F重复(3)(4)(5)直到所有位都被统计并计算过,用临时数组收集起来;
     * G将临时数组拷回到原数组中;
     */
    public static int[] radixSort(int[] nums) {
                int exp;    // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
                int max = getMax(nums);    // 数组a中的最大值
                // 从个位开始,对数组a按"指数"进行排序
                for (exp = 1; max/exp > 0; exp *= 10) {
                    countSort(nums, exp);
                }
                return nums;
        }
    //获取数组中最大的元素
    private static int getMax(int[] nums) {
        int i, max;
            max = nums[0];
            for (i = 1; i < nums.length; i++)
                    if (nums[i] > max)
                            max = nums[i];
            return max;
    }
    /*
     * 对数组按照"某个位数"进行排序(桶排序)
     * 参数说明:
     * exp -- 指数。对数组a按照该指数进行排序。
     * (01) 当exp=1表示按照"个位"对数组a进行排序
     * (02) 当exp=10表示按照"十位"对数组a进行排序
     * (03) 当exp=100表示按照"百位"对数组a进行排序
     */
    private static void countSort(int[] a, int exp) {
        int[] output = new int[a.length]; // 存储"被排序数据"的临时数组
        int[] buckets = new int[10];
        // 将数据出现的次数存储在buckets[]中
        for (int i = 0; i < a.length; i++)
            buckets[(a[i] / exp) % 10]++;
        // 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
        for (int i = 1; i < 10; i++)
            buckets[i] += buckets[i - 1];
        // 将数据存储到临时数组output[]中
        for (int i = a.length - 1; i >= 0; i--) {
            output[buckets[(a[i] / exp) % 10] - 1] = a[i];
            buckets[(a[i] / exp) % 10]--;
        }
        // 将排序好的数据赋值给a[]
        for (int i = 0; i < a.length; i++) {
            a[i] = output[i];
        }
        // 用完清空
        output = null;
        buckets = null;
    }

    public static void main(String[] args) {
        int[] nums = {1221,232,1242,24,12,4,1,43,14,4,21,4,14,4,1,41,2};
        //nums = bubbleSort(nums);冒泡
        //nums = selectSort(nums);选择
        //nums = ArraySort(nums);数组
        //nums = insertSort(nums);插入
        //nums = shellSrot(nums);希尔
        //nums = HeapSorts(nums);选择排序:堆排序
        //nums = quickSort(nums);快速
        //nums = mergeSort(nums);归并
        nums = radixSort(nums);
        for (int k = 0; k < nums.length; k++) {
            System.err.println("排序之后的"+nums[k]);
        }
    }
}

以上是关于简单算法之9种排序的主要内容,如果未能解决你的问题,请参考以下文章

交换排序算法之快速排序

排序系列 之 简单选择排序及其改进算法 —— Java实现

经典算法之桶排序

排序算法之希尔排序

[Java数据结构与算法]简单排序之插入排序

排序算法之希尔排序