C语言学习--八种排序算法

目录

排序的概念

1.直接插入排序

基本思想

代码实现

算法分析

2.希尔排序

基本思想

代码实现

算法分析

3.冒泡排序

基本思想

 代码实现

算法分析

4.快速排序

基本思想

代码实现

算法分析

5.简单选择排序

基本思想

代码实现

算法分析

6.堆排序

基本思想

代码实现

算法分析

7.归并排序

基本思想

代码实现

算法分析

8.基数排序

基本思想

代码实现

算法分析

 总结


排序的概念

排序:所谓排序,就是一串记录,按照某个关键字的大小,按照递增或者递减的顺序进行排列的操作。

稳定性:排序的稳定性,在排序前,有许多相同关键字的记录,他们是按照一定的次序排列的。在排序后,还能按照原先的次序进行排序,那么我们称这种排序算法是稳定的,否则是不稳定的。

内部排序:数据全部在内存中排序。

外部排序:数据元素过多,无法在内存中排序,需要通过内外存之间移动数据来进行排序。

相关算法:


1.直接插入排序

基本思想

直接插入排序是一种简单的插入排序,思想是把待排序的记录按照其关键值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完成,得到一个新的有序序列。

         就比如说,我们现实生活中的玩扑克牌的方式就用了这种思想,我们每摸到一张牌的时候,原先手上的牌是排好序的,我们拿到这张新的牌,会插入到原先的有序序列,然后插入之后,我们新的序列又是有序的。之后,每次摸牌都按照这种方式,最终会得到一个完全有序的序列。

代码实现

有两种一种是直接插入,另一种是折半插入,区别在于查找插入位置的方法不同而已。

//1.直接插入排序

void InsertSort(int *a,int n){
    int j;
    for(int i=1;i<n;i++){
        if(a[i]<a[i-1]){
            int temp=a[i];
            for( j=i-1;j>=0&&a[j]>temp;j--){
                a[j+1]=a[j];
            }//找到temp需要插入的位置,并将元素后以一个
            //j等于
            a[j+1]=temp;
        }
    }
}

1.2.折半插入排序

void InsertSort2(int *a,int n){
    int i,j,low,high,mid;
    for(i=1;i<n;i++){
        int temp=a[i];
        low=0;high=i-1;
        while(low<=high){
            mid=(low+high)/2;
            if(a[mid]>temp){
                high=mid-1;
            }else{
                low=mid+1;
            }
        }//of while找到插入的位置
        for(j=i-1;j>=high+1;j--){
            a[j+1]=a[j];
        }
        a[high+1]=temp;
    }
} 

算法分析

        首先,我们先分析算法的时间复杂度,要考虑算法的最好、最坏以及平均复杂度。最好的情况是当这个数组已经有序或者接近有序的情况下,我们只需要进行比较,不需要移动元素,最好时间复杂度为O(N)。而最坏的情况是,这个数组是完全逆序的时候,我们每次比较后,都要移动大量的元素,最坏时间复杂度为O(N2)**,平均复杂度为**O(N^2)。

        那么,这个算法的空间复杂度为O(1),因为只需要使用常量级别的空间。

        最后,这个算法是否稳定,答案是稳定的。因为每次是从后往前依次比较,不会改变原先的次序,移动的过程中也是一个一个进行移动的。


2.希尔排序

基本思想

        希尔排序也是插入排序中的一种,因为其本质就是使用了插入排序,我们从插入排序的结论中可以得出,越接近有序的数组使用插入排序的效率越高。

        希尔排序的思想,就是使一个数组先部分有序,最后在全局有序。那么如何实现部分有序呢,我们可以对数组的元素按照某种规律进行分组,分组后,对组内的记录进行排序,如何重复进行分组和排序,当最终每组的成员只剩一个时,在进行排序的时候,就是使用了插入排序。

代码实现

我们定义了一个d变量,这个变量是用来进行分组的,当d大于0的时候,每次排序其实都是在预排序,也就是对分组内的成员进行排序,d是间隔,也就是将i,i+d,i+2*d...依次进行排序,之后,d/2或者d/3+1,按照某种规律,最终d=1的时候,在进行排序,就是进行了一次直接插入排序。

//2.希尔排序
void shellSort(int *a,int n){
    int i,j,d;
    for(d=n/2;d>=1;d=d/2){//分成不同的趟数,第一趟分割d=n/2
        for(i=d;i<n;i++){//对每一堂的每个小组排序
            if(a[i]<a[i-d]){
                int temp=a[i];
                for(j=i-d;j>=0&&a[j]>temp;j=j-d){
                    a[j+d]=a[j];
                }
                a[j+d]=temp;
            }//of if
        }//of for2
    }//of for1
}

算法分析

        希尔排序的时间复杂度是一个复杂的问题,在Kunth所著的《计算机程序设计技巧》第3卷中,利用大量的实验统计资料得出,平均复杂度为O(N^1.25)到O(1.6 * N^1.25)。这里的就暂且不讨论该结果具体得出的方式。

        希尔排序是否是稳定的算法呢?答案是不稳定的,因为我们在预排序的过程中,我们会进行大量的跳动式的移动元素的值,因此会导致不能按照原先的序列进行排序。

        希尔排序中的d是如何取值的呢?当成Shell,也就是该算法的原作者,提出取d= d/2,然后向下取整,直到d=1时。后来Kunth提出取d= d/3 + 1 ,d/3向下取整的方式,直到gap=1时。这两种方式没有说哪个好,哪个坏,因此,使用其中一个即可。


3.冒泡排序

基本思想

        冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,依次比较两个元素,如果它们的顺序错误就把它们交换过来。如果遍历一遍数组,发现没有进行交换,故该数组已经有序,就不需要再进行排序。

 代码实现

该排序算法的代码实现也很简单,每趟排序,遍历一遍数组,两两比较,每一趟会将最小的值放在第一位。如果该趟排序没有元素交换,则不需要再进行排序了。

//3.冒泡排序
void BubbleSort(int *a,int n){
    for(int i=0;i<n;i++){//总共要冒n躺
        for(int j=0;j<n-i;j++){//每一趟比较前n-i个元素
            if(a[j]>a[j+1]){
                int temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
    }
}

算法分析

        时间复杂度,当元素为逆序时,需要进行n-1趟排序,而每趟需要比较n-1次。故最坏时间复杂度为O(N^2)。当元素为有序时,第一趟后,发现不需要交换元素,则只需要进行n-1次比较。故最好时间复杂度为O(N)。

        空间也是仅使用了常数个辅助单元,故空间复杂度为O(1)

        冒泡排序是一种稳定的算法。


4.快速排序

基本思想

        快速排序是Hoare于1962年提出的一种以二叉树结构的交换排序。

        其本质是基于分治法实现的,基本思想是任取待排序元素序列中的某个元素作为基准,按照该排序码将待排序集合分割成两子序列,左子序列的所有元素均小于基准值,右子序列均大于基准值。然后左右子序列重复该操作,知道该序列有序为止。

代码实现

关于快速排序,其实c语言的<stdlib>库中自带快排函数qsort(),可以直接用,详情请看:

C语言学习--快速排序函数sqort()-CSDN博客

  1. 先将选定的基准值(最左边)直接取出,然后留下一个坑,
  2. 当右指针遇到小于基准值的数时,直接将该值放入坑中,而右指针指向的位置形成新的坑位,
  3. 然后左指针遇到大于基准值的数时,将该值放入坑中,左指针指向的位置形成坑位,
  4. 重复该步骤,直到左右指针相等。最后将基准值放入坑位之中。
  5. 之后也是以基准值为界限,递归排序基准值左右区间。

 

//4.快速排序
// 挖坑法
int PartSort(int* a, int begin, int end){
	int key = a[begin];
	int piti = begin;
	while (begin < end){
		// 右边找小,填到左边的坑里面去。这个位置形成新的坑
		while (begin < end && a[end] >= key){
			--end;
		}
		a[piti] = a[end];
		piti = end;
		// 左边找大,填到右边的坑里面去。这个位置形成新的坑
		while (begin < end && a[begin] <= key){
            ++begin;
		}
		a[piti] = a[begin];
		piti = begin;
	}
	a[piti] = key;
	return piti;
}
// 快速排序递归实现
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
    int keyi = PartSort(a, begin, end);
    // [begin, keyi-1] keyi [keyi+1, end]
    QuickSort(a, begin, keyi - 1);
    QuickSort(a, keyi + 1, end);
}

算法分析

        快速排序整体的综合性能与使用场景都是比较好的,所以才能称为快速排序。时间复杂度在优化后,基本上能达到O(N*logN),且优化后,优势更加明显。

        空间复杂度,因为使用了递归,导致空间复杂度为O(logN)

        算法是不稳定的。


5.简单选择排序

基本思想

        就是每一次从待排序的数据元素中选择最小或者最大的元素,放在序列的起始位置,直到全部排序完毕。

代码实现

//5.简单选择排序
void SelectSort(int *a,int n){
    for(int i=0;i<n-1;i++){//n-1躺,每一趟找一个最小值放到最前面
        int min=i;//记录最小值所在的下标便于交换位置
        for(int j=i+1;j<n;j++){
            if(a[j]<a[min]){
                min=j;
            }
        }//最小值所在下标min
        int temp=a[min];
        a[min]=a[i];
        a[i]=temp;//把每趟的最小值已到了最前面来
    }
}

每次找到最小(最大)的值,记录当前的位置,并且与开始位置进行交换。然后重复进行该操作,直到集合中只剩一个元素为止。

算法分析

        简单选择排序是比较简单的一种,但是效率并不高,无论是什么情况,算法时间复杂度都为O(N^2),因此,实际中很少使用。

        空间复杂度为O(1),仅使用了常量级别的空间。

        直接选择排序是否是稳定的算法呢?答案是不稳定的,在交换的过程中,可能会导致相对次序进行改变。比如,表L={2,2,1},经过第一趟排序后,结果为L={1,2,2},显示已经和原先的次序不一致,故该排序算法是不稳定的。


6.堆排序

后面三种,堆排序,归并排序,和基数排序不太好实现,我觉得理解原理就可以了;

基本思想

        在了解堆排序之前,首先要知道堆这个数据结构。

        堆是一颗完全二叉树,满足根节点大于或者小于左右孩子结点。堆可以分为大根堆和小根堆。大根堆的最大元素存放在根结点,任意一颗非根节点的值小于等于其双亲结点的值。而小根堆与大根堆恰好相反,小根堆的根元素为最小。

        大根堆可以存放在一个数组中,节点下标i,对应的左右孩子分别是:2*i,2*i+1

        那么,堆排序的思想很简单,首先在排序前,将待排序的数组构建成为一个堆,以大根堆为例,将堆顶元素与堆底元素进行交换,然后继续将堆顶元素进行向下调整,然后保持大根堆的特性。因为对顶元素永远是当前堆中最大的一个,将其放在最后,就相当于把最大元素放在了数组的最后,再将堆的范围缩小,因此大根堆排序后的结果为升序。

代码实现

 

//6.堆排序
void swap(int* p1, int* p2){
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
// 堆排序
// 向下取整
void AdjustDwon(int* a, int n, int root){
	int child = root * 2 + 1;
	while (child < n){
		if (child + 1 < n && a[child + 1] > a[child]){
			child++;
		}
		if (a[child] > a[root]){
			swap(&a[child], &a[root]);
			root = child;
			child = root * 2 + 1;
		}
		else{
			break;
		}
	}
}
void HeapSort(int* a, int n){
	// 建堆方式2:O(N)
	for (int i = (n-2) / 2; i >= 0; --i){
		AdjustDwon(a, n, i);
	}
	// O(N*logN)
	int end = n - 1;
	while (end > 0){
		swap(&a[0], &a[end]);
		AdjustDwon(a, end, 0);
		--end;
	}
}

算法分析

        堆排序是一种效率很高的排序,通过使用堆的数据结构来进行排序,时间复杂度为O(N*logN),建堆的时间为O(N),然后有n-1次向下调整操作,每次调整的时间复杂度与高度有关,而h=log2n + 1,故时间复杂度为O(N*logN)。

        空间也是仅使用了常数个辅助单元,故空间复杂的为O(1)。

        堆排序是否是稳定的算法呢?答案是不稳定的,在进行筛选的过程中,可能把后面相同的元素调整到前面来。


7.归并排序

基本思想

        归并排序是建立在归并操作上的一种有效的排序算法,该算法采用的是分治法。其思想就是将序列分成n个子序列,再使用子序列有序,之后,将其合并为一个新的有序表,如果两个有序表合并为一个有序表,称为二路归并

代码实现

//7.归并排序
void _MergeSort(int* a, int begin, int end, int* tmp){
    
	int mid = (begin + end) / 2;
	// [begin, mid] [mid+1, end] 分治递归,让子区间有序
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid + 1, end, tmp);

	//归并 [begin, mid] [mid+1, end]
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin1;
	while (begin1 <= end1 && begin2 <= end2){
		if (a[begin1] < a[begin2]){
			tmp[i++] = a[begin1++];
		}else{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1){
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2){
		tmp[i++] = a[begin2++];
	}
	// 把归并数据拷贝回原数组
	memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}
void MergeSort(int* a, int n){
	// 借助一个新的辅助空间来帮助合并
	int* tmp = (int*)malloc(sizeof(int) * n);
	_MergeSort(a, 0, n - 1, tmp);
	free(tmp);
}

算法分析

归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。

每趟归并的时间为O(N),并且需要log2N趟归并,所以时间复杂度为O(N*logN)

二路归并排序不会改变相同关键字记录的相对次序,因此是一种稳定的算法。


8.基数排序

基本思想

  1. 将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
  2. 这样说明,比较难理解,下面我们看一个图文解释,理解基数排序的步骤
    在这里插入图片描述

注意:基数排序中不能出现负数!!! 

代码实现

//8.基数排序
//基数排序
void RadixSort(int* arr, int n){
	//max为数组中最大值
	int max = arr[0];
	int base = 1;

	//找出数组中的最大值
	for (int i = 0; i < n; i++){
		if (arr[i] > max){
			max = arr[i];
		}
	}
	//循环结束max就是数组最大值
	//临时存放数组元素的空间
	int* tmp = (int*)malloc(sizeof(int)*n);
	//循环次数为最大数的位数
	while (max / base > 0){	
        //定义十个桶,桶里面装的不是数据本身,而是每一轮排序对应(十、白、千...)位的个数
		//统计每个桶里面装几个数
		int bucket[10] = { 0 };
		for (int i = 0; i < n; i++){
			//arr[i] / base % 10可以取到个位、十位、百位对应的数字
			bucket[arr[i] / base % 10]++;
		}
		//循环结束就已经统计好了本轮每个桶里面应该装几个数

		//将桶里面的元素依次累加起来,就可以知道元素存放在临时数组中的位置
		for (int i = 1; i < 10; i++){
			bucket[i] += bucket[i - 1];
		}
		//循环结束现在桶中就存放的是每个元素应该存放到临时数组的位置


		//开始放数到临时数组tmp
		for (int i = n - 1; i >= 0; i--){
			tmp[bucket[arr[i] / base % 10] - 1] = arr[i];
			bucket[arr[i] / base % 10]--;
		}
		//不能从前往后放,因为这样会导致十位排好了个位又乱了,百位排好了十位又乱了
		/*for (int i = 0; i < n; i++)
		{
			tmp[bucket[arr[i] / base % 10] - 1] = arr[i];
			bucket[arr[i] / base % 10]--;
		}*/

		//把临时数组里面的数拷贝回去
		for (int i = 0; i < n; i++){
			arr[i] = tmp[i];
		}
		base *= 10;
	}
	free(tmp);
}

 

算法分析

基数排序的时间复杂度跟基数选取有关,平均复杂度为O(k·n)。基数排序为稳定排序算法。


 总结

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

合合信息扫描全能王亮相静安区3·15活动,AI扫描带来绿色消费新体验

保护消费者的合法权益&#xff0c;是全社会的共同责任。为优化消费环境、促进品质消费高地建设&#xff0c;打造安全优质和谐的消费环境&#xff0c;上海静安区消保委于3月15日举办静安区2024年“315”国际消费者权益日活动。 “激发消费活力&#xff0c;绿色低碳同行”是本次3…

Vue+SpringBoot打造民宿预定管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色2.2.2 房主角色2.2.3 系统管理员角色 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿4.3 新增民宿评价4.4 查询留言4.5 新增民宿订单 五、免责说明 一、摘要 1.1 项目介绍 基于…

傻傻分不清目标检测、语义分割和实例分割,看这篇就够了

⭐️ 导言 随着深度学习技术的飞速发展&#xff0c;计算机视觉领域取得了巨大的进步。目标检测、语义分割和实例分割是计算机视觉中的重要任务&#xff0c;它们在图像理解和视频分析等方面发挥着关键作用。本文将深入探讨这三个任务的概念、原理、常用算法以及在实际应用中的案…

(css)vue 自定义背景 can‘t resolve

(css)vue 自定义背景 can’t resolve 旧写法&#xff1a; background-image: url(/assets/images/step-bg.jpg);background-size: 100% 100%; 新写法&#xff1a; background-image: url(~/assets/images/step-bg.jpg);background-size: 100% 100%; 解决参考&#xff1a;https…

shopee无货源出单了怎么发货?shopee怎么做无货源?

在Shopee的电商大舞台上&#xff0c;“无货源出单”就像是一场神奇的魔术表演。你的店铺是舞台&#xff0c;买家的订单是观众的掌声&#xff0c;而你&#xff0c;就是那位神秘的魔术师。订单来了&#xff0c;你却没有货&#xff1f;这可不是什么障碍&#xff0c;因为你有着更为…

算法详解——选择排序和冒泡排序

一、选择排序 选择排序算法的执行过程是这样的&#xff1a;首先&#xff0c;算法遍历整个列表以确定最小的元素&#xff0c;接着&#xff0c;这个最小的元素被置换到列表的开头&#xff0c;确保它被放置在其应有的有序位置上。接下来&#xff0c;从列表的第二个元素开始&#x…

[MySQL]数据库基础

文章目录 1.连接服务器2.理解mysql3.初见数据库4.主流数据库5.服务器&#xff0c;数据库&#xff0c;表关系6.数据逻辑存储7.MySQL架构8.SQL分类9.存储引擎 1.连接服务器 mysql -h 127.0.0.1 -P 3306 -u root -p -h&#xff1a;指明登录部署mysql服务的主机。没有写 -h 127.0.…

【链表】Leetcode 21. 合并两个有序链表【简单】

合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 解题思路 1、比较两个链表的头结点&#xff0c;选择其…

jumpserver管理集群

git地址&#xff1a;https://github.com/jumpserver/jumpserver.git 1、下载 jumpserver 需要docker来拉取镜像&#xff0c;没有的话会自动下载docker curl -sSL https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash 拉取的…

Prometheus修改默认数据存储时间

Prometheus的默认数据存储时间可以通过修改启动脚本中的相关参数来调整。具体来说&#xff0c;可以通过修改--storage.tsdb.retention.time参数来改变数据保留的时长。该参数决定了何时删除旧数据&#xff0c;默认为15天。如果需要延长数据保留时间&#xff0c;可以将该参数的值…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Hyperlink)

超链接组件&#xff0c;组件宽高范围内点击实现跳转。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件仅支持与系统浏览器配合使用。 需要权限 使用网络时&#xff0c;需要申请权限ohos.per…

AI论文速读 | UniST:提示赋能通用模型用于城市时空预测

本文是时空领域的统一模型——UniST&#xff0c;无独有偶&#xff0c;时序有个统一模型新工作——UniTS&#xff0c;感兴趣的读者也可以阅读今天发布的另外一条。 论文标题&#xff1a;UniST: A Prompt-Empowered Universal Model for Urban Spatio-Temporal Prediction 作者&…

大势智慧与云世纪签署战略合作,实景三维赋能低空经济,泛测绘助力城市数据更新更高效

2024年《政府工作报告》提出“要大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”、“积极打造商业航天、低空经济等新增长引擎”。 近日&#xff0c;武汉大势智慧科技有限公司&#xff08;以下简称“大势智慧”&#xff09;和青岛云世纪信息科技有限公司&#xf…

android 顺滑滑动嵌套布局

1. 背景 最近项目中用到了上面的布局&#xff0c;于是使用了scrollviewrecycleview&#xff0c;为了自适应高度&#xff0c;重写了recycleview&#xff0c;实现了高度自适应&#xff1a; public class CustomRecyclerView extends RecyclerView {public CustomRecyclerView(Non…

麒麟信安出品 | 无惧停服挑战!看C2K平台如何轻松拿捏CentOS迁移

2020年Redhat公司面向全球公布&#xff0c;于2021年底停止维护开源服务器操作系统CentOS 8&#xff0c;并将于2024年6月30日停止维护CentOS 7&#xff0c;届时CentOS全系列版本将停止维护。 在CentOS系统逐步停服的背景下&#xff0c;麒麟信安为满足各行各业现存的大量CentOS系…

基于树莓派实现 --- 智能家居

最效果展示 演示视频链接&#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 &#xff08;PS&#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型&#xff0c;户型参考了留学时短租的公寓~&a…

el-tree 设置默认展开指定层级

el-tree默认关闭所有选项&#xff0c;但是有添加或者编辑删除的情况下&#xff0c;需要刷新接口&#xff0c;此时会又要关闭所有选项&#xff1b; 需求&#xff1a;在编辑时、添加、删除 需要将该内容默认展开 <el-tree :default-expanded-keys"expandedkeys":da…

【C语言】常见的字符串处理函数

目录 1、strlen&#xff08;&#xff09;函数 2、strcpy&#xff08;&#xff09;、strncpy&#xff08;&#xff09;函数 3、strstr&#xff08;&#xff09; 函数 4、strcmp&#xff08;&#xff09;、strncmp&#xff08;&#xff09;函数 5、strcat&#xff08;&#…

[数据结构]堆

一、堆是什么&#xff1f; 堆是一种完全二叉树 完全二叉树的定义&#xff1a;完全二叉树的形式是指除了最后一层之外&#xff0c;其他所有层的结点都是满的&#xff0c;而最后一层的所有结点都靠左边。​​​​​​&#xff0c;从左到右连续。 教材上定义如下: 若设二叉树的…

AI检测识别技术,为智能化视频生产赋能

在科技飞速发展的今天&#xff0c;智能化生产已经成为企业提高效率、降低成本、增强竞争力的关键所在。美摄科技&#xff0c;作为一家在音视频处理技术领域保持领先的创新型企业&#xff0c;不仅致力于提供卓越的音视频处理技术&#xff0c;更在AI检测识别领域积累了深厚的实力…
最新文章