数据结构之五:排序

news2024/12/14 15:40:44

  void*类型的实现:排序(void*类型)-CSDN博客

一、插入排序

1、直接插入排序

思想:把待排序的数据逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

单趟

整体: 

实现

void InsertSort(int* arr, int sz) {
    assert(arr);
    int i = 0;
    for (i = 0; i < sz - 1; i++) {
        // 单趟:
        int end = i; // 有序序列的最后一个值
        int tmp = arr[end + 1];
        // 把end后面的第一个数据 往 0~end这个有序区间中插入
        while (end >= 0) {
            if (tmp < arr[end]) {
                arr[end + 1] = arr[end];
                end--;
            } else {
                break;
            }
        }
        arr[end + 1] = tmp;
    }
}
 2、希尔排序

希尔排序本质上是对直接插入排序的优化。

 代码实现:

void ShellSort(int* arr, int n) {
    // 1.gap>1相当于预排序,让数组接近有序
    // 2.gap==1相当于直接排序,保证有序
    int gap = n;
    int i = 0;
    while (gap > 1) {
        gap = gap / 3 + 1; // +1保证了最后一次gap一定是1
        // gap==1 最后一次就相当于直接插入排序
        // gap /= 2:效果没有/3好
        for (i = 0; i < n - gap; i++) {
            int end = i;
            int tmp = arr[end + gap];
            while (end >= 0) {
                if (tmp < arr[end]) {
                    arr[end + gap] = arr[end];
                    end -= gap;
                } else {
                    break;
                }
                arr[end + gap] = tmp;
            }
        }
    }
}

对希尔排序多组并排的一个理解: 

  •  希尔排序的时间复杂度在O(N^1.3~N^2)之间。
  • 当且仅当待排数据有序的情况下希尔排序的时间复杂度于直接插入排序。

二、选择排序

 1、直接选择排序

思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。(每次选一个数放到,放到新的位置)。

直接选择排序是很基础的一个排序,实现:

// 选择排序
// 优化,一次选两个数(最大和最小)放在合适位置
void SelectSort(int* arr, int n) {
    assert(arr);
    int begin = 0;
    int end = n - 1;
    while (begin < end) {
        // 在begin和end之间找出最大的数和最小的数的下标
        int maxi = begin;
        int mini = begin;
        int i = 0;
        for (i = begin + 1; i <= end; i++) {
            if (arr[maxi] < arr[i]) {
                maxi = i;
            }
            if (arr[mini] > arr[i]) {
                mini = i;
            }
        }
        Swap(&arr[begin], &arr[mini]);
        // 如果maxi和begin重叠,则maxi的值需要修正。
        if (begin == maxi) {
            maxi = mini;
        }
        Swap(&arr[end], &arr[maxi]);
        begin++;
        end--;
    }
}

时间复杂度:

  • T(N)=N*(N/2)=1/2*N^2,(优化后是N*N/2,优化前是N*N)。
  • 即:O(N^2) 。
2、堆排序

思路:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建小堆,排降序建大堆

直接实现:(在堆中有过讲解)

// 向下调整算法
void AdjustDown(int* arr, int n, int root) {
    int parent = root;
    int child = 2 * parent + 1;

    while (child < n) {
        if (child + 1 < n && arr[child] < arr[child + 1]) {
            child++;
        }
        if (arr[parent] < arr[child]) {
            Swap(&arr[parent], &arr[child]);
            parent = child;
            child = parent * 2 + 1;
        } else {
            break;
        }
    }
}
void HeapSort(int* arr, int n) {
    // 排升序,建大堆
    int i = 0;
    for (i = (n - 1 - 1) / 2; i >= 0; i--) {
        AdjustDown(arr, n, i); // 把arr调整为大堆
    }

    for (i = n - 1; i >= 0; i--) {
        Swap(&arr[i], &arr[0]);
        AdjustDown(arr, i, 0); // 排序
    }
}

三、交换排序

基本思想:交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置。

交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

1、冒泡排序

实现:

void BubbleSort(int* arr, int n) {
    int end = n;
    while (end > 0) {
        int exchange = 0;
        // 一趟
        for (int i = 1; i < end; i++) {
            if (arr[i - 1] > arr[i]) {
                Swap(&arr[i - 1], &arr[i]);
                exchange = 1;
            }
        }
        //优化:
        // 如果一趟冒泡的过程中没有发生交换,则前部分已经有序,不需要在冒泡
        if (exchange == 0) {
            break;
        }
        end--;
    }
}
2、快速排序

        快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。(找到一个key,左边必key小,右边比key大:升序)。

a.递归

实现:

// 三数取中:找到不大不小的数,让排有序时变为最优
int GetMidIndex(int* a, int begin, int end) {
    int mid = (begin + end) / 2;
    if (a[begin] < a[mid]) {
        if (a[mid] < a[end]) {
            return mid;
        } else if (a[begin] > a[end]) {
            return begin;
        } else {
            return end;
        }
    } else {
        if (a[mid] > a[end]) {
            return mid;
        } else if (a[begin] < a[end]) {
            return begin;
        } else {
            return end;
        }
    }
}

int PartSort1(int* a, int begin, int end){//单趟快排1: 左右指针法
    // 三数取中的优化
    int midIndex = GetMidIndex(a, begin, end);
    Swap(&a[midIndex], &a[end]);

    int key = a[end];
    int keyindex = end;
    // 如果是右边做key,那么一定让左边先走,这样保证它们相遇的位置会比key大
    while (begin < end) {
        while (begin < end && a[begin] <= key) {
            begin++;
        }
        while (begin < end && a[end] >= key) {
            end--;
        }
        Swap(&a[begin], &a[end]);
    }
    Swap(&a[begin], &a[keyindex]);
    return end;
}

void QuickSort(int* a, int left, int right) {
    assert(a);
    if (left < right) {
        int div = PartSort(a, left, right);
        // PrintArray(a, right - left + 1);
        // printf("[%d,%d]%d[%d,%d]\n", left, div - 1, div, div + 1,right);
        //[left,div-1]
        QuickSort(a, left, div - 1);
        //[div+1,right]
        QuickSort(a, div + 1, right);
    }
}

 对于单趟快排的其他办法:

法2:挖坑法,直接覆盖数据(不在调用Swap函数,性能比左右指针快一点)。

// 挖坑法:
int PartSort2(int* a, int begin, int end) {
    // 三数取中的优化
    int midIndex = GetMidIndex(a, begin, end);
    Swap(&a[midIndex], &a[end]);

    int key = a[end];
    // 挖出一个坑,可以直接把数据填入到相应位置:对左右指针法的一点修改
    while (begin < end) {
        while (begin < end && a[begin] <= key) {
            begin++;
        }
        // 左边找到比key大的,填到右边的坑,begin的位置形成新的坑
        a[end] = a[begin];
        while (begin < end && a[end] >= key) {
            end--;
        }
        // 右边找到比key小的,填到左边的坑,end的位置形成新的坑
        a[begin] = a[end];
    }
    // 把key填入到begin和end相遇的位置上(最后一个坑)
    a[end] = key;
    return end;
}

法3:前后指针法

// 前后指针法
int PartSort3(int* a, int begin, int end) {
    int prev = begin - 1;
    int cur = begin;
    int key = a[end];
    int keyIndex = end;
    while (cur < end) {
        if (a[cur] < key && ++prev != cur) {
            Swap(&a[prev], &a[cur]);
        }
        cur++;
    }
    Swap(&a[++prev], &a[keyIndex]);
    return prev;
}

 b.小区间优化

小区间使用插入排序可以减少递归层数,提升快排的效率:(小区间优化

当数据分割到小于等于10个数据时候,利用插入排序提升效率。

Q:为什么使用插入排序,而不是时间复杂度的更低的希尔排序或者堆排序?

A1:快速排序不断分割后,子序列趋近于有序

        前文中讲过,当待排数据趋近有序时,直接插入排序的时间复杂度趋近于O(N),因此,使用直接插入排序的性能要优于希尔排序和堆排序。

A2:希尔排序、堆排序、快速排序,都是对大量数据的排序。

        对于较少数据的排序(特别是趋近于有序的数据),使用插入排序的综合性能会更高一点。(插入排序对于小数据的排序性能不一定优于或者差于其他三种排序)。

void QuickSort(int* a, int left, int right) {
    assert(a);
    if (right - left + 1 < 10) {
        // 小区间使用插入排序
        InsertSort(a + left, right - left + 1);
    } else {
        // 大区间使用快速排序
        if (left < right) {
            int div = PartSort1(a, left, right);
            // PrintArray(a, right - left + 1);
            // printf("[%d,%d]%d[%d,%d]\n", left, div - 1, div, div + 1,right);
            //[left,div-1]
            QuickSort(a, left, div - 1);
            //[div+1,right]
            QuickSort(a, div + 1, right);
        }
    }
}
c.非递归(栈)

大区间单趟排,分割的两个小区间不在递归,而是保存在里面。

Q:为什么这里要用非递归实现呢?

A:递归实现的快排是由风险的,当待排的数据量特别大的时候,不断的递归会产生大量的栈帧,而计算机的栈帧仅有8M左右的大小,会发生栈溢出

实现:

void QuickSortNoR(int* a, int left, int right) {
    // 栈模拟实现
    Stack st;
    StackInit(&st); // 一定要记得初始化
    StackPush(&st, right);
    StackPush(&st, left);
    while (!StackEmpty(&st)) {
        int begin = StackTop(&st);
        StackPop(&st);
        int end = StackTop(&st);
        StackPop(&st);

        // 返回区间分割的keyIndex
        int div = PartSort1(a, begin, end);

        // 先对左区间分割,栈中先入右区间

        if (div + 1 < end) {
            // 入右区间右值
            StackPush(&st, end);
            // 入右区间左值
            StackPush(&st, div + 1);
        }
        if (div - 1 >= begin) {
            // 入左区间右值
            StackPush(&st, div - 1);
            // 入左区间左值
            StackPush(&st, begin);
        }
    }
    StackDestory(&st);
}//非递归同样可以使用小区间优化

 快排的时间复杂度分析: 

快排的时间复杂度:O(N*logN)。

快排的空间复杂度:O(logN)。(即栈帧的深度)


四、归并排序

基本思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。(不断地拆分,让子序列有序,归并一个序列时,保持有序)。

二路归并:将两个有序表合并成一个有序表。

分解:(递归图)

 归并:

 递归实现

时间复杂度是:O(N*logN)

空间复杂度是:O(N) 

// 归并函数
void MergeArr(int* a, int begin1, int end1, int begin2, int end2, int* tmp) {
    int left = begin1, right = end2;
    int index = begin1;
    while (begin1 <= end1 && begin2 <= end2) {
        if (a[begin1] < a[begin2])
            tmp[index++] = a[begin1++];
        else
            tmp[index++] = a[begin2++];
    }
    while (begin1 <= end1)
        tmp[index++] = a[begin1++];
    while (begin2 <= end2)
        tmp[index++] = a[begin2++];
    for (int i = left; i <= right; i++)
        a[i] = tmp[i];
}
// 归并的子函数
void _MergeSort(int* a, int left, int right, int* tmp) {
    if (left >= right)
        return;
    int mid = (left + right) / 2;
    //[left,mid] [mid+1,right]
    // 有序则可以合并,现在他们没有序,子问题解决
    _MergeSort(a, left, mid, tmp);
    _MergeSort(a, mid + 1, right, tmp);

    // 归并[left,mid] [mid+1,right]
    MergeArr(a, left, mid, mid + 1, right, tmp);
}

// 递归实现归并排序
void MergeSort(int* a, int n) {
    assert(a);
    int* tmp = (int*)malloc(sizeof(int) * n);
    _MergeSort(a, 0, n - 1, tmp);

    free(tmp);
}
非递归实现

非递归需要修正边界

非递归的时间复杂度:(从while循环入手)O(N*logN)

非递归的空间复杂度:O(N)

void MergeSortNoR(int* a, int n) {
    assert(a);
    int* tmp = (int*)malloc(sizeof(int) * n);
    // 迭代实现
    int gap = 1;
    int i = 0;
    while (gap < n) {
        for (i = 0; i < n; i += 2 * gap) {
            //[i,i+gap-1] [i+gap,i+2*gap-1]
            int begin1 = i;
            int end1 = i + gap - 1;
            int begin2 = i + gap;
            int end2 = i + 2 * gap - 1;

            // 1、合并时只有第一组,第二组不存在就不需要合并
            if (begin2 >= n) {
                break;
            }
            // 2、合并时第二组只有部分数据,需要修正end2边界
            if (end2 >= n) {
                end2 = n - 1;
            }

            MergeArr(a, begin1, end1, begin2, end2, tmp);
            PrintArray(a, n);
        }
        gap *= 2;
    }

    /*free(tmp);
    tmp == NULL;*/
}

五、内外排序

内(外)排序并不是特指某一种排序算法,而是针对不同存储的空间的排序方法。

内排序:指的是在内存中进行排序。

外排序:指的是在外存(文件、磁盘)中进行排序。

外排序实现需要利用C对文件的操作:

//合并两个有序数据的文件
void _MergeFile(const char* file1, const char* file2, const char* mFile) {
    FILE* pf1 = fopen(file1, "r");
    if (pf1 == NULL) {
        printf("2:%s\n", strerror(errno));
        exit(-1);
    }
    FILE* pf2 = fopen(file2, "r");
    if (pf2 == NULL) {
        printf("3:%s\n", strerror(errno));
        exit(-1);
    }
    FILE* fin = fopen(mFile, "w");
    if (fin == NULL) {
        printf("4:%s\n", strerror(errno));
        exit(-1);
    }
    int num1 = 0;
    int num2 = 0;
    int ret1 = fscanf(pf1, "%d\n", &num1) != EOF;
    int ret2 = fscanf(pf2, "%d\n", &num2) != EOF;
    while (ret1 != EOF && ret2 != EOF) { // 文件指针是自动的,都往后移动
        if (num1 < num2) {
            fprintf(fin, "%d\n", num1);
            ret1 = fscanf(pf1, "%d\n", &num1);
            // fseek(pf2, SEEK_CUR, -1);
        } else {
            fprintf(fin, "%d\n", num2);
            ret2 = fscanf(pf2, "%d\n", &num2);
            // fseek(pf1, SEEK_CUR, -1);
        }
    }
    while (ret1 != EOF) {
        fprintf(fin, "%d\n", num1);
        ret1 = fscanf(pf1, "%d\n", &num1);
    }
    while (ret2 != EOF) {
        fprintf(fin, "%d\n", num2);
        ret2 = fscanf(pf2, "%d\n", &num2);
    }
    fclose(pf1);
    fclose(pf2);
    fclose(fin);
}


void MergeSortFile(const char* file) {
    FILE* pf = fopen(file, "r");
    if (pf == NULL) {
        printf("1:%s\n", strerror(errno));
        exit(-1);
    }
    // 分割成小文件,内存排序后写到小文件中
    int n = 10;
    int a[10] = {0};
    int num = 0;
    int i = 0;
    // char* subfile = (char *)malloc(sizeof(char));
    char subfile[20];
    int filei = 0;

    while (fscanf(pf, "%d\n", &num) != EOF) {
        if (i < n - 1) {
            a[i++] = num;
        } else {
            a[i] = num;
            QuickSort(a, 0, n - 1);
            sprintf(subfile, "%d", filei++);
            FILE* fin = fopen(subfile, "w");
            for (i = 0; i < n; i++) {
                fprintf(fin, "%d\n", a[i]);
            }
            fclose(fin);
            i = 0;
            memset(a, 0, sizeof(int) * n);
        }
    }

    // 文件两两合并
    char mFile[100] = "12";
    char file1[100] = "1";
    char file2[100];
    for (i = 1; i <= n; i++) {
        sprintf(file2, "%d", i);
        // 读取file1和file2,归并出mfile
        _MergeFile(file1, file2, mFile);
        strcpy(file1, mFile);
        sprintf(mFile, "%s%d", mFile, i + 1);
    }
    fclose(pf);
}

六、非比较排序

        非比较排序是很“小众”的排序,因为这两种排序只适用于整数类型的排序。不能排序浮点数和字符串型的数据,对于这些类型的数据要用比较排序法来排序。

1、计数排序

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。是一种非比较排序

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中

实现:

void CountSort(int* a, int n) {
    int min = a[0];
    int max = a[0];
    int i = 0;
    for (i = 0; i < n; i++) {
        if (min > a[i]) {
            min = a[i];
        }
        if (max < a[i]) {
            max = a[i];
        }
    }
    int range = max - min + 1;
    int* countArr = (int*)calloc(range, sizeof(int));
    if (countArr == NULL) {
        return;
    }
    // memset(countArr, 0, sizeof(int) * range);
    for (i = 0; i < n; i++) {
        countArr[a[i] - min]++; // 偏移量映射
    }
    int index = 0;
    for (i = 0; i < range; i++) {
        int j = 0;
        for (j = 0; j < countArr[i]; j++) {
            a[index++] = i + min;
        }
    }

    free(countArr);
}
2、基数排序

        基数排序即:桶排序。可以参考:【算法】桶排序(Bucket Sort)详解-CSDN博客,桶排序不是很重要,了解即可。


总结

1、几种排序的时间复杂度比较

2、排序的稳定性

          稳定性:由某一算法完成的排序后,数组中相同元素的相对位置保持不变。即表示该算法是稳定的,否则表示该算法不稳定。


3、归并外部文件的排序(了解即可)

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

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

相关文章

JavaWeb:JavaScript

学习 资源1 学习资源 2 黑马javaweb 1、引入方式 内部脚本&#xff1a; <script>内容</script> 外部脚本&#xff1a; <script src"js/test.js"></script> 2、基础语法 注释&#xff1a;// /* */ 结尾分号可有可无 大括号表示代码块 …

MySQL其五,索引详解,逻辑架构,SQL优化等概念

目录 一、索引 1、索引的概念 2、索引的优缺点 3、添加索引的原则 4、索引的分类 5、索引如何使用 6、存储过程讲解 7、测试索引的效率 7、索引的数据结构 8、覆盖索引&#xff08;SQL优化的点&#xff09; 9、最佳左前缀法则&#xff08;SQL优化的点&#xff09; 二…

考研数学【线性代数基础box(数二)】

本文是对数学二线性代数基础进行总结&#xff0c;一些及极其简单的被省略了&#xff0c;代数的概念稀碎&#xff0c;不如高数关联性高&#xff0c;所以本文仅供参考&#xff0c;做题请从中筛选&#xff01; 本文为初稿&#xff0c;后面会根据刷题和自己的理解继续更新 第一章…

全面解析租赁小程序的功能与优势

内容概要 租赁小程序正在逐渐改变人与物之间的互动方式。通过这些小程序&#xff0c;用户不仅可以轻松找到所需的租赁商品&#xff0c;还能够享受无缝的操作体验。为了给大家一个清晰的了解&#xff0c;下面我们将重点介绍几个核心功能。 建议&#xff1a;在选择租赁小程序时&…

Linux DNS 协议概述

1. DNS 概述 互联网中&#xff0c;一台计算机与其他计算机通信时&#xff0c;通过 IP 地址唯一的标志自己。此时的 IP 地址就类似于我们日常生活中的电话号码。但是&#xff0c;这种纯数字的标识是比较难记忆的&#xff0c;而且数量也比较庞大。例如&#xff0c;每个 IPv4 地址…

Java使用ORM Bee自动生成Javabean.

Java使用ORM Bee自动生成Javabean. 配置数据库连接,添加了pom.xml依赖后,就可以写Java代码,自动生成Javabean了. 可参考:https://gitee.com/automvc/bee https://github.com/automvc/bee 还可以生成字段文件, 这样可以避免硬编码引用字段,速度也比反射快. package org.tea…

【MySQL中多表查询和函数】

目录 1.多表查询 1.1 外键 1.2 链接查询 2.MySQL函数 内置函数简介 数值函数 字符串函数 时间日期函数 条件判断操作 开窗函数 1.多表查询 本质&#xff1a;把多个表通过主外键关联关系链接&#xff08;join&#xff09;合并成一个大表&#xff0c;在去单表查询操作…

二维码数据集,使用yolov,voc,coco标注,3044张各种二维码原始图片(未图像增强)

二维码数据集&#xff0c;使用yolov&#xff0c;voc&#xff0c;coco标注&#xff0c;3044张各种二维码原始图片&#xff08;未图像增强&#xff09; 数据集分割 训练组70&#xff05; 2132图片 有效集20&#xff05; 607图片 测试集10&#xff05; 305图…

MySQL多表查询时有哪些连接方式?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL多表查询时有哪些连接方式?】面试题。希望对大家有帮助&#xff1b; MySQL多表查询时有哪些连接方式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中进行多表查询时&#xff0c;常见的连接方式有以下…

LBS 开发微课堂|通过openGL ES轻松实现建筑物渲染及动画

为了让广大开发者 更深入地了解 百度地图开放平台的 技术能力 轻松掌握满满的 技术干货 更加简单地接入 位置服务 我们特别推出了 “位置服务&#xff08;LBS&#xff09;开发微课堂” 系列技术案例 第五期的主题是 通过openGL ES轻松实现 建筑物渲染及动画 对于…

Java——IO流(下)

一 (字符流扩展) 1 字符输出流 (更方便的输出字符——>取代了缓冲字符输出流——>因为他自己的节点流) (PrintWriter——>节点流——>具有自动行刷新缓冲字符输出流——>可以按行写出字符串&#xff0c;并且可通过println();方法实现自动换行) 在Java的IO流中…

SQLServer到MySQL的数据高效迁移方案分享

SQL Server数据集成到MySQL的技术案例分享 在企业级数据管理中&#xff0c;跨平台的数据集成是一个常见且关键的任务。本次我们将探讨如何通过轻易云数据集成平台&#xff0c;将巨益OMS系统中的退款单明细表从SQL Server高效、安全地迁移到MySQL数据库中。具体方案名称为“7--…

每日计划-1213

1. 完成 SQL2 查询多列 https://www.nowcoder.com/exam/oj?page1tabSQL%E7%AF%87topicId199 2. 八股部分 1) C 中面向对象编程如何实现数据隐藏&#xff1f; 在c中&#xff0c;可以将数据成员声明为私有或受保护&#xff0c;并提供公有的成员函数来访问和修改这些数据成员&am…

ORACLE 导入导出数据库(包含表结构和数据)

导出 1、进入本地oracle 驱动安装目录下–> 进入CMD 2、输入命令 exp 用户名/密码10.xx.xx.xx:1521/orcl fileexport.dmp 3、查看导出的文件 导入 1、进入本地oracle 驱动安装目录下–> 进入CMD 2、输入命令 imp 用户名/密码10.xx.xx.xx:1521/orcl fully ignorey…

Qt之将源代码封装成库文件使用(五)

Qt开发 系列文章 - Code-To-Library&#xff08;五&#xff09; 目录 前言 一、库文件 二、直接封装方式 1.静态库封装 2.动态库封装 3.其它库类型 三、二次重写封装 四、库的使用 1.移植库及头文件 2.添加外部库 总结 前言 库文件是计算机上的一类文件&#xff0c…

视频监控汇聚平台方案设计:Liveweb视频智能监管系统方案技术特点与应用

随着科技的发展&#xff0c;视频监控平台在各个领域的应用越来越广泛。然而&#xff0c;当前的视频监控平台仍存在一些问题&#xff0c;如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果&#xff0c;也制约了视频监控平台的发展。 为了解决这些问…

跨平台开发技术的探索:从 JavaScript 到 Flutter

随着多平台支持和用户体验一致性在应用程序开发中变得越来越重要,开发者面临的挑战是如何在不同平台上保持代码的可维护性和高效性。本文将探讨如何利用现代技术栈,包括 Flutter、JavaScript、HTML5、WebAssembly、TypeScript 和 Svelte,在统一的平台上进行高效的跨平台开发…

Dcoker安装nginx,完成反向代理和负载均衡

1. 简介 官网&#xff1a;nginx Nginx是一个高性能的 HTTP 和反向代理 Web 服务器。它的主要功能包括反向代理、负载均衡和动静分离等。正因为 Nginx的这些功能能够为系统带来性能和安全方面的诸多优势&#xff0c;我们在项目部署时需要引入 Nginx组件。接下来我们会逐一向大…

Allegro X PCB设计小诀窍--如何在Allegro X中进行PCB设计评审

背景介绍&#xff1a;在PCB设计过程中&#xff0c;企业为了提升PCB设计质量&#xff0c;确保PCB设计的可制造性&#xff0c;缩短产品的研发周期&#xff0c;通常需要组织对PCB进行设计评审。但是目前的PCB设计评审过程存在评审文档管理繁琐、意见反馈不及时、问题传递不准确、评…

基于多视角深度学习技术的乳腺X线分类:图神经网络与Transformer架构的研究|文献速递-生成式模型与transformer在医学影像中的应用速递

Title 题目 Mammography classification with multi-view deep learning techniques:Investigating graph and transformer-based architectures 基于多视角深度学习技术的乳腺X线分类&#xff1a;图神经网络与Transformer架构的研究 01 文献速递介绍 乳腺X线检查是乳腺癌…