常见排序算法

程序员内功:八大排序算法

交换排序

一、冒泡排序

冒泡排序是排序算法中较为简单的一种,英文称为Bubble Sort。它遍历所有的数据,每次对相邻元素进行两两比较,如果顺序和预先规定的顺序不一致,则进行位置交换;这样一次遍历会将最大或最小的数据上浮到顶端,之后再重复同样的操作,直到所有的数据有序。

有n个数据,需要n - 1趟比较,

时间复杂度 O(n2),空间复杂度O(1)

以升序冒泡排序为例,冒泡排序就是要**每趟排序过程中通过两两比较相邻元素,将小的数字放到前面,大的数字放在后面。**代码如下:

package com.wang;

/**
 * @Author Mickey
 * @PackageName DailyTest
 * @Package com.wang
 * @Date 2022/5/12 15:23
 * @Version 1.0
 */
public class BubbleSort {
    public  static int[] bubbleSort(int[] nums){
        int n = nums.length;
        for(int i = 1;i < n;i++){
            boolean flag = true;
            for(int j = 1;j < n;j++){
                if(nums[j] < nums[j - 1]){
                    int temp = nums[j - 1];
                    nums[j - 1] = nums[j];
                    nums[j] = temp;
                    flag = false;
                }
            }
            //如果为true,则说明排序已经提前完成
            if(flag){
                break;
            }
        }
        return nums;
    }
    public static void display(int [] array){
        for(int i = 0 ; i < array.length ; i++){
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] nums = new int[]{4,2,8,9,5,7,6,3,1};
        System.out.println("未排序数组顺序为:");
        display(nums);
        System.out.println("-----------------------");
        nums = bubbleSort(nums);
        System.out.println("-----------------------");
        System.out.println("经过冒泡排序后的数组顺序为:");
        display(nums);

    }
}


性能:

排序(1):冒泡排序

算法稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

冒泡排序就是把小的元素往前调或者把大的元素往后调。是相邻的两个元素的比较,交换也发生在这两个元素之间。所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法

二、快速排序

快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数。

然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

package com.wang;

/**
 * @Author Mickey
 * @PackageName DailyTest
 * @Package com.wang
 * @Date 2022/5/12 15:39
 * @Version 1.0
 */
public class QuickSort {
    public static void quickSort(int[] arr,int low,int high){
        if(low>high){
            return;
        }
        int i = low;int j = high;
        //base就是基准位 
        int base = arr[low];
        while (i<j) {
            //先看右边,依次往左递减
            while (base <= arr[j] && i < j) {
                j--;
            }
            //再看左边,依次往右递增
            while (base >= arr[i] && i < j) {
                i++;
            }
            //如果满足条件则交换
            if (i < j) {
                int temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
            }
        }
        //最后将基准位与i和j相等位置的数字交换
        arr[low] = arr[i];
        arr[i] = base;
        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }


    public static void main(String[] args){
        int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
        quickSort(arr, 0, arr.length-1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}


性能:排序(4):快速排序

插入排序

三、希尔排序

​ 希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。希尔排序又称缩小增量排序,因 DL.Shell 于 1959 年提出而得名。它通过比较相距一定间隔的元素来进行,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。
​ 希尔排序时间复杂度是 O(n^(1.3-2)),空间复杂度为常数阶 O(1)。希尔排序没有时间复杂度为 O(n(logn)) 的快速排序算法快 ,因此对中等大小规模表现良好,但对规模非常大的数据排序不是最优选择,总之比一般 O(n^2 ) 复杂度的算法快得多。

三、过程图示
希尔排序目的为了加快速度改进了插入排序,交换不相邻的元素对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

在此我们选择增量 gap=length/2,缩小增量以 gap = gap/2 的方式,用序列 {n/2,(n/2)/2…1} 来表示。

(1)初始增量第一趟 gap = length/2 = 4

06f11f7173d53ac9ad79fab22d4c5c6a.png

(2)第二趟,增量缩小为 2

da097ea48044cc42655fe9d512029bc3.png

(3)第三趟,增量缩小为 1,得到最终排序结果

f9f20ca7337d5786d1049a1ef795a82d.png

package com.wang;

import java.util.Arrays;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 20:21
 * @Version 1.0
 */
public class ShellSort {
    public static void shellSort1(int[] array){
        int insertValue = 0;//保存待插入的值
        int j = 0;//记录要插入的位置下标
        int count = 0;//记录比较轮次
        for (int gap = array.length/2;gap >0; gap/=2) {//每次分组的步长(增量),每次增量除以2
            for (int i = gap; i <array.length ; i++) {
                j = i;
                insertValue = array[j];//保存待插入的值
                if (array[j]<array[j-gap]){//要插入的值小于前面有序子序列的尾元素就进行元素移动
                    while (j-gap>=0&&insertValue<array[j-gap]){
                        array[j] = array[j-gap];
                        j-=gap;
                    }
                    array[j] = insertValue;
                }
            }
            System.out.println("第"+(++count)+"轮希尔排序结果:"+ Arrays.toString(array));
        }

    }

    public static void main(String[] args) {
        int[] array = {8,9,1,7,2,3,5,4,6,0};
        ShellSort.shellSort1(array);
    }
}

四、直接插入排序

直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。
在这里插入图片描述

package com.wang;

import java.util.Arrays;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 18:15
 * @Version 1.0
 */
public class InsertSort {
    public static void insertSort(int[] nums){
        int temp,j;
        for(int i = 0;i < nums.length;i++){
            //记录要插入的数据
            temp = nums[i];
            //从右向左在有序区[0,i-1]中找nums[i]插入的位置
            j = i - 1;
            while(j >= 0 && temp < nums[j]){
                //将大于nums[i]的元素后移
                nums[j + 1] = nums[j];
                j--;
            }
            //在j + 1出插入nums[i]
            nums[j + 1] = temp;
        }
    }

    public static void main(String[] args) {
        int[] nums = {2,1,6,4,7,9,4,5,8};
        System.out.println("排序前:");
        Arrays.stream(nums).forEach(System.out::println);
        insertSort(nums);
        System.out.println("排序后:");
        Arrays.stream(nums).forEach(System.out::println);
    }
}

选择排序

选择排序:每趟从待排序的记录中选出关键字最小的记录,顺序放在已排序的记录序列末尾,直到全部排序结束为止。

五、简单选择排序

选择排序的基本思想描述为:每一趟在n-i+1(i=1,2,…,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。具体来说,假设长度为n的数组arr,要按照从小到大排序,那么先从n个数字中找到最小值min1,如果最小值min1的位置不在数组的最左端(也就是min1不等于arr[0]),则将最小值min1和arr[0]交换,接着在剩下的n-1个数字中找到最小值min2,如果最小值min2不等于arr[1],则交换这两个数字,依次类推,直到数组arr有序排列。算法的时间复杂度为O(n^2)。

package com.wang;

import java.util.Arrays;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 17:10
 * @Version 1.0
 */
public class SelectSort {
    public static int[] selectSort(int[] nums){
        int index = 0;
        for(int i = 0;i < nums.length;i++){
            index = i;
            for(int j = i + 1;j < nums.length;j++){
                if(nums[j] < nums[index]){
                    index = j;
                }
            }
            if(index != i){
                int temp = nums[i];
                nums[i] = nums[index];
                nums[index] = temp;
            }

        }
        return nums;
    }

    public static void main(String[] args) {
        int[] nums = new int[]{1,3,2,5,6,8,6};
        int[] res = selectSort(nums);
        Arrays.stream(res).forEach(System.out::println);
    }
}

六、堆排序

是一棵顺序存储完全二叉树

  • 其中每个结点的关键字都不大于其孩子结点的关键字,这样的堆称为小根堆。在堆排序算法中用于升序排列;
  • 其中每个结点的关键字都不小于其孩子结点的关键字,这样的堆称为大****根堆。在堆排序算法中用于降序排列;

举例来说,对于n个元素的序列{R0, R1, … , Rn}当且仅当满足下列关系之一时,称之为堆:

  • Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)
  • Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)

其中i=1,2,…,n/2向下取整;

用到完全二叉树的性质如下:

  • (1)最后一个非叶子节点的位置为:n / 2 - 1,n 为完全二叉树的节点总数
  • (2)从 0 开始计数,第 i 个节点的左孩子的位置为:2 * n + 1,右孩子位置为:2 * n + 2

堆排序算法的基本思路:

  • 将无序序列建成一个堆,根据升降序需求选择大顶堆和小顶堆。
  • 将堆顶元素与末尾元素交换,将最大元素沉到数组末端。
  • 重新调整,使其重新满足堆定义,然后继续交换堆顶元素和当前末尾元素,反复执行调整和交换,直至整个序列有序。
package com.wang;

import java.util.Arrays;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 20:39
 * @Version 1.0
 */
public class HeapSort {
    public static void heapSort(int[] array)
    {
        //从倒数第一个非叶子节点开始
        for (int i = array.length/2 - 1; i>=0; i--)
        {
            //从第一天非叶子节点从下至上,从左至右调整结构
            adjustHeap(array,i, array.length);
        }

        //将堆顶元素与末尾元素交换 将最大元素沉到数组末尾 + 重新调整堆结构
        for (int i = array.length - 1; i > 0 ; i--)
        {
            //交换堆顶元素和末尾元素
            swap(array,0,i);
            //交换后的末尾元素忽略(j--) 不再参与堆结构的调整
            //重新调整堆结构
            adjustHeap(array,0,i);
        }

    }

    private static void swap(int[] array, int start, int end)
    {
        int temp = array[start];
        array[start] = array[end];
        array[end] = temp;
    }

    public static void adjustHeap(int[] array,int index,int length)
    {
        //取出当前元素
        int temp = array[index];
        //i节点是index节点的左子节点
        for (int i = 2 * index + 1; i < length; i = 2 * i + 1)
        {
            //表明左子节点小于右子节点
            if (i+1 < length && array[i] < array[i+1])
            {
                //将指针移至较大节点
                i++;
            }

            //如果子节点大于父节点
            if (array[i] > temp)
            {
                //将较大值赋给当前节点
                array[index] = array[i];
                //指针移向子节点
                index = i;
            }
            else
            {
                break;
            }
        }
        //循环结束,已经将最大值放在了堆顶
        //将temp值放到最终的位置
        array[index] = temp;

    }

    public static void main(String[] args)
    {
        //升序
        int[] array = {4,6,8,78,13,19,1,5,9,};
        System.out.println("排序前=>"+ Arrays.toString(array));
        heapSort(array);
        System.out.println("排序后=>"+ Arrays.toString(array));
    }

}

七、归并排序

基本思想:假设初始序列含有n个记录,则可看成时n个有序的子序列,每个子序列的长度为1,然后两两并归,得到n/2个长度为2或1的有序子序列;如此重复,直至得到一个长度为n的有序序列为止。这种排序方法称为2-路归并排序。

先从上到下分解,在从下到上排序

algsortmerge2.jpg

algsortmerge3.jpg

package com.wang;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 17:29
 * @Version 1.0
 */

import java.util.Arrays;

public class MergeSort{
    public static int[] sort(int[] nums,int low,int high){

        if(low < high){
            int mid = low + (high - low) / 2;
            // 左边归并排序
            sort(nums,low,mid);
            // 右边归并排序
            sort(nums,mid + 1,high);
            //合并两个有序数组
            merge(nums,low,mid,high);
        }
        return nums;
    }

    private static void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low,j = mid + 1,index = 0;
        while (i <= mid && j <= high){
            // 对比大小,调整顺序
            if(nums[i] < nums[j]){
                temp[index++] = nums[i++];
            }else{
                temp[index++] = nums[j++];
            }
        }
        // 右边剩余元素填充进temp中(因为前面已经归并,剩余的元素必会小于右边剩余的元素)
        while(i <= mid){
            temp[index++] = nums[i++];
        }
        // 右边剩余元素填充进temp中(因为前面已经归并,剩余的元素必会大于于左边剩余的元素)
        while(j <= high){
            temp[index++] = nums[j++];
        }
        // 调整数组顺序
        for(int k = 0;k < temp.length;k++){
            nums[k + low] = temp[k];
        }
    }

    public static void main(String[] args) {
        int[] a = {1,3,2,5,6,8,6};
        sort(a, 0, a.length -1);
        Arrays.stream(a).forEach(System.out::println);
    }
}

八、桶排序

桶排序是计数排序的升级版。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序。桶排序利用了函数的映射关系把数据分配到桶里,高效与否的关键就在于这个映射函数的确定。

算法思路

根据待排序集合中的数据,确定映射规则和桶的数量;
遍历待排序集合,将每一个元素根据映射规则,移动到对应的桶中;
对每一个桶中元素进行排序。
*依次输出每个桶中的数据,得到整个有序的集合。
步骤:
1.找出待排序数组中的最大值max、最小值min
2.桶的数量为(max-min)/bucketSize+1 ,若没有指定桶的数量为(max-min)/arr.length+1
3.遍历数组 arr,计算每个元素 arr[i] 放的桶存放桶的下标=(arr[i]-min)/arr.lengh
4.每个桶各自排序
5.遍历桶数组,把排序好的元素放进输出数组

package com.wang;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author Mickey
 * @PackageName leetcodeTest
 * @Package com.wang
 * @Date 2022/5/15 19:57
 * @Version 1.0
 */
public class BucketSort {
    public static final int[] ARRAY = {35, 23, 48, 9, 16, 24, 5, 11, 32, 17};
    /*  bucketSize 作为每个桶所能放置多少个不同数值,即数值的类型
     *                   例如当BucketSize==5时,该桶可以存放{1,2,3,4,5}这几种数字,
     *                   但是容量不限,即可以存放100个3
     */
    public static List<Integer> sort(List<Integer> array, int bucketSize) {
        if (array == null || array.size() < 2)
            return array;
        int max = array.get(0), min = array.get(0);
        // 找到最大值最小值
        for (int i = 0; i < array.size(); i++) {
            if (array.get(i) > max)
                max = array.get(i);
            if (array.get(i) < min)
                min = array.get(i);
        }
        //获取桶的数量
        int bucketCount = (max - min) / bucketSize + 1;
        //构建桶,初始化
        List<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketCount);
        List<Integer> resultArr = new ArrayList<>();
        for (int i = 0; i < bucketCount; i++) {
            bucketArr.add(new ArrayList<>());
        }
        //将原数组的数据分配到桶中
        for (int i = 0; i < array.size(); i++) {
            //区间范围
            bucketArr.get((array.get(i) - min) / bucketSize).add(array.get(i));
        }
        for (int i = 0; i < bucketCount; i++) {
            if (bucketSize == 1) {
                for (int j = 0; j < bucketArr.get(i).size(); j++)
                    resultArr.add(bucketArr.get(i).get(j));
            } else {
                if (bucketCount == 1)
                    bucketSize--;
                //对桶中的数据再次用桶进行排序
                List<Integer> temp = sort(bucketArr.get(i), bucketSize);
                for (int j = 0; j < temp.size(); j++)
                    resultArr.add(temp.get(j));
            }
        }
        return resultArr;
    }
    public static void print(List<Integer> array) {
        for (int i : array) {
            System.out.print(i + "  ");
        }
        System.out.println("");
    }
    public static void main(String[] args) {
        print(Arrays.stream(ARRAY).boxed().collect(Collectors.toList()));
        System.out.println("============================================");
        print(sort(Arrays.stream(ARRAY).boxed().collect(Collectors.toList()), 2));
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值