【算法】八大排序算法

news2025/1/9 16:02:37

这篇文章是对数据结构中 八大经典排序算法 的详解,包括其原理实现过程时间复杂度空间复杂度及其适用场景。最后两种排序不常见,但仍收录了进来保持文章结构的完整性。

排序(Sort)是将无序的记录序列(或称文件)调整成有序的序列。升序 或 降序 —> 一般都是对数据进行升序排列(从小到大排序)。

对文件(File)进行排序有重要的意义。如果文件按key有序,可对其折半查找,使查找效率提高;在数据库(Data Base)和知识库(Knowledge Base)等系统中,一般要建立若干索引文件,就牵涉到排序问题;在一些计算机的应用系统中,要按不同的数据段作出若干统计,也涉及到排序。排序效率的高低,直接影响到计算机的工作效率。

稳定排序和非稳定排序

设文件 f=(R1……Ri……Rj……Rn)中记录 Ri、Rj(i≠j,i、j=1……n)key 相等,即 Ki=Kj 。若在排序前 Ri 领先于Rj,排序后 Ri 仍领先于 Rj,则称这种排序是稳定的,其含义是它没有破坏原本已有序的次序。反之,若排序后Ri与Rj的次序有可能颠倒,则这种排序是非稳定的,即它有可能破坏了原本已有序记录的次序。

说人话就是:假设有6个数据:5 2 6 2 8 1 —> 具有重复数据;经过排序后得到: 1 2 2 5 6 8,稳定排序和不稳定排序之间讲究的就是在相同的数据中,相同数据是否转换了位置。

1> 1 2 2 5 6 8
------①②--------> 两个 2(重复数据) 没有发生位置改变,称为稳定排序。
2> 1 2 2 5 6 8
------②①--------> 两个 2(重复数据) 发生了位置改变,称为不稳定排序。

排序的稳定性没办法解决,看具体的算法性能决定排序的稳定性。这二者之间只有性能差异,并不会影响到数据和操作的变化。

内排序和外排序

内排序:发生在内存中的排序方式(我们现在用的大部分排序方式都是内排序);
外排序:发生在其他硬件或(存储器)之间的排序 —> 通信排序。

若待排文件 f 在计算机的内存储器中,且排序过程也在内存中进行,称这种排序为内排序。内排序速度快,但由于内存容量一般很小,文件的长度(记录个数)n受到一定限制。若排序中的文件存入外存储器,排序过程借助于内外存数据交换(或归并)来完成,则称这种排序为外排序。我们重点讨论内排序的一些方法、算法以及时间复杂度的分析。

算法数据可视化参考该网站:https://visualgo.net/zh。

截止目前,各种内排序方法可归纳为以下五类:

(1)插入排序
(2)交换排序
(3)选择排序
(4)归并排序
(5)基数排序

也可以按照比较类排序和非比较类排序来进行分类:

  • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
    请添加图片描述
算法复杂度分析

请添加图片描述

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
  • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

1. 冒泡排序(Bubble Sort)

冒泡排序是一种简单的交换排序算法,按顺序比较相邻的两个元素,将较大的元素逐渐“冒泡”到数组的末尾。相信冒泡排序是大家最熟知、面试中常考题、也是最经典的一种排序方式。

算法原理

  1. 对数组从头到尾遍历。
  2. 每次比较相邻的两个元素,如果前者大于后者,则交换它们。
  3. 每轮遍历后,最大的元素会“冒泡”到数组的末尾。
  4. 重复此过程,直到数组完全有序。

时间复杂度

  • 最好情况:O(n)(数组本身有序,使用标志优化)
  • 最坏情况:O(n²)(数组逆序)
  • 平均情况:O(n²)

空间复杂度

  • O(1)(原地排序)

冒泡排序演示
冒泡排序
代码实现(C语言)

void bubbleSort(int arr[], int n) {
    int i, j, temp;
    for (i = 0; i < n - 1; i++) {
        int swapped = 0;  // 标志位,检测是否发生交换
        for (j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                swapped = 1;
            }
        }
        if (!swapped) break;  // 如果没有发生交换,提前退出
    }
}

2. 选择排序(Selection Sort)

选择排序是一种简单的排序算法,通过选择最小(或最大)的元素并将其放到正确位置。

算法原理

  1. 在未排序部分中找到最小元素。
  2. 将该最小元素与未排序部分的第一个元素交换。
  3. 重复上述步骤,直到所有元素有序。

时间复杂度

  • 最好情况:O(n²)
  • 最坏情况:O(n²)
  • 平均情况:O(n²)

空间复杂度

  • O(1)(原地排序)

选择排序演示
请添加图片描述
代码实现(C语言)

void selectionSort(int arr[], int n) {
    int i, j, minIndex, temp;
    for (i = 0; i < n - 1; i++) {
        minIndex = i;
        for (j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        if (minIndex != i) {
            temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

选择排序是表现最稳定的排序算法之一,因为无论什么数据进去都是 O(n2) 的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法。

3. 插入排序(Insertion Sort)

插入排序通过逐步构建有序序列,将每个元素插入到有序序列的正确位置。

算法原理

  1. 从第二个元素开始,视其为待插入元素。
  2. 从已排序部分的末尾向前遍历,找到其插入位置。
  3. 插入元素后,已排序部分长度加 1。
  4. 重复上述步骤,直到所有元素有序。

时间复杂度

  • 最好情况O(n)(数组本身有序)
  • 最坏情况:O(n²)(数组逆序)
  • 平均情况O(n²)

空间复杂度

  • O(1)(原地排序)

插入排序演示
请添加图片描述

代码实现(C语言)

void insertionSort(int arr[], int n) {
    int i, j, key;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

4. 希尔排序(Shell Sort)

希尔排序是插入排序的改进版,通过分组和缩小增量进行排序。

算法原理

  1. 将数组分成若干组,按间隔 gap 分组。
  2. 对每组元素进行插入排序。
  3. 缩小间隔 gap,重复分组和排序。
  4. 最后,当 gap = 1 时,完成整个排序。

时间复杂度

  • 最好情况:O(n log n)
  • 最坏情况:O(n²)
  • 平均情况:O(n log n)

空间复杂度

  • O(1)

希尔排序演示
请添加图片描述

代码实现(C语言)

void shellSort(int arr[], int n) {
    int gap, i, j, temp;
    for (gap = n / 2; gap > 0; gap /= 2) {
        for (i = gap; i < n; i++) {
            temp = arr[i];
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = temp;
        }
    }
}

希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。

5. 快速排序(Quick Sort)

快速排序是一种基于分治的高效排序算法。

算法原理

  1. 选择一个基准值(通常是第一个元素)。
  2. 将数组分为两部分:小于基准值的放左边,大于基准值的放右边。
  3. 对两部分递归排序。
  4. 递归结束后,数组有序。

时间复杂度

  • 最好情况:O(n log n)
  • 最坏情况:O(n²)(划分极不平衡)
  • 平均情况:O(n log n)

空间复杂度

  • O(log n)(递归栈空间)

快速排序演示
请添加图片描述

代码实现(C语言)

void quick_sort(int *a,int left,int right)
{
	if(left>=right)
	{
		return;
	}
	
	int i=left;
	int j=right;
	int key=a[i];
	
	while(i<j)
	{
		while(key<a[j] && i<j)
		{
			j--;
		}
		a[i]=a[j];
		
		while(key>a[i] && i<j)
		{
			i++;
		}
		a[j]=a[i];
		
	}
	
	a[i]=key;
	display(a);
	quick_sort(a,left,i-1);
	quick_sort(a,i+1,right);
}

快速排序思路分析

6. 归并排序(Merge Sort)

归并排序是基于分治的稳定排序算法。

算法原理

  1. 将数组递归分成两部分,直到每部分只有一个元素。
  2. 合并两个有序部分,形成一个有序数组。
  3. 重复上述步骤,最终完成排序。

时间复杂度

  • 最好/最坏/平均情况:O(n log n)

空间复杂度

  • O(n)(合并时需要额外数组)

归并排序演示
请添加图片描述

代码实现(C语言)

void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++) L[i] = arr[left + i];
    for (int i = 0; i < n2; i++) R[i] = arr[mid + 1 + i];
    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) arr[k++] = L[i++];
        else arr[k++] = R[j++];
    }
    while (i < n1) arr[k++] = L[i++];
    while (j < n2) arr[k++] = R[j++];
}

void mergeSort(int arr[], int left, int right) {
    if (left >= right) return;
    int mid = left + (right - left) / 2;
    mergeSort(arr, left, mid);
    mergeSort(arr, mid + 1, right);
    merge(arr, left, mid, right);
}

归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。

7. 堆排序(Heap Sort)

堆排序基于堆数据结构,是一种选择排序。

算法原理

  1. 构建最大堆(堆顶为最大元素)。
  2. 将堆顶元素与堆尾元素交换,缩小堆范围。
  3. 调整堆,重复上述步骤,完成排序。

时间复杂度

  • 最好/最坏/平均情况:O(n log n)

空间复杂度

  • O(1)

堆排序演示
请添加图片描述

代码实现(C语言)

void heapify(int arr[], int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    if (left < n && arr[left] > arr[largest]) largest = left;
    if (right < n && arr[right] > arr[largest]) largest = right;
    if (largest != i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;
        heapify(arr, n, largest);
    }
}

void heapSort(int arr[], int n) {
    for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i);
    for (int i = n - 1; i > 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        heapify(arr, i, 0);
    }
}

8. 基数排序(Radix Sort)

基数排序是一种非比较排序算法,适合对整数或字符串进行排序。其核心思想是按位排序,从最低位到最高位,逐位进行排序(通常使用计数排序作为子过程)。

算法原理

  1. 按位排序:
    • 从个位开始,对每一位进行排序,直到最高位。
    • 每一位的排序需要保持稳定性(如使用计数排序实现)。
  2. 关键步骤:
    • 找到数组中的最大值,确定排序的位数 d。
    • 对每一位(从最低位到最高位)依次排序。
    • 使用计数排序对当前位排序,确保排序稳定。

时间复杂度

  • 对每一位执行一次计数排序,时间复杂度为 O(n + k)
  • 总共需要执行 d 次,时间复杂度为 O(d × (n + k))
    • d 是最大元素的位数。
    • k 是基数(通常为 10)。

空间复杂度

  • 需要额外的计数数组和输出数组,空间复杂度为 O(n + k)

基数排序演示
请添加图片描述

代码实现(C语言)

#include <stdio.h>
#include <stdlib.h>

// 获取数组中的最大值
int getMax(int arr[], int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    return max;
}

// 对数组按当前位进行计数排序
void countingSort(int arr[], int n, int exp) {
    int output[n];   // 输出数组
    int count[10] = {0};  // 计数数组,用于存储每一位数字的出现次数

    // 统计当前位数字的出现次数
    for (int i = 0; i < n; i++) {
        int digit = (arr[i] / exp) % 10;  // 提取当前位的数字
        count[digit]++;
    }

    // 计算累计计数,确保稳定排序
    for (int i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }

    // 根据当前位的数字,将元素放入输出数组
    for (int i = n - 1; i >= 0; i--) {
        int digit = (arr[i] / exp) % 10;  // 提取当前位的数字
        output[count[digit] - 1] = arr[i];
        count[digit]--;
    }

    // 将排序后的结果复制回原数组
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }
}

// 基数排序的主函数
void radixSort(int arr[], int n) {
    int max = getMax(arr, n);  // 找到数组中的最大值

    // 从个位开始,对每一位进行计数排序
    for (int exp = 1; max / exp > 0; exp *= 10) {
        countingSort(arr, n, exp);
    }
}

// 打印数组
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 主函数
int main() {
    int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("Original array:\n");
    printArray(arr, n);

    radixSort(arr, n);

    printf("Sorted array:\n");
    printArray(arr, n);

    return 0;
}
// (1) 获取最大值函数
//     getMax 找到最大值,用于确定排序的位数(d)。
//     时间复杂度:O(n)。
// (2) 计数排序函数
//     countingSort 按当前位(exp)对数组排序:
//       提取当前位的数字:(arr[i] / exp) % 10。
//       使用计数数组统计出现次数,完成稳定排序。
// (3) 基数排序主函数
//     对每一位(个位、十位、百位……)依次调用 countingSort。
//     外层循环次数为最大元素的位数 d。
// (4) 输出数组
//     使用 printArray 打印数组,方便调试和验证。

运行结果:
输入数组:

170, 45, 75, 90, 802, 24, 2, 66

排序过程(按位):

  1. 按个位排序:
170, 90, 802, 2, 24, 45, 66, 75
  1. 按十位排序:
802, 2, 24, 45, 66, 75, 170, 90
  1. 按百位排序:
2, 24, 45, 66, 75, 90, 170, 802

最终输出结果:

2, 24, 45, 66, 75, 90, 170, 802

基数排序基于分别排序,分别收集,所以是稳定的。基数排序是一种快速、稳定的排序算法,适合对整数或字符串进行排序。通过按位排序,避免了直接比较元素大小,在特定场景下(如大量非负整数排序),基数排序的效率优于比较排序算法(如快速排序)。

9. 计数排序(Counting Sort)

计数排序是一种非比较排序算法,适用于整数或离散范围较小的数据。通过统计每个元素出现的次数,并利用这些计数信息将数据排序。

算法原理

  1. 找出数组中的最大值和最小值,确定计数数组的大小。
  2. 创建一个计数数组 count,统计每个数字出现的次数。
  3. 对计数数组进行累加操作,计算每个元素的位置。
  4. 根据计数数组,将原数组中的元素放到正确的位置上,并生成输出数组。

时间复杂度

  • O(n + k)(n 为数组长度,k 为数据范围)。

空间复杂度

  • O(k)

计数排序演示
请添加图片描述
代码实现(C语言)

#include <stdio.h>
#include <stdlib.h>

// 计数排序
void countingSort(int arr[], int n) {
    // 找到数组中的最大值和最小值
    int max = arr[0], min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
        if (arr[i] < min) min = arr[i];
    }

    int range = max - min + 1;  // 数据范围
    int* count = (int*)calloc(range, sizeof(int));  // 创建计数数组并初始化为 0
    int* output = (int*)malloc(n * sizeof(int));    // 创建输出数组

    // 统计每个元素的出现次数
    for (int i = 0; i < n; i++) {
        count[arr[i] - min]++;
    }

    // 计算计数数组的累加值
    for (int i = 1; i < range; i++) {
        count[i] += count[i - 1];
    }

    // 根据计数数组将元素放入正确位置,生成输出数组
    for (int i = n - 1; i >= 0; i--) {
        output[count[arr[i] - min] - 1] = arr[i];
        count[arr[i] - min]--;
    }

    // 将排序后的数组拷贝回原数组
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }

    // 释放动态分配的内存
    free(count);
    free(output);
}

int main() {
    int arr[] = {4, 2, 2, 8, 3, 3, 1};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("Original array: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    countingSort(arr, n);

    printf("Sorted array: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

运行结果

# 输入数组:
{4, 2, 2, 8, 3, 3, 1}
# 输出数组:
{1, 2, 2, 3, 3, 4, 8}

计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。

计数排序适用于整数或范围较小的数据,具有高效的时间复杂度,但空间使用较大。

10. 桶排序(Bucket Sort)

桶排序是一种基于分布的排序算法,将输入数据分配到若干个桶(区间)中,然后对每个桶内的数据进行单独排序,最后将桶内的元素合并得到结果。

算法原理

  1. 确定桶的数量和每个桶的范围。
  2. 创建若干个桶,将元素分配到对应的桶中。
  3. 对每个桶内的元素进行排序(可以使用其他排序算法,如插入排序、快速排序等)。
  4. 将所有桶内的元素按序合并。

时间复杂度

  • O(n + k)(k 为桶的数量)。

空间复杂度

  • O(n + k)

桶排序演示
桶排序_1
桶排序_2
代码实现(C语言)

#include <stdio.h>
#include <stdlib.h>

// 桶排序中的插入排序
void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

// 桶排序
void bucketSort(float arr[], int n) {
    // 创建 n 个桶,每个桶是一个动态数组
    int bucketCount = n;
    float** buckets = (float**)malloc(bucketCount * sizeof(float*));
    int* bucketSizes = (int*)calloc(bucketCount, sizeof(int));  // 存储每个桶的大小

    for (int i = 0; i < bucketCount; i++) {
        buckets[i] = (float*)malloc(n * sizeof(float));  // 每个桶最大容量为 n
    }

    // 将元素分配到对应的桶中
    for (int i = 0; i < n; i++) {
        int bucketIndex = (int)(arr[i] * bucketCount);  // 根据值计算桶索引
        buckets[bucketIndex][bucketSizes[bucketIndex]++] = arr[i];
    }

    // 对每个桶内的数据进行排序
    for (int i = 0; i < bucketCount; i++) {
        insertionSort(buckets[i], bucketSizes[i]);
    }

    // 合并所有桶中的数据
    int index = 0;
    for (int i = 0; i < bucketCount; i++) {
        for (int j = 0; j < bucketSizes[i]; j++) {
            arr[index++] = buckets[i][j];
        }
        free(buckets[i]);  // 释放桶内存
    }

    free(buckets);
    free(bucketSizes);
}

int main() {
    float arr[] = {0.42, 0.32, 0.23, 0.52, 0.25, 0.47, 0.51};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("Original array: ");
    for (int i = 0; i < n; i++) {
        printf("%.2f ", arr[i]);
    }
    printf("\n");

    bucketSort(arr, n);

    printf("Sorted array: ");
    for (int i = 0; i < n; i++) {
        printf("%.2f ", arr[i]);
    }
    printf("\n");

    return 0;
}

运行结果:

# 输入数组:
{0.42, 0.32, 0.23, 0.52, 0.25, 0.47, 0.51}
# 输出数组:
{0.23, 0.25, 0.32, 0.42, 0.47, 0.51, 0.52}

桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

桶排序适用于浮点数或连续数据,通过分桶和排序实现高效排序,尤其在数据分布均匀时表现优异。

想要了解更多算法动画演示和代码逻辑在这个网站中可以查阅: https://visualgo.net/en

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

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

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

相关文章

【学习笔记】数据结构(十一)

外部排序 文章目录 外部排序11.1 外存信息的存取11.2 外部排序的方法11.3 多路平衡归并的实现 - 增加k11.4 置换-选择排序 - 减少m11.5 最佳归并树 外部排序 指的是大文件的排序&#xff0c;即待排序的记录存储在外存储器 上&#xff0c;在排序过程中需进行多次的内、外存之间的…

基于 Python 自动化接口测试(踩坑与实践)

文档&#xff1a;基于 Python 的自动化接口测试 目录 背景问题描述与解决思路核心代码修改点及其详细解释最终测试结果后续优化建议 1. 问题背景 本项目旨在使用 Python 模拟浏览器的请求行为&#xff0c;测试文章分页接口的可用性。测试目标接口如下&#xff1a; bashcoder…

单片机-外部中断

中断是指 CPU 在处理某一事件 A 时&#xff0c;发生了另一事件 B&#xff0c;请求 CPU 迅速去处理(中断发生)&#xff1b;CPU 暂时停止当前的工作(中断响应)&#xff0c; 转去处理事件 B(中断服务)&#xff1b;待 CPU 将事件 B 处理完毕后&#xff0c;再回到原来事件 A 被中断的…

vite5.x配置https

旧版的vite直接在config里面配置https&#xff1a;true即可&#xff0c;新版的麻烦一些。 1.准备工作 需要安装openssl 下载地址&#xff1a;Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 找到合适的版本安装&#xff0c;配置好环境变量&#x…

Clip Studio Paint 报错:Running on unsupported Os. Clip Studio Paint will close.

问题描述 启动 Clip Studio Paint 报错&#xff1a;Running on unsupported Os. Clip Studio Paint will close. 原因 Clip Studio Paint 锁区&#xff0c;系统是中国大陆的无法使用。 解决方式 打开系统设置 时间和语言- 区域- 区域格式- 简体中文&#xff08;新加坡&am…

vue2/vue3中使用的富文本编辑器vue-quill

前言&#xff1a; 整理下常用的富文本编辑器工具。 vue3: 实现效果&#xff1a; 实现步骤&#xff1a; 1、安装插件&#xff0c; 编辑器核心插件 vueup/vue-quill yarn add pnpm i npm i cnpm i vueup/vue-quill vueup/vue-quill 2、安装选择性插件 &am…

Vscode 如何使用GitHub Copilot

一、“GitHub Copilot”进行登录 前提必须有github账号&#xff0c;如果没有就注册一个&#xff1b; 系统会提示您输入 GitHub 凭据。单击“登录 GitHub”&#xff0c;然后单击“允许”并输入您的 GitHub 凭据。 登录成功后&#xff1a; 二、 GitHub Copilot功能 1、预测代码 …

docker搭建atlassian-confluence:7.2.0

文章目录 引言I 部署前准备数据库镜像准备自己构建镜像dockerhub第三方镜像II 安装启动容器基础配置(获取服务器ID)授权码获取集群选择设置数据库配置管理员账号引言 准备数据库、镜像启动容器获取服务器ID根据服务器ID等信息,基于atlassian-agent.jar 授权I 部署前准备 数…

通过可穿戴外骨骼,以更灵活的方式操作你的机器人。

今天&#xff0c;我们将介绍一款专为控制 Mercury X1 和 Mercury B1 机械臂而设计的创新外骨骼。这种外骨骼以人类手臂的结构为蓝本&#xff0c;可实现直观和精确的控制。 开发这种外骨骼的动机源于人们对深度学习和机器学习等领域日益增长的兴趣。这些技术使机器人能够自主学习…

Ubuntu更改内核

需求背景&#xff1a; 由于软件需要在较低版本或者指定版本才可以运行 版本&#xff1a; 配置文件&#xff1a; vi /etc/default/grub 启动界面&#xff1a; 可运行版本&#xff1a; 解决方案&#xff1a; 方案1、更改启动顺序 sudo vi /etc/default/grub 方案2、调整启动顺…

maven之插件调试

当使用maven进行项目管理的时候&#xff0c;可能会碰到一些疑难问题。网上资料很少&#xff0c;可能会想着直接调试定位问题。这里以maven-compiler-plugin为例&#xff1a; &#xff08;1&#xff09;准备maven-compiler-plugin源码 进入maven 官网-》Maven Plugins-》找到对…

DevToys 专为 Windows 开发者打造的“瑞士军刀”式离线软件

你是否还在为寻找各种在线开发小工具而疲于奔波&#xff1f;**每次要格式化 JSON、比较文本、或者测试正则表达式&#xff0c;都得打开一堆网站&#xff0c;弹窗广告满天飞&#xff0c;严重影响工作效率。想不想要一个“多合一”的离线工具箱&#xff0c;轻松搞定开发中琐碎的日…

INT301 Bio Computation 题型整理

perceptron 设计和计算 1. XOR: 当两个输入值中只有一个为真时&#xff0c;输出为真 2. 3. 5. 6. 7. 2^3 2^n 9. a) 直接test b) 把v≥2 改成 v≥1 10. no, because it cant be separate through only one decision boundary,its not linearlly separable. Backpropagatio…

009:传统计算机视觉之边缘检测

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 本节来看一个利用传统计算机视觉方法来实现图片边缘检测的方法。 什么是边缘检测&#xff1f; 边缘检测是通过一些算法来识别图像中物体之间或者物体与背景之间的边界&…

ffmpeg-avio实战:打开本地文件或者网络直播流dome

使用ffmpeg打开打开本地文件或者网络直播流的一个小dome。流程产靠ffmpeg4.x系列的解码流程-CSDN博客 #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavformat/avio.h> #include <libavutil/file.h> #include &l…

Unity Burst详解

【简介】 Burst是Unity的编译优化技术&#xff0c;优化了从C#代码编译成Native代码的过程&#xff0c;经过编译优化后代码有更高的运行效率。 在Unity中使用Burst很简单&#xff0c;在方法或类前加上[BurstCompile]特性即可。在构建时编译代码的步骤&#xff0c;Burst编译器会…

el-table 合并单元格

参考文章&#xff1a;vue3.0 el-table 动态合并单元格 - flyComeOn - 博客园 <el-table :data"tableData" border empty-text"暂无数据" :header-cell-style"{ background: #f5f7fa }" class"parent-table" :span-method"obj…

WebRTC 在视频联网平台中的应用:开启实时通信新篇章

在当今这个以数字化为显著特征的时代浪潮之下&#xff0c;实时通信已然稳稳扎根于人们生活与工作的方方面面&#xff0c;成为了其中不可或缺的关键一环。回首日常生活&#xff0c;远程办公场景中的视频会议让分散各地的团队成员能够跨越地理距离的鸿沟&#xff0c;齐聚一堂共商…

OpenAI CEO 奥特曼发长文《反思》

OpenAI CEO 奥特曼发长文《反思》 --- 引言&#xff1a;从 ChatGPT 到 AGI 的探索 ChatGPT 诞生仅一个多月&#xff0c;如今我们已经过渡到可以进行复杂推理的下一代模型。新年让人们陷入反思&#xff0c;我想分享一些个人想法&#xff0c;谈谈它迄今为止的发展&#xff0c;…

网络空间安全导论期末考试复习题

题型&#xff1a;10个选择题10个大题 1、选择题 简单&#xff0c;记忆书本里的小标题 2、大题&#xff08;较难&#xff09; 网络安全体系的五个层次的内容画公钥密码结合报文鉴别的示意图解释误用入侵检测并画示意图解释隧道技术并画示意图防火墙的作用&#xff0c;防火墙和…