当前位置: 首页 > news >正文

数组排序算法

数组排序算法

用C语言实现的数组排序算法。

排序算法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度是否稳定适用场景
QuickO(n log n)O(n²)O(n log n)O(log n)不稳定大规模数据,通用排序
BubbleO(n²)O(n²)O(n)O(1)稳定小规模数据,教学用途
InsertO(n²)O(n²)O(n)O(1)稳定小规模或部分有序数据
SelectO(n²)O(n²)O(n²)O(1)不稳定小规模数据,简单实现
MergeO(n log n)O(n log n)O(n log n)O(n)稳定大规模数据,稳定排序需求
HeapO(n log n)O(n log n)O(n log n)O(1)不稳定大规模数据,原地排序需求
CountO(n + k)O(n + k)O(n + k)O(n + k)稳定小范围整数排序
RadixO(d(n + k))O(d(n + k))O(d(n + k))O(n + k)稳定整数或字符串排序,位数较小
BucketO(n + k)O(n²)O(n)O(n + k)稳定均匀分布的数据
ShellO(n log n)O(n²)O(n log n)O(1)不稳定中等规模数据,改进的插入排序

快速排序

快速排序(Quick Sort)是一种高效的排序算法,采用分治法(Divide and Conquer)策略。以下是使用C语言实现数组的快速排序的代码:

#include <stdio.h>// 交换两个元素的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 分区函数,返回分区点的索引
int partition(int arr[], int low, int high) {int pivot = arr[high];  // 选择最后一个元素作为基准int i = (low - 1);  // i是较小元素的索引for (int j = low; j <= high - 1; j++) {// 如果当前元素小于或等于基准if (arr[j] <= pivot) {i++;  // 增加较小元素的索引swap(&arr[i], &arr[j]);}}swap(&arr[i + 1], &arr[high]);  // 将基准元素放到正确的位置return (i + 1);
}// 快速排序的递归函数
void quickSort(int arr[], int low, int high) {if (low < high) {// pi是分区点,arr[pi]已经排好序int pi = partition(arr, low, high);// 递归地对分区点左边和右边的子数组进行排序quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {10, 7, 8, 9, 1, 5};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);quickSort(arr, 0, n - 1);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. swap函数:用于交换两个元素的值。
  2. partition函数:选择数组的最后一个元素作为基准(pivot),然后将数组分为两部分,左边部分的元素都小于或等于基准,右边部分的元素都大于基准。最后返回基准元素的正确位置。
  3. quickSort函数:递归地对数组进行排序。首先通过partition函数找到分区点,然后对分区点左边和右边的子数组分别进行快速排序。
  4. printArray函数:用于打印数组的内容。
  5. main函数:测试快速排序的实现。

运行结果:

原始数组: 
10 7 8 9 1 5 
排序后的数组: 
1 5 7 8 9 10 

时间复杂度:

  • 平均时间复杂度:O(n log n)
  • 最坏时间复杂度:O(n^2)(当数组已经有序或所有元素相等时)
  • 空间复杂度:O(log n)(递归栈的深度)

快速排序是一种非常高效的排序算法,尤其适用于大规模数据的排序。

冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地遍历数组,比较相邻的元素并交换它们的位置,直到整个数组有序。以下是使用C语言实现数组的冒泡排序的代码:

#include <stdio.h>// 交换两个元素的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 冒泡排序函数
void bubbleSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {  // 外层循环控制遍历次数for (int j = 0; j < n - i - 1; j++) {  // 内层循环比较相邻元素if (arr[j] > arr[j + 1]) {swap(&arr[j], &arr[j + 1]);  // 如果顺序错误,交换元素}}}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {64, 34, 25, 12, 22, 11, 90};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);bubbleSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. swap函数:用于交换两个元素的值。
  2. bubbleSort函数
    • 外层循环控制遍历次数,每次遍历会将当前未排序部分的最大值“冒泡”到正确的位置。
    • 内层循环比较相邻元素,如果顺序错误(前一个元素大于后一个元素),则交换它们。
  3. printArray函数:用于打印数组的内容。
  4. main函数:测试冒泡排序的实现。

运行结果:

原始数组: 
64 34 25 12 22 11 90 
排序后的数组: 
11 12 22 25 34 64 90 

优化版本:

如果某次遍历中没有发生任何交换,说明数组已经有序,可以提前结束排序。以下是优化后的冒泡排序代码:

void bubbleSortOptimized(int arr[], int n) {int swapped;  // 标记是否发生交换for (int i = 0; i < n - 1; i++) {swapped = 0;  // 每次遍历前重置标记for (int j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {swap(&arr[j], &arr[j + 1]);swapped = 1;  // 发生交换,标记为1}}if (swapped == 0) {  // 如果没有发生交换,说明数组已经有序break;}}
}

时间复杂度:

  • 最坏情况:O(n²)(当数组完全逆序时)
  • 最好情况:O(n)(当数组已经有序时,优化版本可以达到)
  • 平均情况:O(n²)

空间复杂度:

  • O(1)(原地排序,不需要额外空间)

冒泡排序虽然简单,但在实际应用中效率较低,通常用于教学或小规模数据的排序。对于大规模数据,更高效的排序算法(如快速排序、归并排序等)更为适用。

插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。以下是使用C语言实现数组的插入排序的代码:


插入排序代码实现

#include <stdio.h>// 插入排序函数
void insertionSort(int arr[], int n) {int i, j, key;for (i = 1; i < n; i++) {key = arr[i];  // 当前需要插入的元素j = i - 1;// 将比key大的元素向后移动while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;  // 插入key到正确位置}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {12, 11, 13, 5, 6};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);insertionSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. insertionSort函数
    • 从第二个元素开始(i = 1),将当前元素key插入到已排序部分的正确位置。
    • 使用while循环将比key大的元素向后移动,直到找到key的正确位置。
    • key插入到正确位置。
  2. printArray函数:用于打印数组的内容。
  3. main函数:测试插入排序的实现。

运行结果:

原始数组: 
12 11 13 5 6 
排序后的数组: 
5 6 11 12 13 

时间复杂度:

  • 最坏情况:O(n²)(当数组完全逆序时)
  • 最好情况:O(n)(当数组已经有序时)
  • 平均情况:O(n²)

空间复杂度:

  • O(1)(原地排序,不需要额外空间)

插入排序的特点:

  1. 适合小规模数据:对于小规模数据或部分有序的数据,插入排序的效率较高。
  2. 稳定排序:插入排序是稳定的排序算法,相同元素的相对顺序不会改变。
  3. 简单直观:实现简单,易于理解和实现。

优化版本:

插入排序可以通过二分查找来优化查找插入位置的过程,将查找时间从O(n)优化到O(log n),但整体时间复杂度仍然是O(n²)。

// 使用二分查找优化插入排序
void insertionSortOptimized(int arr[], int n) {int i, j, key, low, high, mid;for (i = 1; i < n; i++) {key = arr[i];low = 0;high = i - 1;// 使用二分查找找到插入位置while (low <= high) {mid = (low + high) / 2;if (arr[mid] > key) {high = mid - 1;} else {low = mid + 1;}}// 将元素向后移动for (j = i - 1; j >= low; j--) {arr[j + 1] = arr[j];}arr[low] = key;  // 插入key到正确位置}
}

插入排序在实际应用中常用于小规模数据排序或作为其他排序算法(如快速排序、归并排序)的辅助排序方法。

选择排序

选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是每次从未排序部分中选择最小(或最大)的元素,将其放到已排序部分的末尾。以下是使用C语言实现数组的选择排序的代码:


选择排序代码实现

#include <stdio.h>// 交换两个元素的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 选择排序函数
void selectionSort(int arr[], int n) {int i, j, min_idx;for (i = 0; i < n - 1; i++) {min_idx = i;  // 假设当前索引i是最小元素的索引// 在未排序部分中找到最小元素的索引for (j = i + 1; j < n; j++) {if (arr[j] < arr[min_idx]) {min_idx = j;}}// 将找到的最小元素与当前元素交换if (min_idx != i) {swap(&arr[min_idx], &arr[i]);}}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);selectionSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. swap函数:用于交换两个元素的值。
  2. selectionSort函数
    • 外层循环从第一个元素开始,依次选择未排序部分的最小元素。
    • 内层循环在未排序部分中找到最小元素的索引。
    • 将找到的最小元素与当前元素交换。
  3. printArray函数:用于打印数组的内容。
  4. main函数:测试选择排序的实现。

运行结果:

原始数组: 
64 25 12 22 11 
排序后的数组: 
11 12 22 25 64 

时间复杂度:

  • 最坏情况:O(n²)(无论数组是否有序,都需要进行完整的比较和交换)
  • 最好情况:O(n²)(即使数组已经有序,仍然需要进行完整的比较)
  • 平均情况:O(n²)

空间复杂度:

  • O(1)(原地排序,不需要额外空间)

选择排序的特点:

  1. 简单直观:实现简单,易于理解和实现。
  2. 不稳定排序:选择排序是不稳定的排序算法,可能会改变相同元素的相对顺序。
  3. 适合小规模数据:对于小规模数据,选择排序的效率尚可,但对于大规模数据效率较低。

优化版本:

选择排序的优化空间较小,但可以通过同时选择最小和最大元素来减少外层循环的次数。

// 优化版本:同时选择最小和最大元素
void selectionSortOptimized(int arr[], int n) {int i, j, min_idx, max_idx;for (i = 0; i < n / 2; i++) {min_idx = i;max_idx = i;// 在未排序部分中找到最小和最大元素的索引for (j = i + 1; j < n - i; j++) {if (arr[j] < arr[min_idx]) {min_idx = j;}if (arr[j] > arr[max_idx]) {max_idx = j;}}// 将最小元素放到前面if (min_idx != i) {swap(&arr[min_idx], &arr[i]);}// 如果最大元素的位置被影响,需要更新max_idxif (max_idx == i) {max_idx = min_idx;}// 将最大元素放到后面if (max_idx != n - i - 1) {swap(&arr[max_idx], &arr[n - i - 1]);}}
}

选择排序虽然简单,但在实际应用中效率较低,通常用于教学或小规模数据的排序。对于大规模数据,更高效的排序算法(如快速排序、归并排序等)更为适用。

归并排序

归并排序(Merge Sort)是一种高效的排序算法,采用分治法(Divide and Conquer)策略。它的核心思想是将数组分成两个子数组,分别对子数组进行排序,然后将排序后的子数组合并成一个有序数组。以下是使用C语言实现数组的归并排序的代码:


归并排序代码实现

#include <stdio.h>
#include <stdlib.h>// 合并两个有序子数组
void merge(int arr[], int left, int mid, int right) {int i, j, k;int n1 = mid - left + 1;  // 左子数组的大小int n2 = right - mid;     // 右子数组的大小// 创建临时数组int* L = (int*)malloc(n1 * sizeof(int));  // 左子数组int* R = (int*)malloc(n2 * sizeof(int));  // 右子数组// 将数据复制到临时数组for (i = 0; i < n1; i++) {L[i] = arr[left + i];}for (j = 0; j < n2; j++) {R[j] = arr[mid + 1 + j];}// 合并临时数组到原数组i = 0;  // 左子数组的索引j = 0;  // 右子数组的索引k = left;  // 合并后数组的索引while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;}k++;}// 复制左子数组剩余的元素while (i < n1) {arr[k] = L[i];i++;k++;}// 复制右子数组剩余的元素while (j < n2) {arr[k] = R[j];j++;k++;}// 释放临时数组的内存free(L);free(R);
}// 归并排序的递归函数
void mergeSort(int arr[], int left, int right) {if (left < right) {int mid = left + (right - left) / 2;  // 计算中间位置// 递归地对左子数组和右子数组进行排序mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);// 合并两个有序子数组merge(arr, left, mid, right);}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {12, 11, 13, 5, 6, 7};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);mergeSort(arr, 0, n - 1);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. merge函数
    • 合并两个有序子数组LR到原数组arr中。
    • 使用临时数组存储子数组的数据,然后按顺序合并到原数组。
  2. mergeSort函数
    • 递归地将数组分成两个子数组,分别对子数组进行排序。
    • 调用merge函数合并两个有序子数组。
  3. printArray函数:用于打印数组的内容。
  4. main函数:测试归并排序的实现。

运行结果:

原始数组: 
12 11 13 5 6 7 
排序后的数组: 
5 6 7 11 12 13 

时间复杂度:

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

空间复杂度:

  • O(n)(需要额外的临时数组存储数据)

归并排序的特点:

  1. 稳定排序:归并排序是稳定的排序算法,相同元素的相对顺序不会改变。
  2. 适合大规模数据:归并排序的时间复杂度为O(n log n),适合处理大规模数据。
  3. 分治法思想:通过递归将问题分解为更小的子问题,然后合并结果。

优化版本:

归并排序可以通过以下方式优化:

  1. 小规模数据使用插入排序:当子数组规模较小时,插入排序的效率更高。
  2. 避免频繁的内存分配:可以预先分配一个临时数组,避免在每次合并时分配内存。
// 优化版本:预先分配临时数组
void mergeSortOptimized(int arr[], int left, int right, int* temp) {if (left < right) {int mid = left + (right - left) / 2;// 递归地对左子数组和右子数组进行排序mergeSortOptimized(arr, left, mid, temp);mergeSortOptimized(arr, mid + 1, right, temp);// 合并两个有序子数组merge(arr, left, mid, right);}
}

归并排序是一种非常高效的排序算法,尤其适用于需要稳定排序的场景或处理大规模数据。

堆排序

堆排序(Heap Sort)是一种基于二叉堆(Binary Heap)数据结构的排序算法。它的核心思想是将数组构建成一个最大堆(或最小堆),然后逐步将堆顶元素(最大值或最小值)与堆的最后一个元素交换,并调整堆,直到整个数组有序。以下是使用C语言实现数组的堆排序的代码:


堆排序代码实现

#include <stdio.h>// 交换两个元素的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 调整堆,使其满足最大堆的性质
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) {swap(&arr[i], &arr[largest]);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--) {swap(&arr[0], &arr[i]);  // 将堆顶元素与堆的最后一个元素交换heapify(arr, i, 0);      // 调整堆,使其满足最大堆的性质}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {12, 11, 13, 5, 6, 7};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);heapSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. swap函数:用于交换两个元素的值。
  2. heapify函数
    • 调整堆,使其满足最大堆的性质。
    • 从根节点开始,比较根节点与其左右子节点,找到最大值。
    • 如果最大值不是根节点,交换根节点和最大值,并递归调整堆。
  3. heapSort函数
    • 构建最大堆:从最后一个非叶子节点开始,逐步调整堆。
    • 逐步将堆顶元素(最大值)与堆的最后一个元素交换,并调整堆。
  4. printArray函数:用于打印数组的内容。
  5. main函数:测试堆排序的实现。

运行结果:

原始数组: 
12 11 13 5 6 7 
排序后的数组: 
5 6 7 11 12 13 

时间复杂度:

  • 建堆过程:O(n)
  • 每次调整堆:O(log n)
  • 总时间复杂度:O(n log n)

空间复杂度:

  • O(1)(原地排序,不需要额外空间)

堆排序的特点:

  1. 不稳定排序:堆排序是不稳定的排序算法,可能会改变相同元素的相对顺序。
  2. 适合大规模数据:堆排序的时间复杂度为O(n log n),适合处理大规模数据。
  3. 基于二叉堆:利用二叉堆的性质实现排序。

优化版本:

堆排序的优化空间较小,但可以通过以下方式改进:

  1. 使用最小堆:如果需要升序排序,可以使用最小堆。
  2. 减少交换次数:在调整堆时,可以减少不必要的交换操作。

堆排序是一种高效的排序算法,尤其适用于需要原地排序的场景或处理大规模数据。

计数排序

计数排序(Counting Sort)是一种非比较型整数排序算法。它的核心思想是通过统计数组中每个元素的出现次数,然后根据统计结果将元素放回正确的位置。计数排序适用于元素范围较小且已知的情况。以下是使用C语言实现数组的计数排序的代码:


计数排序代码实现

#include <stdio.h>
#include <stdlib.h>// 计数排序函数
void countingSort(int arr[], int n) {// 找到数组中的最大值int max = arr[0];for (int i = 1; i < n; i++) {if (arr[i] > max) {max = arr[i];}}// 创建计数数组,并初始化为0int* count = (int*)calloc(max + 1, sizeof(int));// 统计每个元素的出现次数for (int i = 0; i < n; i++) {count[arr[i]]++;}// 将计数数组转换为前缀和数组for (int i = 1; i <= max; i++) {count[i] += count[i - 1];}// 创建输出数组int* output = (int*)malloc(n * sizeof(int));// 从后向前遍历原数组,将元素放入输出数组的正确位置for (int i = n - 1; i >= 0; i--) {output[count[arr[i]] - 1] = arr[i];count[arr[i]]--;}// 将输出数组的内容复制回原数组for (int i = 0; i < n; i++) {arr[i] = output[i];}// 释放动态分配的内存free(count);free(output);
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {4, 2, 2, 8, 3, 3, 1};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);countingSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. countingSort函数
    • 找到数组中的最大值,确定计数数组的大小。
    • 创建计数数组,统计每个元素的出现次数。
    • 将计数数组转换为前缀和数组,表示每个元素在输出数组中的位置。
    • 从后向前遍历原数组,将元素放入输出数组的正确位置。
    • 将输出数组的内容复制回原数组。
  2. printArray函数:用于打印数组的内容。
  3. main函数:测试计数排序的实现。

运行结果:

原始数组: 
4 2 2 8 3 3 1 
排序后的数组: 
1 2 2 3 3 4 8 

时间复杂度:

  • 时间复杂度:O(n + k),其中n是数组长度,k是数组中元素的最大值。
  • 空间复杂度:O(n + k)(需要额外的计数数组和输出数组)。

计数排序的特点:

  1. 非比较排序:计数排序不直接比较元素的大小,而是通过统计元素的出现次数进行排序。
  2. 稳定排序:计数排序是稳定的排序算法,相同元素的相对顺序不会改变。
  3. 适合小范围整数排序:计数排序适用于元素范围较小且已知的情况。

优化版本:

计数排序的优化可以通过以下方式实现:

  1. 减少空间占用:如果元素范围较大,可以使用哈希表或其他方法减少计数数组的大小。
  2. 处理负数:如果需要处理负数,可以将数组中的元素统一加上一个偏移量,使其变为非负数。

以下是处理负数的优化版本:

void countingSortWithNegative(int arr[], int n) {// 找到数组中的最小值和最大值int min = arr[0], max = arr[0];for (int i = 1; i < n; i++) {if (arr[i] < min) {min = arr[i];}if (arr[i] > max) {max = arr[i];}}// 计算偏移量int range = max - min + 1;// 创建计数数组,并初始化为0int* count = (int*)calloc(range, 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];}// 创建输出数组int* output = (int*)malloc(n * sizeof(int));// 从后向前遍历原数组,将元素放入输出数组的正确位置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);
}

计数排序是一种高效的排序算法,尤其适用于元素范围较小的情况。对于元素范围较大的情况,可以考虑使用其他排序算法(如快速排序或归并排序)。

基数排序

基数排序(Radix Sort)是一种非比较型整数排序算法。它的核心思想是将整数按位数切割成不同的数字,然后按每个位数分别进行排序(通常使用计数排序或桶排序作为子排序算法)。基数排序适用于整数或字符串的排序。以下是使用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 = (int*)malloc(n * sizeof(int));  // 输出数组int count[10] = {0};  // 计数数组,初始化为0// 统计每个数字出现的次数for (int i = 0; i < n; i++) {count[(arr[i] / exp) % 10]++;}// 将计数数组转换为前缀和数组for (int i = 1; i < 10; i++) {count[i] += count[i - 1];}// 从后向前遍历原数组,将元素放入输出数组的正确位置for (int i = n - 1; i >= 0; i--) {output[count[(arr[i] / exp) % 10] - 1] = arr[i];count[(arr[i] / exp) % 10]--;}// 将输出数组的内容复制回原数组for (int i = 0; i < n; i++) {arr[i] = output[i];}// 释放动态分配的内存free(output);
}// 基数排序函数
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 size) {for (int i = 0; i < size; 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("原始数组: \n");printArray(arr, n);radixSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. getMax函数:获取数组中的最大值,用于确定需要排序的位数。
  2. countingSort函数
    • 对数组按指定位数(exp)进行计数排序。
    • 使用计数数组统计每个数字出现的次数,并将其转换为前缀和数组。
    • 从后向前遍历原数组,将元素放入输出数组的正确位置。
  3. radixSort函数
    • 获取数组中的最大值,确定需要排序的位数。
    • 对每个位数调用countingSort函数进行排序。
  4. printArray函数:用于打印数组的内容。
  5. main函数:测试基数排序的实现。

运行结果:

原始数组: 
170 45 75 90 802 24 2 66 
排序后的数组: 
2 24 45 66 75 90 170 802 

时间复杂度:

  • 时间复杂度:O(d * (n + k)),其中d是最大数字的位数,n是数组长度,k是基数(通常为10)。
  • 空间复杂度:O(n + k)(需要额外的计数数组和输出数组)。

基数排序的特点:

  1. 非比较排序:基数排序不直接比较元素的大小,而是通过按位数排序。
  2. 稳定排序:基数排序是稳定的排序算法,相同元素的相对顺序不会改变。
  3. 适合整数或字符串排序:基数排序适用于整数或固定长度的字符串排序。

优化版本:

基数排序的优化空间较小,但可以通过以下方式改进:

  1. 使用桶排序:在某些情况下,可以使用桶排序代替计数排序作为子排序算法。
  2. 处理负数:如果需要处理负数,可以将数组分为正数和负数两部分,分别进行基数排序。

基数排序是一种高效的排序算法,尤其适用于整数或字符串的排序场景。

桶排序

桶排序(Bucket Sort)是一种分布式排序算法,它将数组分到有限数量的桶中,每个桶再分别排序(通常使用插入排序或其他排序算法),最后将各个桶中的元素合并成有序数组。以下是使用C语言实现数组的桶排序的代码:


桶排序代码实现

#include <stdio.h>
#include <stdlib.h>// 定义桶的数量
#define BUCKET_SIZE 10// 定义链表节点
typedef struct Node {float data;struct Node* next;
} Node;// 插入节点到链表中(按升序插入)
Node* insert(Node* head, float value) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = value;newNode->next = NULL;if (head == NULL || head->data >= value) {newNode->next = head;head = newNode;} else {Node* current = head;while (current->next != NULL && current->next->data < value) {current = current->next;}newNode->next = current->next;current->next = newNode;}return head;
}// 桶排序函数
void bucketSort(float arr[], int n) {// 创建桶数组Node* buckets[BUCKET_SIZE] = {NULL};// 将元素分配到桶中for (int i = 0; i < n; i++) {int bucketIndex = (int)(arr[i] * BUCKET_SIZE);  // 计算桶的索引buckets[bucketIndex] = insert(buckets[bucketIndex], arr[i]);}// 将桶中的元素合并到原数组int index = 0;for (int i = 0; i < BUCKET_SIZE; i++) {Node* current = buckets[i];while (current != NULL) {arr[index++] = current->data;current = current->next;}}
}// 打印数组
void printArray(float arr[], int size) {for (int i = 0; i < size; i++) {printf("%.2f ", arr[i]);}printf("\n");
}// 主函数
int main() {float arr[] = {0.42, 0.32, 0.75, 0.12, 0.89, 0.63, 0.25, 0.55};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);bucketSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. Node结构体:定义链表节点,用于存储桶中的元素。
  2. insert函数
    • 将元素按升序插入到链表中。
    • 如果链表为空或当前元素小于链表头节点,则插入到链表头部。
    • 否则,遍历链表找到合适的插入位置。
  3. bucketSort函数
    • 创建桶数组,每个桶是一个链表。
    • 将数组中的元素分配到对应的桶中。
    • 对每个桶中的元素进行排序(通过插入排序实现)。
    • 将各个桶中的元素合并到原数组。
  4. printArray函数:用于打印数组的内容。
  5. main函数:测试桶排序的实现。

运行结果:

原始数组: 
0.42 0.32 0.75 0.12 0.89 0.63 0.25 0.55 
排序后的数组: 
0.12 0.25 0.32 0.42 0.55 0.63 0.75 0.89 

时间复杂度:

  • 平均情况:O(n + k),其中n是数组长度,k是桶的数量。
  • 最坏情况:O(n²)(当所有元素都分配到同一个桶时)。
  • 最好情况:O(n)(当元素均匀分布在各个桶中时)。

空间复杂度:

  • O(n + k)(需要额外的桶数组和链表节点)。

桶排序的特点:

  1. 分布式排序:将元素分配到多个桶中,分别排序后再合并。
  2. 适合均匀分布的数据:当元素均匀分布在各个桶中时,桶排序的效率较高。
  3. 稳定排序:如果使用的子排序算法是稳定的,桶排序也是稳定的。

优化版本:

桶排序的优化可以通过以下方式实现:

  1. 动态调整桶的数量:根据数据的分布动态调整桶的数量,避免所有元素都分配到同一个桶中。
  2. 使用更高效的子排序算法:例如使用快速排序或归并排序代替插入排序。

桶排序是一种高效的排序算法,尤其适用于数据分布均匀的场景。对于非均匀分布的数据,桶排序的性能可能会下降。

希尔排序

希尔排序(Shell Sort)是插入排序的一种改进版本,也称为缩小增量排序。它的核心思想是通过将数组分成若干个子序列,对每个子序列进行插入排序,然后逐步缩小子序列的间隔,最终对整个数组进行一次插入排序。希尔排序的时间复杂度优于普通的插入排序。以下是使用C语言实现数组的希尔排序的代码:


希尔排序代码实现

#include <stdio.h>// 希尔排序函数
void shellSort(int arr[], int n) {// 初始间隔(gap)为数组长度的一半,逐步缩小间隔for (int gap = n / 2; gap > 0; gap /= 2) {// 对每个子序列进行插入排序for (int i = gap; i < n; i++) {int temp = arr[i];  // 当前需要插入的元素int j;// 将比temp大的元素向后移动for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {arr[j] = arr[j - gap];}arr[j] = temp;  // 插入temp到正确位置}}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 主函数
int main() {int arr[] = {12, 34, 54, 2, 3};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);shellSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

代码说明:

  1. shellSort函数
    • 初始间隔(gap)为数组长度的一半,逐步缩小间隔。
    • 对每个子序列进行插入排序。
    • 将比当前元素大的元素向后移动,直到找到当前元素的正确位置。
  2. printArray函数:用于打印数组的内容。
  3. main函数:测试希尔排序的实现。

运行结果:

原始数组: 
12 34 54 2 3 
排序后的数组: 
2 3 12 34 54 

时间复杂度:

  • 最坏情况:O(n²)(取决于间隔序列的选择)。
  • 平均情况:O(n log n) 到 O(n^(3/2))。
  • 最好情况:O(n log n)。

空间复杂度:

  • O(1)(原地排序,不需要额外空间)。

希尔排序的特点:

  1. 改进的插入排序:通过分组插入排序,减少了元素的移动次数。
  2. 不稳定排序:希尔排序是不稳定的排序算法,可能会改变相同元素的相对顺序。
  3. 适合中等规模数据:希尔排序的效率高于普通的插入排序,适合中等规模的数据排序。

优化版本:

希尔排序的性能取决于间隔序列的选择。常见的间隔序列有:

  1. 希尔原始序列gap = n / 2, gap /= 2
  2. Hibbard序列gap = 2^k - 1
  3. Sedgewick序列gap = 9 * 4^i - 9 * 2^i + 1gap = 4^i + 3 * 2^i + 1

以下是使用Hibbard序列的优化版本:

// 使用Hibbard序列的希尔排序
void shellSortHibbard(int arr[], int n) {// 计算Hibbard序列的最大值int k = 1;while ((1 << k) - 1 < n) {k++;}// 使用Hibbard序列作为间隔for (int gap = (1 << k) - 1; gap > 0; gap = (1 << (--k)) - 1) {for (int i = gap; i < n; i++) {int temp = arr[i];int j;for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {arr[j] = arr[j - gap];}arr[j] = temp;}}
}

希尔排序是一种高效的排序算法,尤其适用于中等规模数据的排序。通过选择合适的间隔序列,可以进一步提高其性能。

总结

以下是常见排序算法的比较表格,包括时间复杂度、空间复杂度、稳定性以及适用场景等信息:

排序算法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度是否稳定适用场景
QuickO(n log n)O(n²)O(n log n)O(log n)不稳定大规模数据,通用排序
BubbleO(n²)O(n²)O(n)O(1)稳定小规模数据,教学用途
InsertO(n²)O(n²)O(n)O(1)稳定小规模或部分有序数据
SelectO(n²)O(n²)O(n²)O(1)不稳定小规模数据,简单实现
MergeO(n log n)O(n log n)O(n log n)O(n)稳定大规模数据,稳定排序需求
HeapO(n log n)O(n log n)O(n log n)O(1)不稳定大规模数据,原地排序需求
CountO(n + k)O(n + k)O(n + k)O(n + k)稳定小范围整数排序
RadixO(d(n + k))O(d(n + k))O(d(n + k))O(n + k)稳定整数或字符串排序,位数较小
BucketO(n + k)O(n²)O(n)O(n + k)稳定均匀分布的数据
ShellO(n log n)O(n²)O(n log n)O(1)不稳定中等规模数据,改进的插入排序

表格说明:

  1. 时间复杂度
    • 平均:算法在大多数情况下的性能。
    • 最坏:算法在最差情况下的性能。
    • 最好:算法在最优情况下的性能。
  2. 空间复杂度:算法所需的额外空间。
  3. 稳定性:排序后相同元素的相对顺序是否保持不变。
  4. 适用场景:算法最适合的应用场景。

总结:

  • Quick Sort:通用高效,适合大规模数据,但不稳定。
  • Bubble Sort:简单但效率低,适合小规模数据或教学用途。
  • Insertion Sort:适合小规模或部分有序数据,稳定。
  • Selection Sort:简单但效率低,适合小规模数据。
  • Merge Sort:稳定且高效,适合大规模数据,但需要额外空间。
  • Heap Sort:原地排序,适合大规模数据,但不稳定。
  • Counting Sort:适合小范围整数排序,稳定。
  • Radix Sort:适合整数或字符串排序,稳定。
  • Bucket Sort:适合均匀分布的数据,稳定。
  • Shell Sort:改进的插入排序,适合中等规模数据。

根据具体需求选择合适的排序算法可以提高程序的效率。

相关文章:

数组排序算法

数组排序算法 用C语言实现的数组排序算法。 排序算法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度是否稳定适用场景QuickO(n log n)O(n)O(n log n)O(log n)不稳定大规模数据&#xff0c;通用排序BubbleO(n)O(n)O(n)O(1)稳定小规模数据&#xff0c;教学用途InsertO(n)…...

利用腾讯云cloud studio云端免费部署deepseek-R1

1. cloud studio 1.1 cloud studio介绍 Cloud Studio&#xff08;云端 IDE&#xff09;是基于浏览器的集成式开发环境&#xff0c;为开发者提供了一个稳定的云端工作站。支持CPU与GPU的访问。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器即可使用。Clo…...

Codeforces Round 1002 (Div. 2)(A-D)

题目链接&#xff1a;Dashboard - Codeforces Round 1002 (Div. 2) - Codeforces A. Milya and Two Arrays 思路 数组a中不同数的数量*数组b的&#xff0c;就是能够组成不同数的数量 代码 void solve(){int n;cin>>n;int cnt10;int cnt20;map<int,bool> mp;ma…...

半导体器件与物理篇7 微波二极管、量子效应和热电子器件

基本微波技术 微波频率&#xff1a;微波频率涵盖约从0.1GHz到3000GHz&#xff0c;相当于波长从300cm到0.01cm。 分布效应&#xff1a;电子部件在微波频率&#xff0c;与其在较低频率的工作行为不同。 输运线&#xff1a;一个由电阻、电容、电感三种等效基本电路部件所组成的…...

Hot100之图论

200岛屿数量 题目 思路解析 把访问过的格子插上棋子 思想是先污染再治理&#xff0c;我们有一个inArea&#xff08;&#xff09;函数&#xff0c;是判断是否出界了 我们先dfs&#xff08;&#xff09;放各个方向遍历&#xff0c;然后我们再把这个位置标为0 我们岛屿是连着…...

CSS 样式化表格:从基础到高级技巧

CSS 样式化表格&#xff1a;从基础到高级技巧 1. 典型的 HTML 表格结构2. 为表格添加样式2.1 间距和布局2.2 简单的排版2.3 图形和颜色2.4 斑马条纹2.5 样式化标题 3. 完整的示例代码4. 总结 在网页设计中&#xff0c;表格是展示数据的常见方式。然而&#xff0c;默认的表格样式…...

DeepSeek相关技术整理

相关介绍 2024年12月26日&#xff0c;DeepSeek V3模型发布&#xff08;用更低的训练成本&#xff0c;训练出更好的效果&#xff09;671B参数&#xff0c;激活37B。2025年1月20日&#xff0c;DeepSeek-R1模型发布&#xff08;仅需少量标注数据&#xff08;高质量长cot&#xff…...

Spring Boot框架下的单元测试

1. 什么是单元测试 1.1 基本定义 单元测试(Unit Test) 是对软件开发中最小可测单位&#xff08;例如一个方法或者一个类&#xff09;进行验证的一种测试方式。在 Java 后端的 Spring Boot 项目中&#xff0c;单元测试通常会借助 JUnit、Mockito 等框架对代码中核心逻辑进行快…...

OpenAI 实战进阶教程 - 第四节: 结合 Web 服务:构建 Flask API 网关

目标 学习将 OpenAI 接入 Web 应用&#xff0c;构建交互式 API 网关理解 Flask 框架的基本用法实现 GPT 模型的 API 集成并返回结果 内容与实操 一、环境准备 安装必要依赖&#xff1a; 打开终端或命令行&#xff0c;执行以下命令安装 Flask 和 OpenAI SDK&#xff1a; pip i…...

xss-labs靶场

xss-labs靶场 xss攻击类型 反射型xss 即攻击者将恶意脚本嵌入到url或者表单中&#xff0c;当用户访问特定的url或者提交表单时&#xff08;用户端请求时)&#xff0c;恶意脚本会执行 攻击需要用户点击恶意链接或访问包含恶意参数的url触发 存储型xss 即攻击者将恶意脚本提交…...

Eigen::Tensor使用帮助

0 引言 用python实现了某些算法之后&#xff0c;想转成C来获取更高的性能。但是python数组的操作太灵活了&#xff0c;尤其是3维、4维、5维等高维数组&#xff0c;以及它们的广播、数组坐标、切片等机制。还有numpy的pad、where等操作更是给C转换带来了更多的麻烦。 查阅了相…...

高阶开发基础——快速入门C++并发编程4

目录 使用call_once来确保调用的唯一性 先看我们的原始的单例模式 使用call_once来确保调用的唯一性 一个相似的概念是——单例模式&#xff0c;笔者找到的是stack_overflow的一个问答&#xff0c;如果不喜欢看英文&#xff0c;可以考虑看一下这个CSDN回答&#xff1a; c - H…...

C++基础day1

前言&#xff1a;谢谢阿秀&#xff0c;指路阿秀的学习笔记 一、基础语法 1.构造和析构: 类的构造函数是一种特殊的函数&#xff0c;在创建一个新的对象时调用。类的析构函数也是一种特殊的函数&#xff0c;在删除所创建的对象时调用。 构造顺序&#xff1a;父类->子类 析…...

Deepseek:网页版OR本地部署版本?

使用本地部署的 DeepSeek 还是网页版的 DeepSeek&#xff0c;取决于具体需求和使用场景。以下是两者的对比及推荐建议&#xff1a; 响应速度 网页版 DeepSeek&#xff1a;响应速度受网络状况和服务器负载影响较大。如果网络不稳定或服务器繁忙&#xff0c;可能会出现延迟甚至…...

【文件上传】

目录 一. 介绍二. 本地存储三. 阿里云OSS3.1 准备工作3.2 入门程序3.3 案例集成3.4 程序优化 \quad 一. 介绍 \quad 三要素缺一不可 \quad 二. 本地存储 \quad 解决相同命名覆盖问题 \quad 三. 阿里云OSS \quad \quad 3.1 准备工作 \quad \quad 3.2 入门程序 \quad \quad 3.3…...

股票入门知识

股票入门&#xff08;更适合中国宝宝体制&#xff09; 股市基础知识 本文介绍了股票的基础知识&#xff0c;股票的分类&#xff0c;各板块发行上市条件&#xff0c;股票代码&#xff0c;交易时间&#xff0c;交易规则&#xff0c;炒股术语&#xff0c;影响股价的因素&#xf…...

Debezium Oracle Connector SCN处理优化指南

Debezium Oracle Connector SCN处理优化指南 📌 问题场景 SCN跳跃场景: 起始SCN:15,000(含数据变更)结束SCN:1,000,000(无中间数据)默认批次大小:10,000 → 需执行985次无效查询🚀 优化方案 1. 自适应批次调整 代码位置:LogMinerStreamingChangeEventSource.j…...

2021版小程序开发5——小程序项目开发实践(1)

2021版小程序开发5——小程序项目开发实践(1) 学习笔记 2025 使用uni-app开发一个电商项目&#xff1b; Hbuidler 首选uni-app官方推荐工具&#xff1a;https://www.dcloud.io/hbuilderx.htmlhttps://dev.dcloud.net.cn/pages/app/list 微信小程序 管理后台&#xff1a;htt…...

软件测试02----用例设计方法

今天目标 1.能对穷举场景设计测试点 2.能对限定边界规则设计测试点 3.能对多条件依赖关系进行设计测试点 4.能对项目业务进行设计测试点 一、解决穷举场景 重点&#xff1a;使用等价类划分法 1.1等价类划分法 重点&#xff1a;有效等价和单个无效等价各取1个即可。 步骤&#…...

分享半导体Fab 缺陷查看系统,平替klarity defect系统

分享半导体Fab 缺陷查看系统&#xff0c;平替klarity defect系统&#xff1b;开发了半年有余。 查看Defect Map&#xff0c;Defect image&#xff0c;分析Defect size&#xff0c;defect count trend. 不用再采用klarity defect系统&#xff08;license 太贵&#xff09; 也可以…...

C语言-----数据结构从门到精通

1.数据结构基本概念 数据结构是计算机中存储、组织数据的方式&#xff0c;旨在提高数据的访问和操作效率。它是实现高效算法和程序设计的基石。 目标:通过思维导图了解数据结构的知识点,并掌握。 1.1逻辑结构 逻辑结构主要四种类型: 集合&#xff1a;结构中的数据元素之…...

存储器知识点3

1.只读存储器中内容断电后不会丢失&#xff0c;通常存储固定不变的内容&#xff0c;不需要定时刷新。 2.虚拟存储器将主存和辅存地址空间统一编址&#xff0c;其大小受到辅助存储器容量的限制。使得主存空间得到了扩充&#xff0c;需要硬件支持&#xff0c;并由操作系统调度。…...

Weevely代码分析

亲测php5和php8都无效&#xff0c;只有php7有效 ailx10 1949 次咨询 4.9 网络安全优秀回答者 互联网行业 安全攻防员 去咨询 上一次做weevely实验可以追溯到2020年&#xff0c;当时还是weevely3.7&#xff0c;现在的是weevely4 生成php网页木马依然差不多…… php菜刀we…...

leetcode解题思路分析(一百六十三)1409 - 1415 题

查询带键的排列 给定一个正整数数组 queries &#xff0c;其取值范围在 1 到 m 之间。 请你根据以下规则按顺序处理所有 queries[i]&#xff08;从 i0 到 iqueries.length-1&#xff09;&#xff1a; 首先&#xff0c;你有一个排列 P[1,2,3,…,m]。 对于当前的 i &#xff0c;找…...

【MATLAB例程】TOA和AOA混合的高精度定位程序,适用于三维、N锚点的情况

代码实现了一个基于到达角&#xff08;AOA&#xff09;和到达时间&#xff08;TOA&#xff09;混合定位的例程。该算法能够根据不同基站接收到的信号信息&#xff0c;自适应地计算目标的位置&#xff0c;适用于多个基站的场景 文章目录 主要功能代码结构运行结果程序代码 主要功…...

PyTorch框架——基于深度学习YOLOv8神经网络学生课堂行为检测识别系统

基于YOLOv8深度学习的学生课堂行为检测识别系统&#xff0c;其能识别三种学生课堂行为&#xff1a;names: [举手, 读书, 写字] 具体图片见如下&#xff1a; 第一步&#xff1a;YOLOv8介绍 YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本…...

智慧园区系统对比不同智能管理模式提升企业运营效率与安全性

内容概要 在当今竞争激烈的市场中&#xff0c;企业需要不断提高运营效率与安全性&#xff0c;以应对复杂的环境。这时&#xff0c;“智慧园区系统”应运而生&#xff0c;成为一种有效的解决方案。智能管理模式的多样性让企业在选择系统时有了更多的选择&#xff0c;而在这些模…...

读书笔记 | 《最小阻力之路》:用结构思维重塑人生愿景

一、核心理念&#xff1a;结构决定行为轨迹 橡皮筋模型&#xff1a;愿景张力的本质 书中提出&#xff1a;人类行为始终沿着"现状"与"愿景"之间的张力路径运动&#xff0c;如同橡皮筋拉伸产生的动力。 案例&#xff1a;音乐家每日练习的坚持&#xff0c;不…...

257. 二叉树的所有路径

二叉树的所有路径 已解答 简单 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,null,5] 输出&#xff1a;[“1->2->5”,“…...

Vulkan 学习(13)---- Vulkan Framebuffercommand buffer

目录 Vulkan Framebuffer创建 VkFramebufferVkFrameBuffer 创建示例 Vulkan command buffercommand buffer pool分配指令缓存池释放指令缓存池录制 command buffer提交 command buffer Vulkan Framebuffer Vulkan 帧缓冲区(FrameBuffer) 是一个容器对象(资源管理类的对象)&…...

从零开始学习安时积分法(STM32实现程序)

在STM32微控制器上实现安时积分法&#xff08;Coulomb Counting&#xff09;来估算电池的SOC&#xff08;State of Charge&#xff09;&#xff0c;需要完成以下几个步骤&#xff1a; 硬件配置&#xff1a; 使用STM32的ADC模块测量电池的电流。使用定时器模块进行时间积分。配置…...

基于Kamailio、MySQL、Redis、Gin、Vue.js的微服务架构

每个服务使用一台独立的服务器的可行部署方案&#xff0c;尤其是在高并发、高可用性要求较高的场景中。这种方案通常被称为分布式部署或微服务架构。以下是针对您的VoIP管理系统&#xff08;基于Kamailio、MySQL、Redis、Gin、Vue.js&#xff09;的详细分析和建议。 1. 分布式部…...

Unity 粒子特效在UI中使用裁剪效果

1.使用Sprite Mask 首先建立一个粒子特效在UI中显示 新建一个在场景下新建一个空物体&#xff0c;添加Sprite Mask组件&#xff0c;将其的Layer设置为UI相机渲染的UI层&#xff0c; 并将其添加到Canvas子物体中&#xff0c;调整好大小&#xff0c;并选择合适的Sprite&#xff…...

Android 开发:新的一年,新的征程

回顾 2023 年&#xff0c;Android 开发领域可谓成果斐然。这一年&#xff0c;Android 系统不断迭代&#xff0c;新技术、新工具层出不穷&#xff0c;为开发者们带来了前所未有的机遇与挑战。如今&#xff0c;我们站在新的起点&#xff0c;怀揣着对技术的热爱与追求&#xff0c;…...

手写MVVM框架-环境搭建

项目使用 webpack 进行进行构建&#xff0c;初始化步骤如下: 1.创建npm项目执行npm init 一直下一步就行 2.安装webpack、webpack-cli、webpack-dev-server&#xff0c;html-webpack-plugin npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin 3.配置webpac…...

SQL进阶实战技巧:某芯片工厂设备任务排产调度分析 | 间隙分析技术应用

目录 0 技术定义与核心原理 1 场景描述 2 数据准备 3 间隙分析法 步骤1:原始时间线可视化...

[HOT 100] 0167. 两数之和 ||

文章目录 1. 题目链接2. 题目描述3. 题目示例4. 解题思路5. 题解代码6. 复杂度分析 1. 题目链接 167. 两数之和 II - 输入有序数组 - 力扣&#xff08;LeetCode&#xff09; 2. 题目描述 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &…...

CSS整体回顾

一. 邂逅CSS和常见的CSS 1.1. CSS的编写方式 1.2. 常见的CSS font-size/color/width/height/backgroundColor 二. 文本属性 2.1. text-decoration 2.2. text-indent 2.3. text-align 三. 字体属性 3.1. font-family 3.2. font-style 3.3. font-weight 3.4. font-size 3.5. …...

使用 Grafana 和 Prometheus展现消息队列性能

引言 上篇文章通过JMX提取Kafka数据&#xff0c;本篇文章将通过JDBC存储Kafka性能数据存储于数据库&#xff0c;并通过Grafana 和 Prometheus进行展示&#xff0c;实现开发中常用的可视化监控 1. 环境准备 Kafka&#xff1a;运行中的 Kafka 集群&#xff0c;确保可以…...

openssl 生成证书 windows导入证书

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…...

Skyeye 云 VUE 版本 v3.15.6 发布

Skyeye 云智能制造&#xff0c;采用 Springboot winUI 的低代码平台、移动端采用 UNI-APP。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公告、问卷、报表…...

25.2.3 【洛谷】作为栈的复习不错(学习记录)

今天学习的东西不算多&#xff0c;放了一个星期假&#xff0c;感觉不少东西都没那么清楚&#xff0c;得复习一下才行。今天搞个栈题写&#xff0c;把栈复习一下&#xff0c;明天进入正轨&#xff0c;边复习边学习新东西&#xff0c;应该会有二叉树的学习等等... 【洛谷】P1449 …...

【C++】线程池实现

目录 一、线程池简介线程池的核心组件实现步骤 二、C11实现线程池源码 三、线程池源码解析1. 成员变量2. 构造函数2.1 线程初始化2.2 工作线程逻辑 3. 任务提交(enqueue方法)3.1 方法签名3.2 任务封装3.3 任务入队 4. 析构函数4.1 停机控制 5. 关键技术点解析5.1 完美转发实现5…...

大模型领域的Scaling Law的含义及作用

Scaling Law就像是一个“长大公式”&#xff0c;用来预测当一个东西&#xff08;比如模型&#xff09;变大&#xff08;比如增加参数、数据量&#xff09;时&#xff0c;它的性能&#xff08;比如准确率&#xff09;会怎么变化。 它能帮助我们提前知道&#xff0c;增加多少资源…...

用FormLinker实现自动调整数据格式,批量导入微软表单

每天早上打开Excel时&#xff0c;你是否也经历过这样的噩梦&#xff1f; 熬夜调整好的问卷格式&#xff0c;导入微软表单后全乱套 客户发来的PDF反馈表&#xff0c;手动录入3小时才完成10% 200道题库要转为在线测试&#xff0c;复制粘贴到手指抽筋 微软官方数据显示&#xf…...

C#,shell32 + 调用控制面板项(.Cpl)实现“新建快捷方式对话框”(全网首发)

Made By 于子轩&#xff0c;2025.2.2 不管是使用System.IO命名空间下的File类来创建快捷方式文件&#xff0c;或是使用Windows Script Host对象创建快捷方式&#xff0c;亦或是使用Shell32对象创建快捷方式&#xff0c;都对用户很不友好&#xff0c;今天小编为大家带来一种全新…...

洛谷 P11626 题解

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription] 给定长度为 n n n 的数组 A 1 ⋯ n A_{1 \cdots n} A1⋯n​&#xff0c;求 ∑ a 1 n ∑ b a 1 n ∑ c b 1 n ∑ d c 1 n ∑ e d 1 n ∑ f e 1 n ∑ g f 1 n ( gcd …...

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频&#xff0c;esp01S的收发硬件代码目前没有分享&#xff0c;但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…...

一文读懂 RAG:LLM 借助检索打开思路

一、引言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;随着深度学习技术的飞速发展&#xff0c;大型语言模型&#xff08;LLMs&#xff09;展现出了强大的语言理解和生成能力。然而&#xff0c;LLMs也存在一些局限性&#xff0c;如容易产生幻觉、知识更新不及时…...

使用istio实现权重路由

istio概述 **概述&#xff1a;**Istio 是一个开源的 服务网格&#xff08;Service Mesh&#xff09;解决方案&#xff0c;主要用于管理、保护和监控微服务架构中的服务通信。它为微服务提供了基础设施层的控制功能&#xff0c;不需要更改应用程序的代码&#xff0c;从而解决服…...