图解|从武侠角度探究STL排序算法的奥秘

C语言与CPP编程 2021-07-09 20:52

前言

今天来看一下STL中的sort算法的底层实现和代码技巧。

众所周知STL是借助于模板化来支撑数据结构和算法的通用化,通用化对于C++使用者来说已经很惊喜了,但是如果你看看STL开发者强大的阵容就意识到STL给我们带来的惊喜绝不会止步于通用化,强悍的性能和效率是STL的更让人惊艳的地方。

STL极致表现的背后是大牛们炉火纯青的编程技艺和追求极致的工匠精神的切实体现。

笔者能力所限,只能踏着前人的肩膀来和大家一起看看STL中sort算法的背后究竟隐藏着什么,是不是有种《走进科学》的既视感,让我们开始今天的sort算法旅程吧!

内省式哲学

在了解sort算法的实现之前先来看一个概念:内省式排序,说实话笔者的语文水平确实一般,对于这个词语用在排序算法上总觉得不通透,那就研究一下吧!

内省式排序英文是Introspective Sort,其中单词introspective是内省型的意思,还是不太明白,继续搜索,看一下百度百科对这个词条的解释:

内省(Introspection )在心理学中,它是心理学基本研究方法之一。内省法又称自我观察法。它是发生在内部的,我们自己能够意识到的主观现象。也可以说是对于自己的主观经验及其变化的观察。

正因为它的主观性,内省法自古以来就成为心理学界长期的争论。另外内省也可看作自我反省,也是儒家强调的自我思考。从这个角度说可以应用于计算机领域,如Java内省机制和cocoa内省机制。

好家伙,原来内省是个心理学名词,到这里笔者有些感觉了,内省就是自省、自我思考、根据自己的主观经验来观察变化做出调整,而不是把希望寄托于外界,而是自己的经验和能力。

通俗点说,内省算法不挑数据集,尽量针对每种数据集都能给定对应的处理方法,让排序都能有时间保证。

写到这里,让笔者脑海浮现了《倚天屠龙记》里面张无忌光明顶大战六大门派的场景,无论敌人多么强悍或者羸弱,我都按照自己的路子应对。

他强由他强,清风拂山岗;
他横由他横,明月照大江;
他自狠来他自恶,我自一口真气足。
---《九阳真经》达摩

哲学啊,确实这样的,我们切换到排序的角度来看看内省是怎么样的过程。

笔者理解的内省式排序算法就是不依赖于外界数据的好坏多寡,而是根据自己针对每种极端场景下做出相应的判断和决策调整,从而来适应多种数据集合展现出色的性能。

内省式排序

俗话说侠者讲究刀、枪、剑、戟、斧、钺、钩、叉等诸多兵器,这也告诉我们一个道理没有哪种兵器是无敌的,只有在某些场景下的明显优势,这跟软件工程没有银弹是一样的。

回到我们的排序算法上,排序算法也可谓是百花齐放:冒泡排序、选择排序、插入排序、快速排序、堆排序、桶排序等等。

虽然一批老一辈的排序算法是O(n^2)的,优秀的算法可以到达O(nlogn),但是即使都是nlogn的快速排序和堆排序都有各自的长短之处,插入排序在数据几乎有序的场景下性能可以到达O(n),有时候我们应该做的不是冲突对比而是融合创新。

内省排序是由David Musser在1997年设计的排序算法。这个排序算法首先从快速排序开始,当递归深度超过一定深度(深度为排序元素数量的对数值)后转为堆排序,David Musser大牛是STL领域响当当的人物。

抛开语境一味地对比孰好孰坏其实都没有意义,内省式排序就是集大成者,为了能让排序算法达到一个综合的优异性能,内省式排序算法结合了快速排序、堆排序、插入排序,并根据当前数据集的特点来选择使用哪种排序算法,让每种算法都展示自己的长处,这种思想确实挺启发人的。

内省排序的排兵布阵

前面提到了内省式排序主要结合了快速排序、堆排序、插入排序,那么不禁要问,这三种排序是怎么排兵布阵的呢?

知己知彼百战不殆,所以先看下三种排序的优缺点吧!

快速排序

在大量数据时无论是有序还是重复,使用优化后的算法大多可以到达O(nlogn),虽然堆排序也是O(nlogn)但是由于某些原因快速排序会更快一些,当递归过深分割严重不均匀情况出现时会退化为O(n^2)的复杂度,这时性能会打折扣,这也就是快速排序的短处了。

堆排序

堆排序是快速排序的有力竞争者,最大的特点是可以到达O(nlogn)并且复杂度很稳定,并不会像快速排序一样可能退化为O(n^2),但是堆排序过程中涉及大量堆化调整,并且元素比较是跳着来的对Cache的局部性特征利用不好,以及一些其他的原因导致堆排序比快速排序更慢一点,但是大O复杂度仍然是一个级别的。

插入排序

插入排序的一个特点是就像我们玩纸牌,在梳理手中的牌时,如果已经比较有序了,那么只需要做非常少的调整即可,因此插入排序在数据量不大且近乎有序的情况下复杂度可以降低到O(n),这一点值得被应用。

优缺点也大致清楚了,所以可以猜想一下内省式排序在实际中是如何调度使这三种排序算法的:

  • 启动阶段 面对大量的待排序元素,首先使用快速排序进行大刀阔斧排序,复杂度可以在O(nlogn)运行

  • 深入阶段 在快速排序使用递归过程中,涉及栈帧保存切换等诸多递归的操作,如果分区切割不当递归过深可能造成栈溢出程序终止,因此如果快速排序过程中退化为O(n^2),此时会自动检测切换为堆排序,因为堆排序没有恶化情况,都可以稳定在O(nlogn)

  • 收尾阶段 在经过快排和堆排的处理之后,数据分片的待排序元素数量小于某个经验设定值(可以认为是递归即将结束的前几步调用)时,数据其实已经几乎有序,此时就可以使用插入排序来提高效率,将复杂度进一步降低为O(n)。

写到这里,笔者又天马行空地想到了一个场景:

2005年春晚小品中黄宏和巩汉林出演的《装修》中黄宏作为装修工人手拿一大一小两把锤子,大锤80小锤40,大小锤头切换使用。

其实跟内省排序切换排序算法是一个道理,所以技术源于生活又高于生活,贴图一张大家一起体会一下:

用了很多篇幅来讲内省思想和内省式排序,相信大家也已经get到了,所以我们具体看下实现细节,这个才是本文的重点,我们继续往下一起分析吧!

sort算法的实现细节

本文介绍的sort算法是基于SGI STL版本的,并且主要是以侯捷老师的《STL源码剖析》一书为蓝本来进行展开的,因此使用了不带仿函数的版本,让我们来一起领略大牛们的杰作吧!图为笔者买了很久却一直压箱底的STL神书:

sort函数的应用场景

SGI STL中的sort的参数是两个随机存取迭代器RandomAccessIterator,sort的模板也是基于此种迭代器的,因此如果容器不是随机存取迭代器,那么可能无法使用通用的sort函数。

  • 关联容器 map和set底层是基于RB-Tree,本身就已经自带顺序了,因此不需要使用sort算法

  • 序列容器 list是双向迭代器并不是随机存取迭代器,vector和deque是随机存取迭代器适用于sort算法

  • 容器适配器 stack、queue和priority-queue属于限制元素顺序的容器,因此不适用sort算法。

综上我们可以知道,sort算法可以很好的适用于vector和deque这两种容器。

sort总体概览

前面介绍了内省式排序,所以看下sort是怎么一步步来使用introsort的,上一段入口代码:

template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
    if (first != last) {
        __introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
        __final_insertion_sort(first, last);
    }
}

从代码来看sort使用了first和last两个随机存取迭代器,作为待排序序列的开始和终止,进一步调用了__introsort_loop和__final_insertion_sort两个函数,从字面上看前者是内省排序循环,后者是插入排序。其中注意到__introsort_loop的第三个参数__lg(last - first)*2,凭借我们的经验来猜(蒙)一下吧,应该递归深度的限制,不急看下代码实现:

template <class Size>
inline Size __lg(Size n){
    Size k;
    for(k = 0;n > 1;n >>= 1) ++k;
    return k;
}

这段代码的意思就是n=last-first,2^k<=n的最大整数k值。

所以整体看当假设last-first=20时,k=4,最大分割深度depth_max=4*2=8,从而我们就可以根据first和last来确定递归的最大深度了。

快速排序和堆排序的配合 __introsort_loop函数中主要封装了快速排序和堆排序,来看看这个函数的实现细节:

//sort函数的入口
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
                      RandomAccessIterator last, T*,
                      Size depth_limit) {
    while (last - first > __stl_threshold) {
        if (depth_limit == 0) {
            partial_sort(first, last, last);//使用堆排序
            return;
        }
        --depth_limit;//减分割余额
        RandomAccessIterator cut = __unguarded_partition
          (first, last, T(__median(*first, *(first + (last - first)/2),
                                   *(last - 1))));//三点中值法分区过程
        __introsort_loop(cut, last, value_type(first), depth_limit);//子序列递归调用
        last = cut;//迭代器交换 切换到左序列
    }
}
//基于三点中值法的分区算法
template <class RandomAccessIterator, class T>
RandomAccessIterator __unguarded_partition(RandomAccessIterator first, 
                                           RandomAccessIterator last, 
                                           T pivot) {
while (true) {
    while (*first < pivot) ++first;
    --last;
    while (pivot < *last) --last;
    if (!(first < last)) return first;
    iter_swap(first, last);
    ++first;
}

各位先不要晕更不要蒙圈,一点点分析肯定可以拿下的。

  • 先看参数两个随机存取迭代器first和last,第三个参数是__lg计算得到的分割深度;

  • 这时候我们进入了while判断了last-first的区间大小,__stl_threshold为16,侯捷大大特别指出__stl_threshold的大小可以是5~20,具体大小可以自己设置,如果大于__stl_threshold那就才会继续执行,否则跳出;假如现在区间大小大于__stl_threshold,判断第三个参数depth_limit是否为0,也就是是否出现了分割过深的情况,相当于给了一个初始最大值,然后每分割一次就减1,直到depth_limit=0,这时候调用partial_sort,从《stl源码剖析》的其他章节可以知道,partial_sort就是对堆排序的封装,看到这里有点意思了主角之一的heapsort出现了;

  • 继续往下看,depth_limit>0 尚有分割余额,那就燥起来吧!这样来到了__unguarded_partition,这个函数从字眼看是快速排序的partiton过程,返回了cut随机存取迭代器,__unguarded_partition的第三个参数__median使用的是三点中值法来获取的基准值Pivot,至此快速排序的partition的三个元素集齐了,最后返回新的切割点位置;

  • 继续看马上搞定啦,__introsort_loop出现了,果然递归了,特别注意一下这里只有一个递归,并且传入的是cut和last,相当于右子序列,那左子序列怎么办啊?别急往下看,last=cut峰回路转cut变成了左子序列的右边界,这样就开始了左子序列的处理;

快速排序的实现对比

前面提到了在sort中快速排序的写法和我们之前见到的有一些区别,看了一下《STL源码剖析》对快排左序列的处理,侯捷老师是这么写的:"写法可读性较差,效率并没有比较好",看到这里更蒙圈了,不过也试着分析一下吧!

图为:STL源码剖析中侯捷老师对该种写法的注释

常见写法:

//快速排序的常见写法伪代码
quicksort(arr,left,right){
    pivoit = func(arr);//使用某种方法获取基准值
    cut = partition(left,right,pivot);//左右边界和基准值来共同确定分割点位置
    quicksort(arr,left,cut-1);//递归处理左序列
    quicksort(arr,cut+1,right);//递归处理右序列
}

SGI STL中的写法:

stl_quicksort(first,last){
      //循环作为外层控制结构
      while(ok){
         cut = stl_partition(first,last,_median(first,last));//分割分区
         stl_quicksort(cut,last);//递归调用 处理右子序列
         last = cut;//cut赋值为last 相当于切换到左子序列 再继续循环
   }
}

网上有一些大佬的文章说sgi stl中快排的写法左序列的调用借助了while循环节省了一半的递归调用,是典型的尾递归优化思路。

这里我暂时还没有写测试代码做对比,先占坑后续写个对比试验,再来评论吧,不过这种sgi的这种写法可以看看哈。

堆排序的细节

//注:这个是带自定义比较函数的堆排序版本
//堆化和堆顶操作
template <class RandomAccessIterator, class T, class Compare>
void __partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
                    RandomAccessIterator last, T*, Compare comp) {
    make_heap(first, middle, comp);
    for (RandomAccessIterator i = middle; i < last; ++i)
        if (comp(*i, *first))
            __pop_heap(first, middle, i, T(*i), comp, distance_type(first));
    sort_heap(first, middle, comp);
}
//堆排序的入口
template <class RandomAccessIterator, class Compare>
inline void partial_sort(RandomAccessIterator first,
                         RandomAccessIterator middle,
                         RandomAccessIterator last, Compare comp) {
    __partial_sort(first, middle, last, value_type(first), comp);
}

插入排序上场了

__introsort_loop达到__stl_threshold阈值之后,可以认为数据集近乎有序了,此时就可以通过插入排序来进一步提高排序速度了,这样也避免了递归带来的系统消耗,看下__final_insertion_sort的具体实现:

template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first, 
                            RandomAccessIterator last) {
    if (last - first > __stl_threshold) {
        __insertion_sort(first, first + __stl_threshold);
        __unguarded_insertion_sort(first + __stl_threshold, last);
    }
    else
        __insertion_sort(first, last);
}

来分析一下__final_insertion_sort的实现细节吧:

  • 引入参数随机存取迭代器first和last

  • 如果last-first > __stl_threshold不成立就调用__insertion_sort,这个相当于元素数比较少了可以直接调用,不用做特殊处理;

  • 如果last-first > __stl_threshold成立就进一步再分割成两部分,分别调用__insertion_sort和__unguarded_insertion_sort,两部分的分割点是__stl_threshold,不免要问这俩函数有啥区别呀?

__insertion_sort的实现

//逆序对的调整
template <class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value) {
    RandomAccessIterator next = last;
    --next;
    while (value < *next) {
        *last = *next;
        last = next;
        --next;
    }
    *last = value;
}

template <class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first, 
                            RandomAccessIterator last, T*) {
    T value = *last;
    if (value < *first) {
        copy_backward(first, last, last + 1);//区间移动
        *first = value;
    }
    else
        __unguarded_linear_insert(last, value);
}

//__insertion_sort入口
template <class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first, RandomAccessIterator last) {
    if (first == last) return
    for (RandomAccessIterator i = first + 1; i != last; ++i)
        __linear_insert(first, i, value_type(first));
}

在插入函数中同样出现了__unguarded_xxx这种形式的函数,unguarded单词的意思是无防备的,无保护的,侯捷大大提到这种函数形式是特定条件下免去边界检验条件也能正确运行的函数。

copy_backward也是一种整体移动的优化,避免了one by one的调整移动,底层调用memmove来高效实现。

__unguarded_insertion_sort的实现

template <class RandomAccessIterator, class T>
void __unguarded_insertion_sort_aux(RandomAccessIterator first, 
                                    RandomAccessIterator last, T*) {
    for (RandomAccessIterator i = first; i != last; ++i)
        __unguarded_linear_insert(i, T(*i));
}

template <class RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first, 
                                RandomAccessIterator last) {
    __unguarded_insertion_sort_aux(first, last, value_type(first));
}

关于插入排序的这两个函数的实现和目的用途,展开起来会很细致,所以后面想着单独在写插入排序时单独拿出了详细学习一下,所以本文就暂时先不深究了,感兴趣的读者可以先行阅读相关资料,后续我们再共同辩驳哈!

总结

本文主要阐述了内省式排序的思想和基本实现思路,并且以此为切入点对sgi stl中sort算法的实现来进行了一些解读。

stl的作者们为了追求极致性能所以使用了大量的技巧,对此本文并没有过多展开,也主要是段位不太高怕解读错了,聪明的读者们可以尝试来剖析一探大牛们的巅峰技艺。

C语言与CPP编程 C语言/C++开发,C语言/C++基础知识,C语言/C++学习路线,C语言/C++进阶,数据结构;算法;python;计算机基础等
评论
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球中空长航时无人机产值达到9009百万美元,2024-2030年期间年复合增长率CAGR为8.0%。 环洋市场咨询机构出版了的【全球中空长航时无人机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球中空长航时无人机总体规模,包括产量、产值、消费量、主要生产地区、主要生产商及市场份额,同时分析中空长航时无人机市场主要驱动因素、阻碍因素、市场机遇、挑战、新产品发布等。报告从中空长航时
    GIRtina 2025-01-09 10:35 100浏览
  • Snyk 是一家为开发人员提供安全平台的公司,致力于协助他们构建安全的应用程序,并为安全团队提供应对数字世界挑战的工具。以下为 Snyk 如何通过 CircleCI 实现其“交付”使命的案例分析。一、Snyk 的挑战随着客户对安全工具需求的不断增长,Snyk 的开发团队面临多重挑战:加速交付的需求:Snyk 的核心目标是为开发者提供更快、更可靠的安全解决方案,但他们的现有 CI/CD 工具(TravisCI)运行缓慢,无法满足快速开发和部署的要求。扩展能力不足:随着团队规模和代码库的不断扩大,S
    艾体宝IT 2025-01-10 15:52 51浏览
  • 一个真正的质量工程师(QE)必须将一件产品设计的“意图”与系统的可制造性、可服务性以及资源在现实中实现设计和产品的能力结合起来。所以,可以说,这确实是一种工程学科。我们常开玩笑说,质量工程师是工程领域里的「侦探」、「警察」或「律师」,守护神是"墨菲”,信奉的哲学就是「墨菲定律」。(注:墨菲定律是一种启发性原则,常被表述为:任何可能出错的事情最终都会出错。)做质量工程师的,有时会不受欢迎,也会被忽视,甚至可能遭遇主动或被动的阻碍,而一旦出了问题,责任往往就落在质量工程师的头上。虽然质量工程师并不负
    优思学院 2025-01-09 11:48 115浏览
  • 故障现象一辆2017款东风风神AX7车,搭载DFMA14T发动机,累计行驶里程约为13.7万km。该车冷起动后怠速运转正常,热机后怠速运转不稳,组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断 用故障检测仪检测,发动机控制单元中无故障代码存储;读取发动机数据流,发现进气歧管绝对压力波动明显,有时能达到69 kPa,明显偏高,推断可能的原因有:进气系统漏气;进气歧管绝对压力传感器信号失真;发动机机械故障。首先从节气门处打烟雾,没有发现进气管周围有漏气的地方;接着拔下进气管上的两个真空
    虹科Pico汽车示波器 2025-01-08 16:51 117浏览
  • HDMI 2.2 规格将至,开启视听新境界2025年1月6日,HDMI Forum, Inc. 宣布即将发布HDMI规范2.2版本。新HDMI规范为规模庞大的 HDMI 生态系统带来更多选择,为创建、分发和体验理想的终端用户效果提供更先进的解决方案。新技术为电视、电影和游戏工作室等内容制作商在当前和未来提供更高质量的选择,同时实现多种分发平台。96Gbps的更高带宽和新一代 HDMI 固定比率速率传输(Fixed Rate Link)技术为各种设备应用提供更优质的音频和视频。终端用户显示器能以最
    百佳泰测试实验室 2025-01-09 17:33 124浏览
  • 在当前人工智能(AI)与物联网(IoT)的快速发展趋势下,各行各业的数字转型与自动化进程正以惊人的速度持续进行。如今企业在设计与营运技术系统时所面临的挑战不仅是技术本身,更包含硬件设施、第三方软件及配件等复杂的外部因素。然而这些系统往往讲究更精密的设计与高稳定性,哪怕是任何一个小小的问题,都可能对整体业务运作造成严重影响。 POS应用环境与客户需求以本次分享的客户个案为例,该客户是一家全球领先的信息技术服务与数字解决方案提供商,遭遇到一个由他们所开发的POS机(Point of Sal
    百佳泰测试实验室 2025-01-09 17:35 115浏览
  • 1月7日-10日,2025年国际消费电子产品展览会(CES 2025)盛大举行,广和通发布Fibocom AI Stack,赋智千行百业端侧应用。Fibocom AI Stack提供集高性能模组、AI工具链、高性能推理引擎、海量模型、支持与服务一体化的端侧AI解决方案,帮助智能设备快速实现AI能力商用。为适应不同端侧场景的应用,AI Stack具备海量端侧AI模型及行业端侧模型,基于不同等级算力的芯片平台或模组,Fibocom AI Stack可将TensorFlow、PyTorch、ONNX、
    物吾悟小通 2025-01-08 18:17 87浏览
  • 「他明明跟我同梯进来,为什么就是升得比我快?」许多人都有这样的疑问:明明就战绩也不比隔壁同事差,升迁之路却比别人苦。其实,之间的差异就在于「领导力」。並非必须当管理者才需要「领导力」,而是散发领导力特质的人,才更容易被晓明。许多领导力和特质,都可以通过努力和学习获得,因此就算不是天生的领导者,也能成为一个具备领导魅力的人,进而被老板看见,向你伸出升迁的橘子枝。领导力是什么?领导力是一种能力或特质,甚至可以说是一种「影响力」。好的领导者通常具备影响和鼓励他人的能力,并导引他们朝着共同的目标和愿景前
    优思学院 2025-01-08 14:54 96浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2025-01-09 09:58 83浏览
  • 职场是人生的重要战场,既是谋生之地,也是实现个人价值的平台。然而,有些思维方式却会悄无声息地拖住你的后腿,让你原地踏步甚至退步。今天,我们就来聊聊职场中最忌讳的五种思维方式,看看自己有没有中招。1. 固步自封的思维在职场中,最可怕的事情莫过于自满于现状,拒绝学习和改变。世界在不断变化,行业的趋势、技术的革新都在要求我们与时俱进。如果你总觉得自己的方法最优,或者害怕尝试新事物,那就很容易被淘汰。与其等待机会找上门,不如主动出击,保持学习和探索的心态。加入优思学院,可以帮助你快速提升自己,与行业前沿
    优思学院 2025-01-09 15:48 102浏览
  • 在智能网联汽车中,各种通信技术如2G/3G/4G/5G、GNSS(全球导航卫星系统)、V2X(车联网通信)等在行业内被广泛使用。这些技术让汽车能够实现紧急呼叫、在线娱乐、导航等多种功能。EMC测试就是为了确保在复杂电磁环境下,汽车的通信系统仍然可以正常工作,保护驾乘者的安全。参考《QCT-基于LTE-V2X直连通信的车载信息交互系统技术要求及试验方法-1》标准10.5电磁兼容试验方法,下面将会从整车功能层面为大家解读V2X整车电磁兼容试验的过程。测试过程揭秘1. 设备准备为了进行电磁兼容试验,技
    北汇信息 2025-01-09 11:24 103浏览
  • 1月9日,在2025国际消费电子展览会(CES)期间,广和通发布集智能语音交互及翻译、4G/5G全球漫游、随身热点、智能娱乐、充电续航等功能于一体的AI Buddy(AI陪伴)产品及解决方案,创新AI智能终端新品类。AI Buddy是一款信用卡尺寸的掌中轻薄智能设备,为用户带来实时翻译、个性化AI语音交互助手、AI影像识别、多模型账户服务、漫游资费服务、快速入网注册等高品质体验。为丰富用户视觉、听觉的智能化体验,AI Buddy通过蓝牙、Wi-Fi可配套OWS耳机、智能眼镜、智能音箱、智能手环遥
    物吾悟小通 2025-01-09 18:21 38浏览
  • 在过去十年中,自动驾驶和高级驾驶辅助系统(AD/ADAS)软件与硬件的快速发展对多传感器数据采集的设计需求提出了更高的要求。然而,目前仍缺乏能够高质量集成多传感器数据采集的解决方案。康谋ADTF正是应运而生,它提供了一个广受认可和广泛引用的软件框架,包含模块化的标准化应用程序和工具,旨在为ADAS功能的开发提供一站式体验。一、ADTF的关键之处!无论是奥迪、大众、宝马还是梅赛德斯-奔驰:他们都依赖我们不断发展的ADTF来开发智能驾驶辅助解决方案,直至实现自动驾驶的目标。从新功能的最初构思到批量生
    康谋 2025-01-09 10:04 99浏览
  •  在全球能源结构加速向清洁、可再生方向转型的今天,风力发电作为一种绿色能源,已成为各国新能源发展的重要组成部分。然而,风力发电系统在复杂的环境中长时间运行,对系统的安全性、稳定性和抗干扰能力提出了极高要求。光耦(光电耦合器)作为一种电气隔离与信号传输器件,凭借其优秀的隔离保护性能和信号传输能力,已成为风力发电系统中不可或缺的关键组件。 风力发电系统对隔离与控制的需求风力发电系统中,包括发电机、变流器、变压器和控制系统等多个部分,通常工作在高压、大功率的环境中。光耦在这里扮演了
    晶台光耦 2025-01-08 16:03 88浏览
  • 车机导航有看没有懂?智能汽车语系在地化不可轻忽!随着智能汽车市场全球化的蓬勃发展,近年来不同国家地区的「Automotive Localization」(汽车在地化)布局成为兵家必争之地,同时也是车厂在各国当地市场非常关键的营销利器。汽车在地化过程中举足轻重的「汽车语系在地化」,则是透过智能汽车产品文字与服务内容的设计订制,以对应不同国家地区用户的使用习惯偏好,除了让当地车主更能清楚理解车辆功能,也能进一步提高品牌满意度。客户问题与难处某车厂客户预计在台湾市场推出新一代车款,却由于车机导航开发人
    百佳泰测试实验室 2025-01-09 17:47 30浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦