ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

八大排序算法

2022-01-30 10:31:39  阅读:158  来源: 互联网

标签:10 arr 12 八大 int 13 算法 15 排序


所谓排序,就是将一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。常用的排序算法大致有8种:插入排序(直接插入排序、希尔排序)、选择排序(简单选择排序、堆排序)、交换排序(冒泡排序、快速排序)、归并排序、基数排序。

一、直接插入排序

算法思想:把要排序的数组分为了两个部分,一部分是排序好的元素,另一部分是待插入的元素,如果选择的元素比已排序好的元素小,则交换,直到全部元素都比较过为止。

排序过程:

代码实现:

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    insertSort(arr);
}

public static void insertSort(int[] arr) {
    //第一个元素 默认有序
    for (int i = 1; i < arr.length; i++) {
        //从第二个元素开始
        int temp = arr[i];
        for (int j = i; j >= 0; j--) {
            //若当前元素不是第一个 并且 当前元素大于temp,则向后移动
            if (j > 0 && arr[j - 1] > temp) {
                arr[j] = arr[j - 1];
            } else {
                arr[j] = temp;
                break;
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

执行结果:

[5, 10, 12, 13, 7, 4, 2, 15, 9]
[5, 10, 12, 13, 7, 4, 2, 15, 9]
[5, 10, 12, 13, 7, 4, 2, 15, 9]
[5, 7, 10, 12, 13, 4, 2, 15, 9]
[4, 5, 7, 10, 12, 13, 2, 15, 9]  
[2, 4, 5, 7, 10, 12, 13, 15, 9]
[2, 4, 5, 7, 10, 12, 13, 15, 9]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度:最好情况O(n),最坏情况O(n²),平均复杂度O(n²)

空间复杂度:只有temp一个空间,O(1)

二、希尔排序

算法思想:先将整个待排序的序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对所有元素进行直接插入排序。

排序过程:

代码实现:​​​​​​​

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    shellSort(arr);
}

public static void shellSort(int[] arr) {
    //找到步长
    int step = arr.length / 2;
    //步长大于0 当步长等于1时,相当于一次直接插入排序
    while (step > 0) {
        //每个序列都从第二个开始 现在是对每个序列分别进行直接插入排序
        for (int i = step; i < arr.length; i++) {
            //若第i个元素大于i-step元素,直接插入。小于的话,移动有序表后插入 这个if可以省略
            if (arr[i] < arr[i - step]) {
                //上一个元素的位置
                int j = i - step;
                //临时存储当前元素
                int temp = arr[i];
                //元素后移
                arr[i] = arr[i - step];
                //找到元素存储的位置j + step
                while (j >= 0 && arr[j] > temp) {
                    arr[j + step] = arr[j];
                    j = j - step;
                }
                arr[j + step] = temp;
            }
        }
        step = step / 2;
        System.out.println(Arrays.toString(arr));
    }
}

执行结果:​​​​​​​

[7, 4, 2, 13, 9, 5, 12, 15, 10]
[2, 4, 7, 5, 9, 13, 10, 15, 12]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度

最好情况O(nlogn),最坏情况O(n²),平均复杂度O(n^1.5)

空间复杂度:只有temp一个空间,O(1)

三、简单选择排序

算法思想:在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。

排序过程:

代码实现:​​​​​​​

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    selectSort(arr);
}

public static void selectSort(int[] arr) {
    //每次从剩下的元素中选择最小值放到第一个位置
    for (int i = 0; i < arr.length - 1; i++) {
        //记录每一趟最小值坐标
        int min = i;
        //寻找每一趟的最小值 先找到坐标 最后再进行交换 减少交换次数
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[min]) {
                min = j;
            }
        }
        //元素交换
        if (min != i) {
            int temp = arr[min];
            arr[min] = arr[i];
            arr[i] = temp;
        }
        System.out.println(Arrays.toString(arr));
    }
}

执行结果:​​​​​​​

[2, 5, 12, 13, 7, 4, 10, 15, 9]
[2, 4, 12, 13, 7, 5, 10, 15, 9]
[2, 4, 5, 13, 7, 12, 10, 15, 9]
[2, 4, 5, 7, 13, 12, 10, 15, 9]
[2, 4, 5, 7, 9, 12, 10, 15, 13]
[2, 4, 5, 7, 9, 10, 12, 15, 13]
[2, 4, 5, 7, 9, 10, 12, 15, 13]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度最好情况O(n²),最坏情况O(n²),平均复杂度O(n²)

空间复杂度:只有temp一个空间,O(1)

Tips:选择排序可以进行改进,每次不光找到最大值,还可以找到最小值放到最后,从而减少一半的趟数。

四、堆排序

堆的定义如下:n个元素的序列{k1,k2,···,kn},当且仅当满足下关系时,称之为堆:

ki <= k(2i) 或 ki >= k(2i)

ki <= k(2i+1) 或 ki >= k(2i+1)

按照堆的特点可以把堆分为大顶堆小顶堆

大顶堆:每个结点的值都大于或等于其左右孩子结点的值

小顶堆:每个结点的值都小于或等于其左右孩子结点的值

算法思想:

①创建最小堆:将堆所有数据重新排序

②最大堆调整:将堆的末端子节点作调整,使得子节点永远大于父节点

③堆排序:移除位在第一个数据的根节点,并做最小堆调整的递归运算

排序过程:

代码实现:​​​​​​​

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    heapSort(arr);
}

public static void heapSort(int[] arr) {
    //初始堆
    buildHeap(arr, arr.length);
    //从最后一个元素开始对序列进行调整
    System.out.println("堆排序开始");
    for (int i = arr.length - 1; i > 0; i--) {
        //交换堆顶元素arr[0]和堆中最后一个元素
        int temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;
        //每次交换堆顶元素和堆中最后一个元素之后,都要对堆顶进行调整
        adjustHeap(arr, 0, i);
    }
    System.out.println("堆排序结束");
}

/**
 * 构建堆
 *
 * @param arr 数组
 * @param len 长度
 */
private static void buildHeap(int[] arr, int len) {
    System.out.println("构建堆开始");
    for (int i = (len - 1) / 2; i >= 0; i--) {
        adjustHeap(arr, i, len);
    }
    System.out.println("构建堆结束");
}

执行结果:​​​​​​​

构建堆开始
[10, 5, 12, 13, 7, 4, 2, 15, 9]
[10, 5, 12, 9, 7, 4, 2, 15, 13]
[10, 5, 2, 9, 7, 4, 12, 15, 13]
[10, 5, 2, 9, 7, 4, 12, 15, 13]
[2, 5, 4, 9, 7, 10, 12, 15, 13]
构建堆结束
堆排序开始
[4, 5, 10, 9, 7, 13, 12, 15, 2]
[5, 7, 10, 9, 15, 13, 12, 4, 2]
[7, 9, 10, 12, 15, 13, 5, 4, 2]
[9, 12, 10, 13, 15, 7, 5, 4, 2]
[10, 12, 15, 13, 9, 7, 5, 4, 2]
[12, 13, 15, 10, 9, 7, 5, 4, 2]
[13, 15, 12, 10, 9, 7, 5, 4, 2]
[15, 13, 12, 10, 9, 7, 5, 4, 2]
堆排序结束

Tips:最小堆输出的是倒序,正序排列可构建最大堆

时间复杂度

最好情况O(nlogn),最坏情况O(nlogn),平均复杂度O(nlogn)

空间复杂度:只有temp一个空间,O(1)

五、冒泡排序

算法思想:在要排序的序列中,对当前还未排好序的全部元素,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒,就好像水泡上浮一样,如果他们的顺序错误就把他们交换过来。

排序过程:

代码实现:

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    bubbleSort(arr);
}
​
public static void bubbleSort(int[] arr) {
    //外层循环控制趟数
    for (int i = arr.length - 1; i > 0; i--) {
        //节点比较 只比较到第i个元素即可
        for (int j = 0; j < i; j++) {
            //交换元素
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

执行结果:

[5, 10, 12, 7, 4, 2, 13, 9, 15]
[5, 10, 7, 4, 2, 12, 9, 13, 15]
[5, 7, 4, 2, 10, 9, 12, 13, 15]
[5, 4, 2, 7, 9, 10, 12, 13, 15]
[4, 2, 5, 7, 9, 10, 12, 13, 15]
[2, 4, 5, 7, 9, 10, 12, 13, 15]
[2, 4, 5, 7, 9, 10, 12, 13, 15]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度最好情况O(n),最坏情况O(n²),平均复杂度O(n²)

空间复杂度:只有temp一个空间,O(1)

Tips:我们可以看到最后几趟都是没有必要的,因此可以在没有元素交换时中止排序,从而减少循环比较时间。

六、快速排序

算法思想:选择一个基准,通过一趟排序将待排元素分为两个部分,其中一部分比基准值都大,另一部分比基准值都小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。(分而治之的思想)

排序过程:

此时的基准10找到了自己的位置。然后以此类推,递归的排序左序列和右序列即可使整个序列有序。

代码实现:

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    quickSort(arr, 0, arr.length - 1);
}
​
public static void quickSort(int[] arr, int low, int high) {
    //递归的中止条件
    if (arr.length <= 0) {
        return;
    }
    //递归的中止条件
    if (low >= high) {
        return;
    }
    int left = low;
    int right = high;
    //基准 以序列的第一个元素为基准
    int temp = arr[left];
    while (left < right) {
        //从右侧找到比基准小的
        while (left < right && arr[right] >= temp) {
            right--;
        }
        arr[left] = arr[right];
        //从左侧找到比基准大的
        while (left < right && arr[left] <= temp) {
            left++;
        }
        arr[right] = arr[left];
    }
    //放入基准值
    arr[left] = temp;
    System.out.println(Arrays.toString(arr));
    //递归排序左序列
    quickSort(arr, low, left - 1);
    //递归排序右序列
    quickSort(arr, left + 1, high);
}

执行结果:

[9, 5, 2, 4, 7, 10, 13, 15, 12]
[7, 5, 2, 4, 9, 10, 13, 15, 12]
[4, 5, 2, 7, 9, 10, 13, 15, 12]
[2, 4, 5, 7, 9, 10, 13, 15, 12]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度最好情况O(nlogn),最坏情况O(n²),平均复杂度O(nlogn)

空间复杂度:最好情况O(logn),最差情况O(n)

七、归并排序

算法思想:归并排序是将两个(或两个以上)有序序列合并成一个新的有序序列,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

排序过程:

Tips:图中只是为了方便做了向下移动,实际上没有重新复制一个一模一样的数组。

代码实现:

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    mergeSort(arr);
}
​
public static int[] mergeSort(int[] arr) {
    if (arr.length == 1) {
        return arr;
    }
    int mid = arr.length / 2;
    int[] left = Arrays.copyOfRange(arr, 0, mid);
    int[] right = Arrays.copyOfRange(arr, mid, arr.length);
    System.out.println("合并:" + Arrays.toString(left) + "\t" + Arrays.toString(right));
    return merge(mergeSort(left), mergeSort(right));
}
​
/**
 * 合并两个有序数组
 *
 * @param left  数组1
 * @param right 数组2
 * @return 新数组
 */
private static int[] merge(int[] left, int[] right) {
    //合并后的数组大小
    int[] mergeArr = new int[left.length + right.length];
    //i是left坐标,j是right坐标,k是新数组坐标
    int i = 0, j = 0, k = 0;
    //下边是合并两个有序数组  此时传进来的数组left和right一定是有序的
    while (i < left.length && j < right.length) {
        mergeArr[k++] = left[i] <= right[j] ? left[i++] : right[j++];
    }
    //合并left数组剩下的元素
    while (i < left.length) {
        mergeArr[k++] = left[i++];
    }
    //合并right数组剩下的元素
    while (j < right.length) {
        mergeArr[k++] = right[j++];
    }
    System.out.println(Arrays.toString(mergeArr));
    return mergeArr;
}

执行结果:

合并:[10, 5, 12, 13]  [7, 4, 2, 15, 9]
合并:[10, 5]  [12, 13]
合并:[10]  [5]
[5, 10]
合并:[12]  [13]
[12, 13]
[5, 10, 12, 13]
合并:[7, 4]  [2, 15, 9]
合并:[7]  [4]
[4, 7]
合并:[2]  [15, 9]
合并:[15]  [9]
[9, 15]
[2, 9, 15]
[2, 4, 7, 9, 15]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度最好情况O(nlogn),最坏情况O(nlogn),平均复杂度O(nlogn)

空间复杂度:O(n)

八、基数排序

算法思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,序列就变成一个有序序列。

排序过程:

代码实现:

public static void main(String[] args) {
    int[] arr = new int[]{10, 5, 12, 13, 7, 4, 2, 15, 9};
    radixSort(arr);
}
​
public static void radixSort(int[] arr) {
    if (arr.length == 1) {
        return;
    }
    //找到数组中的最大值
    int max = 0;
    for (int item : arr) {
        if (max < item) {
            max = item;
        }
    }
    //获取最大位数
    int maxDigit = 1;
    while (max / 10 > 0) {
        maxDigit++;
        max = max / 10;
    }
    //申请桶空间
    int[][] buckets = new int[10][arr.length];
    int divisor = 10;
    for (int i = 0; i < maxDigit; i++) {
        //只有10个数字 key是每个位置的值 value存放该值的个数
        int[] bucketLength = new int[10];
        //分配:将所有元素分配到桶中
        for (int value : arr) {
            int whereBucket = (value % divisor) / (divisor / 10);
            buckets[whereBucket][bucketLength[whereBucket]] = value;
            //该位的个数
            bucketLength[whereBucket]++;
        }
        //收集:将不同桶里数据拿出来
        int k = 0;
        for (int j = 0; j < buckets.length; j++) {
            for (int l = 0; l < bucketLength[j]; l++) {
                arr[k++] = buckets[j][l];
            }
        }
        System.out.println(Arrays.toString(arr));
        divisor = divisor * 10;
    }
}

执行结果:

[10, 12, 2, 13, 4, 5, 15, 7, 9]
[2, 4, 5, 7, 9, 10, 12, 13, 15]

时间复杂度d:位数,r:基数,n:序列个数

最好情况O(d*(n+r)),最坏情况O(d*(n+r)),平均复杂度O(d*(n+r))

空间复杂度:O(n+r)

 今天的分享就到此结束啦,喜欢的小伙伴记得点赞呦。

关注公众号JavaGrowUp,下期不迷路,获取更多精彩内容。

标签:10,arr,12,八大,int,13,算法,15,排序
来源: https://blog.csdn.net/jianghui009/article/details/122750650

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有