十大排序(Java版本)

news2024/9/22 21:29:22

排序分为比较排序和非比较排序两种,常见的排序为比较排序,共有七类:直接插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序以及归并排序。另有三种非基于比较类的排序:计数排序、基数排序和桶排序


基于比较的排序

直接插入排序

直接插入排序指的是按照顺序插入已排好的序列。就好比扑克牌,当摸到第二张牌时,如果牌大就放到第一张牌的右边,牌小就放在左边,每张牌这样处理,在摸完牌后,手中的扑克牌自然就有序了。

public static void insertSort(int[] array) {
    for (int i = 0; i < array.length; i++) {
        int tmp = array[i];
        int j = i - 1;
        for (; j >= 0; j--) {
            if (array[j] > tmp) {
                array[j + 1] = array[j];
            }else {
                break;
            }
        }
        array[j + 1] = tmp;
    }
}

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

当一组数据趋于有序时,直接插入排序就越快,如果一组数据是有序的(非逆序),则只需遍历一遍数据,时间复杂度为O(N)。特点是越有序越快。

希尔排序

希尔排序本质上是直接插入排序的优化,当数据较多时,直接插入排序效率很低,考虑把数据分组,局部有序之后再直接插入排序,从而提高效率。

具体实现为:两两有序成一组 -> 两组两组有序 -> 整体有序

尽量选择相距较远的两数为一组,尽可能保证大数和小数分开。例如:

可以发现两次之后数据基本有序,这时在考虑直接插入排序效率较高:

public static void shellSort(int[] array) {
    int gap = array.length;
    while (gap > 1) {
        shell(array, gap);
        gap /= 2;
    }
    shell(array, 1);
}
private static void shell(int[] array, int gap) {
    for (int i = 0; i < array.length; i++) {
        int tmp = array[i];
        int j = i - gap;
        while (j >= 0) {
            if (array[j] > tmp) {
                array[j + gap] = array[j];
            }else {
                break;
            }
            j -= gap;
        }
        array[j + gap] = tmp;
    }
}

时间复杂度:大约在O(N^1.3) ~ O(N^1.6)之间,无法得出具体值

空间复杂度:O(1)

稳定性:不稳定

选择排序

选择排序的基本思路:遍历数组找到最小的值(或最大)与下标为0的元素交换,接着从下标为1的位置开始遍历找到最小的值(或最大)与下标为1的元素进行交换,依次遍历直到有序。

public static void selectSort(int[] array){
    // write code  here
    for (int i = 0; i < array.length; i++) {
        int minIndex = i;
        for (int j = i + 1; j < array.length; j++) {
            if (array[j] < array[minIndex]) {
                minIndex = j;
            }
        }
        swap(array, i, minIndex);
    }
}

private static void swap(int[] array, int i, int j) {
    int tmp = array[i];
    array[i] = array[j];
    array[j] = tmp;
}

时间复杂度:O(N^2) ->任何情况下时间复杂度不变

空间复杂度:O(1)

稳定性:不稳定

冒泡排序

思路:相邻两元素进行比较,值较大的(或较小)往后放,一轮遍历后最大值(或最小值)移到最右边

public static void bubbleSort(int[] array){
    for (int i = 0; i < array.length; i++) {        
        for (int j = 0; j < array.length- 1 - i; j++) {
            if (array[j + 1] < array[j]) {
                swap(array, j + 1, j);
            }
        }
    }
}

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

冒泡排序与选择排序均为思路简单但效率较低的排序算法,不过冒泡排序可以进行一定程度的优化,使其在处理有序的数组时效率更高:当一轮比较结束后,没有发生交换,就代表该序列有序,可以直接结束。但即使优化,也仅仅优化了有序的情况。

public static void bubbleSort(int[] array){
    for (int i = 0; i < array.length; i++) {
        boolean flag = false;
        for (int j = 0; j < array.length- 1 - i ; j++) {
            if (array[j + 1] < array[j]) {
                swap(array, j + 1, j);
                flag = true;//代表未排完
            }
        }
        if (!flag) return;
    }
}

堆排序

假如排升序,可以建立大根堆,每次把堆顶元素同末尾元素交换,同时堆的usedSize--(代表删除),向下调整成大根堆后重复操作,直到usedSize为0,此时堆有序。

例如:将序列[21,11,4,12,22,35,58,89,33]调整为升序序列:

首先建立大根堆:

接着进行删除操作:

这样最大的“89”就有序了,依次进行交换和删除,最终序列有序。

可以自己模拟建堆并实现相关方法,或者直接使用PriorityQueue类也可行,PriorityQueue默认建小根堆,可以在建堆时添加构造器作为参数构建大根堆:

public  static void heapSortB(int[] array) {
    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((o1, o2) -> {
        return o2.compareTo(o1);
    });
    for (int elem: array) {
        priorityQueue.offer(elem);
    }
    for (int i = array.length - 1; i >= 0; i--) {
        array[i] = priorityQueue.poll();
    }
}

new PriorityQueue<>()括号中为构造器。

时间复杂度:O(NlogN)

空间复杂度:O(1)

稳定性:不稳定

快速排序

快排属于一种二叉树式的排序,首先在待排序序列中找到某一元素作为基准值,把序列中小于基准值的放到基准值的左边,大于基准值的放到基准值的右边,这样基准值的位置是有序的。再分别出列基准值左边和右边的序列,直到整个序列有序,大体思路如下:

    public static void quickSort(int[] array){
        quickSortChild(array, 0, array.length - 1);
    }
    private static void quickSortChild(int[] array, int left, int right) {
        //倘若基准值恰好是最小值,那么基准值下标为0,再去递归左边的序列会导致left = 0, right = -1
        //因此left是有可能大于right的,右边同理,该情况下直接返回。
        if (left >= right) return;
        int pivot = partition(array, left, right);
        quickSortChild(array, left, pivot - 1);
        quickSortChild(array, pivot + 1, right);
    }

接下来就只需以基准值进行划分即可,常见方法有:Hoare法、挖坑法和前后指针法。

Hoare法:

private static int partition(int[] array, int left, int right) {
    int tmp = left;//以首元素为基准值
    while (left < right) {
        while (left < right && array[right] >= array[tmp]) {
            right--;//从后往前走,直到元素值小于基准值
        }
        while (left < right && array[left] <= array[tmp]) {
            left++;//从前往后走,直到元素值大于基准值
        }
        swap(array, left, right);
    }
    //此时左右指针相遇,再与基准值交换
    swap(array, tmp, left);
    return left;
}

注意一定要先走右边,先走右边可以保证相遇时左右指针指向的值一定小于基准值,若先走左,则停下时必定停在大于基准值的位置,再交换该值与基准值必然破坏序列的有序性。

挖坑法:

private static int partition1(int[] array, int left, int right) {
    int pivot = array[left];
    while (left < right) {
        while (left < right && array[right] >= pivot) {
            right--;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivot) {
            left++;
        }
        array[right] = array[left];
    }
    array[left] = pivot;
    return left;
}

逻辑上大体相似,依然是先走右边,找到时直接将right指向的值赋给left即可(每次right走的时候,left指向的值均是无用值,因此可以直接覆盖,left走时同理),左右相遇的位置就是基准值应在的位置。

前后指针法:

private static int partition2(int[] array, int left, int right) {
    int prev = left;
    int cur = left + 1;
    while (cur <= right) {
        if (array[cur] < array[left] && array[++prev] != array[cur]) {
            swap(array, prev, cur);
        }
        cur++;
    }
    swap(array, prev, left);
    return prev;
}

当cur指向的值大于基准值时,cur向前走,当小于基准值时cur和prev都向前走,这样在cur小于基准值时,prev的下一个值必定大于基准值。

时间复杂度:O(NlogN)

空间复杂度:O(logN)

稳定性:不稳定

当一组数据完全有序时,时间复杂度为O(N^2),空间复杂度为O(N)。考虑有序的情况,可以进行一定程度的优化:在选取基准值前,可以先确定首元素中间元素和尾元素中中间大小的值与首元素交换,避免完全有序的情况。也可以在数据较少时,选择其他排序方法,例如直接插入排序(此时占用的空间非常多),这样可以避免当数据量非常庞大时造成栈溢出的情况。

非递归快速排序:

利用栈的先进后出特性将序列的首尾元素入栈,需要排序时出栈即可:

public static void quickSortNor(int[] array) {
    Deque<Integer> stack = new ArrayDeque<>();
    int left = 0;
    int right = array.length - 1;
    stack.push(left);
    stack.push(right);
    while (!stack.isEmpty()) {
        //先入的是left,所以后出的是left
        right = stack.pop();
        left = stack.pop();
        if (right - left < 1) {
            continue;//代表该段序列最多有一个元素,不用排序
        }
        int pivot = partition(array, left, right);
        //把左边序列的left和right入栈
        stack.push(left);
        stack.push(pivot);
        //把右边序列的left和right入栈
        stack.push(pivot + 1);
        stack.push(right);
    }
}

归并排序

归并排序:每次把待排序列均分成两个子序列,两个子序列有序后再进行合并。

大体框架如下:

public static void mergeSort(int[] array){
    mergeSortChild(array, 0, array.length - 1);
}

private static void mergeSortChild(int[] array, int left, int right) {
    if (left >= right) return;//此处原因同快排
    int mid = (right + left) / 2;
    mergeSortChild(array, left, mid);
    mergeSortChild(array, mid + 1, right);
    merge(array, left, right, mid);//这里的right - left是两个序列的总长度
}

框架也可以由非递归实现:

public static void mergeSortNor(int[] array){
    int gap = 1;//gap代表需要合并的两个序列的各自长度
    while (gap < array.length) {
        for (int i = 0; i < array.length; i += 2 * gap) {
            //合并一组
            int mid = i + gap - 1;//可能越界
            if (mid >= array.length) {
                mid = array.length - 1;
            }
            int j = mid + gap;
            if (j >= array.length) {
                j = array.length - 1;
            }
            merge(array, i, j, mid);
        }
        gap *= 2;
    }
}

那么实现这个排序地关键就是合并两个序列:

两个有序序列的合并:[9, 53, 73, 82]和[3, 7, 20, 45]

一定是首元素比较,小的放进来,往后走,再比较,直到一方走完。此时未走完的序列中所有的值一定是有序的且都大于已放入的元素,因此只需把剩余元素依次拷贝进来即可:

private static void merge(int[] array, int left, int right, int mid) {
    int s1 = left, s2 = mid + 1;
    int[] tmp = new int[right - left + 1];
    int i = 0;
    //s1-mid为第一段序列,mid + 1-right为第二段序列
    while (s1 <= mid && s2 <= right) {
        if (array[s1] < array[s2]) {
            tmp[i++] = array[s1++];
        }else {
            tmp[i++] = array[s2++];
        }
    }
    //剩余序列依次放入
    while (s1 <= mid) {
        tmp[i++] = array[s1++];
    }
    while (s2 <= right) {
        tmp[i++] = array[s2++];
    }
    //注意拷贝到原数组时数组下标+left才是原数组的真正下标
    //比如left为5,那么tmp[0]的值就要放到array[0 + 5]
    System.arraycopy(tmp, 0, array, left, tmp.length);
}

时间复杂度:O(NlogN)

空间复杂度:O(N)

稳定性:稳定

归并排序属于稳定排序,归并排序常用来处理海量数据的排序问题,归并排序的排序效率略低于快速排序

非基于比较的排序

基于比较的排序速度最快的时间复杂度也有O(NlogN),若要实现时间复杂度为线性,则需要考虑以空间换时间的做法,即计数排序、基数排序和桶排序。

计数排序

首先确定最大值和最小值,创建一个长度为最大值-最小值+1的计数数组,遍历到某个元素就在计数数组的相应下标所指的值+1,遍历完再根据计数数组返回原数组。

一种简单写法:该写法不稳定

public static void countSort(int[] array){
    int min = array[0];
    int max = array[0];
    for (int elem : array) {
        if (elem < min) {
            min = elem;
        } else if (elem > max) {
            max = elem;
        }
    }
    int[] tmp = new int[max - min + 1];
    for (int elem : array) {
        tmp[elem - min]++;
    }
    for (int i = 0, j = 0; i < tmp.length; i++) {
        if (tmp[i] >= 1) {
            array[j++] = i + min;
            tmp[i--]--;
        }
    }
}

若要实现稳定排序,需要再额外创建一个数组来存放从计数数组中返回的值,最后再复制到原数组:

public static void countSortB(int[] array) {
    int min = array[0];
    int max = array[0];
    for (int elem : array) {
        if (elem < min) {
            min = elem;
        } else if (elem > max) {
            max = elem;
        }
    }
    int[] tmp = new int[max - min + 1];
    int[] ret = new int[array.length];
    for (int elem : array) {
        tmp[elem - min]++;
    }
    for (int i = 1; i < tmp.length; i++) {
        tmp[i] += tmp[i - 1];//tmp[i] 表示比i + min小的数有tmp[i] - 1个
    }
    for (int i = array.length - 1; i >= 0; i--) {
        //这里的array[i] - min == 上一个for循环中的i
        ret[--tmp[array[i] - min]] = array[i];//前面有几个就放在下标是几的位置
        //从后往前,先出现的放在后面,从而稳定
    }
    System.arraycopy(ret, 0, array, 0, array.length);
}

时间复杂度:O(N) 实际上是N + max - min

空间复杂度:O(N) 实际上是N + max - min

稳定性:稳定

计数排序速度很快,但占用空间较多,当数据较为集中时,可以考虑计数排序。

桶排序

桶排序实际上是基于计数排序的一种变形:它不再是一个值放在一个位置,而是某个范围内的值放到某块空间,在每块空间内分别排序,直到每个空间都有序,按顺序返回原数组即有序:

比如说0~50的数据,可以分为5个桶0~9放到桶1中,10~19放到桶2中,20~29放到桶3中,30~39放到桶4中,40~49放到桶5中,还剩一个最大值50,放到桶5中。接着排序,返回。

public static void bucketSort(int[] array) {
    int max = array[0];
    int min = array[0];
    for (int elem : array) {
        if (elem > max) {
            max = elem;
        } else if (elem < min) {
            min = elem;
        }
    }
    //(max - min) / array.length仅为一种计算桶数量的方式,可以任意指定
    int bucketNum = (max - min) / array.length + 1;//+1保证最大值也能入桶
    ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketNum);
    for (int i = 0; i < bucketNum; i++) {
        buckets.add(new ArrayList<>());//创建桶
    }
    for (int elem : array) {
        int num = (elem - min) / array.length;//这里要保持和bucketNum一致
        buckets.get(num).add(elem);//在相应桶中添加元素
    }
    for (ArrayList<Integer> bucket : buckets) {
        Collections.sort(bucket);//每个桶内元素进行排序,也可以用其他排序方法
    }
    for (int i = 0, k = 0; i < buckets.size(); i++) {
        for (int j = 0; j < buckets.get(i).size(); j++) {
            array[k++] = buckets.get(i).get(j);
        }
    }
}

时间复杂度:O(N)->假如有M个桶,三次遍历整个数组为O(3 * N) + 一次遍历M个桶,桶内排序一般采用最快的算法为O(NlogN),则一个桶内的时间复杂度为:O(N/M * log(N/M)),M个桶时间复杂度为:O(N*(logN - logM)),整个过程时间复杂度为:O(N*(logN - logM + 3) + M)。当N = M时,化简后为O(N)

空间复杂度:O(N + M)

稳定性:稳定 ->桶内排序算法稳定即稳定

基数排序

基数排序是一种非常神奇的排序算法,首先需要创建10个数组(不考虑负数的话)用来存放数据,接着遍历数组,个位数为几就放进哪个数组,一轮遍历后按照顺序拿出来(先进先出),再按照新的顺序遍历,十位数为几就放进哪个数组,以此类推,直到最高位也处理完,数组就是有序的了:

例如对下列数据排序:[122, 245, 78, 4, 902, 34, 56, 44, 83, 32]

第一轮遍历

按顺序拿出来为[122, 902, 32, 83, 4, 34, 44, 245, 56, 78],接着按十位放

第二轮遍历

按顺序拿出来:[902, 4, 122, 32, 34, 44, 245, 56, 78, 83],再按百位放

第三轮遍历

按顺序拿出来:[4, 32, 34, 44, 56, 78, 83, 122, 245, 902],可以看到已经有序。

public static void baseSort(int[] array) {
    int[][] base = new int[10][array.length];
    int[] count = new int[10];//存放目标位数值的个数
    int maxDigit = getMaxDigit(array);//得到最大位数
    int digit = 1;//当前需要的位数
    while (maxDigit > 0) {
        //往base数组存值
        for (int value : array) {
            int tmp = value / digit % 10;//目标元素目标位数上的值
            base[tmp][count[tmp]++] = value;
        }
        //放好的值按顺序拿出来
        for (int i = 0, k = 0; i < 10; i++) {
            int j = 0;
            while (count[i] > 0) {
                array[k++] = base[i][j++];
                count[i]--;
            }
        }
        digit *= 10;
        maxDigit--;
    }
}

private static int getMaxDigit(int[] array) {
    int max = array[0];
    for (int elem : array) {
        if (elem > max) {
            max = elem;
        }
    }
    int count = 0;
    while (max > 0) {
        count++;
        max /= 10;
    }
    return count;
}

当然,这样是不能处理负数的,为了把负数添加进来,可以创建二十个数组,前十个用来放负数,因此代码就改成:

public static void baseSort(int[] array) {
    int[][] base = new int[20][array.length];
    int[] count = new int[20];//存放目标位数值的个数
    int maxDigit = getMaxDigit1(array);//得到最大位数
    int negNum = getNegNum(array);//得到数组中的负数个数
    int digit = 1;//当前需要的位数
    while (maxDigit > 0) {
        //往base数组存值
        for (int value : array) {
            if (value < 0) {
                int tmp = -value / digit % 10;//目标元素目标位数上的值
                base[tmp][count[tmp]++] = value;//0-9的位置存负数
            }else {
                int tmp = value / digit % 10;//目标元素目标位数上的值
                base[tmp + 10][count[tmp + 10]++] = value;
            }
        }
        //放好的值按顺序拿出来
        int k = 0;
        for (int i = 0; i < 20; i++) {
            int j = 0;
            while (count[i] > 0) {
                array[k++] = base[i][j++];
                count[i]--;
            }
        }
        digit *= 10;
        maxDigit--;
    }
    //负数的顺序是反的,需要交换顺序
    for (int i = 0; i < negNum / 2; i++) {
        swap(array, i, negNum - 1 - i);
    }
}
//得到负数的个数
private static int getNegNum(int[] array) {
    int count = 0;
    for (int elem : array) {
        if (elem < 0) {
            count++;
        }
    }
    return count;
}

private static int getMaxDigit1(int[] array) {
    //负数也要考虑,因此要找到最大值和最小值
    int max = array[0];
    int min = array[0];
    for (int elem : array) {
        if (elem > max) {
            max = elem;
        }else if (elem < min) {
            min = elem;
        }
    }
    min = -min;
    max = Math.max(max, min);
    int count = 0;
    while (max > 0) {
        count++;
        max /= 10;
    }
    return count;
}

时间复杂度:O(N)

空间复杂度:O(N)

稳定性:稳定

该算法虽然较快,但消耗的空间较多,空间复杂度实际上是20 * N。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/171739.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TreeMap和TreeSet的介绍

目录 1、认识 TreeMap 和 TreeSet 2、TreeMap 的主要成员变量 3、TreeMap 的主要构造方法 4、TreeMap 和 TreeSet 的元素必须可比较 5、TreeMap 和 TreeSet 关于 key 有序 6、TreeMap 和 TreeSet 的关系 7、总结 1、认识 TreeMap 和 TreeSet TreeMap 和 TreeSet 是Ja…

探索SpringMVC-组件之ViewResolver

前言 ViewResolver也就是视图解析器&#xff0c;他将是我们《探索SpringMVC》系列要介绍的最后一个常用的组件。其他组件&#xff1a;MultipartResolver、LocaleResolver、ThemeResolver、RequestToViewNameTranslator、FlashMapManager&#xff0c;相对简单&#xff0c;大家可…

一个想活得简单的程序猿的2022年终总结!

前言 今年的总结相比以往来说&#xff0c;可写的太少了&#xff0c;但看到我17年开始写的年终总结&#xff0c;已定下每年写下的承诺&#xff0c;因此即便可写的不多&#xff0c;但是还是写下吧&#xff0c;毕竟又过了一年&#xff0c;总有东西会留下&#xff01; 今年事件 疫…

【Linux杂篇】Windows远程登陆Linux、Linux静态IP配置

前言 如果要长期连接Linux环境&#xff0c;就需要给Linux配置一个静态IP&#xff0c;否则可能每次连接的IP都不一样而且还很麻烦。 除此之外&#xff0c;我们使用ssh远程登录的时候&#xff0c;每次都要输入密码&#xff0c;也很麻烦&#xff0c;所以建议配置ssh密钥&#xff…

执行 java -jar xxx.jar 的时候底层到底做了什么?

大家都知道我们常用的 SpringBoot 项目最终在线上运行的时候都是通过启动 java -jar xxx.jar 命令来运行的。那你有没有想过一个问题&#xff0c;那就是当我们执行 java -jar 命令后&#xff0c;到底底层做了什么就启动了我们的 SpringBoot 应用呢&#xff1f;或者说一个 Sprin…

Redis删除了大量数据后,为什么内存占用还是很高?

前言 上周刚来了个应届小师弟&#xff0c;组长说让我带着&#xff0c;周二问了我这样一个问题&#xff1a;师兄啊&#xff0c;我用top命令看了下服务器的内存占用情况&#xff0c;发现Redis内存占用严重&#xff0c;于是我就删除了大部分不用的keys&#xff0c;为什么内存占用…

文件操作【C语言】

目录 一、为什么使用文件 二、什么是文件 1、程序文件 2、数据文件 3、文件名 三、文件的打开和关闭 1、文件指针 2、文件的打开和关闭 四、文件的顺序读写 五、文件的随机读写 1、fseek 2、ftell 3、rewind 七、文件读取结束的判定 1、被错误使用的feof 1、文…

unocss原子化

文章目录1. 安装2. 配置3. Unocss预设3.1 presetUno3.2 presetAttributify3.3 presetIcons了解什么是UnoCSS请看&#xff1a;重新构想原子化CSS - 知乎 github地址&#xff1a;UnoCSS UnoCSS搜索引擎 1. 安装 npm i -D unocss2. 配置 vite.config.ts import { defineConf…

分享微信抽奖小程序制作步骤_微信抽奖小程序怎么开发

各位商家在节日期间做活动的时候&#xff0c;都希望用更少的费用去或者更好的宣传和推广的效果。比较常见的就是抽奖活动小程序。无须玩家下载&#xff0c;通过微信扫码或者指定入口就可以参与。方便&#xff0c;效果又好。那么,性价比高的抽奖活动小程序怎么做&#xff1f; 来…

LabVIEW使用VI脚本重新排列对象

LabVIEW使用VI脚本重新排列对象VI脚本可用来重新排列前面板和程序框图的对象。该教程以程序框图对象重新排列为例。按照下列步骤&#xff0c;使用VI脚本重新排列程序框图对象。创建VI前&#xff0c;需先了解VI脚本的基本内容。必须启用VI脚本&#xff0c;才能显示VI脚本选板&am…

solr-cloud集群

Zookeeper集群搭建完成&#xff0c;下面开始构建solr-cloud从复制四个tomcat实例开始将配置好的单机版solr复制到tomcat实例下修改tomcat端口号vim tomcat01/conf/server.xmlvim tomcat02 /conf/server.xml使用配置好的单机版solrhome关联solr和solrhomevim tomcat01/webapps/s…

数据库系统概念 | 第三章:SQL介绍

文章目录&#x1f4da;SQL语言概览&#x1f4da;SQL数据定义&#x1f407;基本数据类型&#x1f407;基本模式定义&#x1f955;create table&#x1f955;create domain&#x1f955;drop table&#x1f955;delete table&#x1f955;alter table&#x1f4da;SQL查询的基本结…

Transformer模型详解

1. 前言 transformer结构是google在2017年的Attention Is All You Need论文中提出&#xff0c;在NLP的多个任务上取得了非常好的效果&#xff0c;可以说目前NLP发展都离不开transformer。最大特点是抛弃了传统的CNN和RNN&#xff0c;整个网络结构完全是由Attention机制组成。 …

VESC操作入门——控制霍尔电机、无感电机和AS5047P

目录一、设备说明二、VESC4驱动霍尔电机2.1、硬件准备2.2、硬件连接2.3、打开软件2.4、连接2.5、校准电机2.6、主界面操作三、VESC4驱动无感电机3.1、硬件准备3.2、硬件连接3.3、打开软件3.4、校准电机四、VESC4驱动AS5047P4.1、软硬件修改4.2、硬件准备4.3、硬件连接4.4、校准…

Win32解决透明字体改变时重叠的问题,GetClientRect与GetWindowRect的使用

透明字体,改变时发生文本重叠,解决办法是刷新窗体局部区域,该区域是文本或者按钮等控件的区域 Win32 API中使用InvalidateRect函数使指定区域失效,意味着要刷新该区域,再用UpdateWindow函数强迫窗体立即刷新 RECT rc; ... InvalidateRect(hWnd,&rc,true); UpdateWind…

Python操作文件及其内容的常用方式

Python操作文件及其内容的常用方式 文章目录Python操作文件及其内容的常用方式1&#xff1a;修改文件名1.1&#xff1a;修改指定文件名1.2&#xff1a;修改目录下的所有文件的文件名2&#xff1a;读取文件2.1&#xff1a;读取文件内容2.1.1&#xff1a;按行读取2.1.2&#xff1…

[Arduino]环境安装与配置

最近着迷与Arduio&#xff0c;可以连接控制各种器件帮助人类降低负担&#xff0c;如室内外温度动态采集、声控灯、自动给绿植浇水等各种应用&#xff0c;感觉挺有意思&#xff1b;随着最近两年物联网的推广及“万物互联”的普及&#xff0c;个人觉得物联网还是有点花样的&#…

认证授权功能分析

1 模块需求分析 1.1 什么是认证授权 截至目前&#xff0c;项目已经完成了课程发布功能&#xff0c;课程发布后用户通过在线学习页面点播视频进行学习。如何去记录学生的学习过程呢&#xff1f;要想掌握学生的学习情况就需要知道用户的身份信息&#xff0c;记录哪个用户在什么…

1949-2020年各省全要素生产率(年度)

1949-2020年各省全要素生产率(年度) 1、时间&#xff1a;1949-2020年 2、计算说明&#xff1a;产出为实际GDP&#xff0c;投入要素为从业人员数、固定资产&#xff08;永续盘存法&#xff09; 3、范围&#xff1a;包括31省 4、指标说明&#xff1a; 全要素生产率&#xf…

TiCDC 源码阅读(三)TiCDC 集群工作过程解析

内容概要 TiCDC 是一款 TiDB 增量数据同步工具&#xff0c;通过拉取上游 TiKV 的数据变更日志&#xff0c;TiCDC 可以将数据解析为有序的行级变更数据输出到下游。 本文是 TiCDC 源码解读的第三篇&#xff0c;主要内容是讲述 TiCDC 集群的启动及基本工作过程&#xff0c;将从…