精华内容
下载资源
问答
  • SQL笔面试题:如何求取中位数

    千次阅读 2021-08-19 00:32:34
    公众号后台回复“图书“,了解更多号主新书内容 作者:胖里 来源: 胖里的日常 先来看看中位数的概念。中位数(Median)又称中值,统计学中的专有名词,是按顺序排...
    
    
    公众号后台回复“图书“,了解更多号主新书内容
         作者:胖里
         来源:  胖里的日常
    

    先来看看中位数的概念

    中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本、种群或概率分布中的一个数值,其可将数值集合划分为相等的上下两部分。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。

    百度百科

    说到中位数,大家应该都不陌生。中位数是九年义务教育中数学里的一个重要概念,想当初刚学习的时候会经常对平均数、中位数、众数进行比较,比较它们的优缺点是什么,什么情况下应该用哪一种数。

    不知道大家日常数据分析工作中是否会用到中位数的求取,如果是通过Excel、Python等进行数据分析、可视化展示,那这两款软件都有其对应的求中位数的函数,分别是median()和numpy库中的median()。如果写SQL的时候用到,可能就没有那么现成的函数了。(oracle中有求取中位数的函数)

    除了日常工作,数据分析的笔面试中也经常会出现中位数求取的考察。今天就总结三种用SQL求取中位数的方法。

    方法1:充分利用窗口函数

    思路介绍:

    根据中位数的概念,想要求取中位数,需要对一组数据进行排序,找出居于中间位置的数,如果有奇数个数,那最中间的一个为中位数,如果有偶数个数,那中间两个数的平均数为中位数。因此我们需要实现的是排序,取中间值或中间两值的平均值,既然涉及到中间这种位置定位,那自然少不了编号与总体个数的比较。

    因此可以概括为排序、编号、找位置、取值。那就需要考虑到排序函数row_number()、计数函数cout()、求均值函数avg()。

    示例:

    有一组数:1,3,55,8,34,66,42,88,SQL找出中位数。

    按照先前的思路,使用相关函数实现:

    select avg(num)
    from 
    (
        select num 
            ,row_number() over(order by num) as rn 
            ,count(*) over() as n
        from tmp
    )as t 
    where rn in (floor(n/2)+1,if(mod(n,2) = 0,floor(n/2),floor(n/2)+1))
    

    先使用row_number()函数对数据从小到大进行排序标号,用count()顺便实现数据总数的记录,假设为n个。如果n为奇数,则取最中间一个值作为中位数,也就是编号为floor(n/2)+1的数,如果n为偶数,需要取中间位置的两个数,也就是floor(n/2)和floor(n/2)+1的两个数。因此可以将floor(n/2)+1作为一个rn的取值,另一个通过判断奇偶性来选择。

    当然思路一致,你选择不同的函数实现也是可以的,比如不用if用case when来判断。

    方法2:正排倒排来一遍法

    思路介绍:

    不妨这样想一想,还是根据中位数的概念,一组数据想求中位数,那么这个数或这两个数肯定在一组排序好的数据的中间位置,那是不是正排和倒排的编号会存在某种规律?

    假设有一组数:33,25,4,63,18(奇数个),正排和倒排编号之后如下。

    假设还有一组数:33,25,4,63,18,22(偶数个),正排和倒排编号之后如下。

    观察上述两个示例,会发现由于中位数的独特魅力所在,无论正排还是倒排,对于奇数个数来说,其编号始终不变,而对于偶数个数来说,两个中位数(取均值)的编号相差±1。

    按照上述观察结果,就可以得到另一种求中位数的思路,也就是对数据进行正排和倒排,编号,按照奇偶两种条件进行限制,求得编号是这两种条件的一个值或两个值的平均数作为中位数。

    示例:

    有一组数:1,3,55,8,34,66,42,88,SQL找出中位数。

    按照先前的思路,使用相关函数实现:

    select avg(num)
    from 
    (
        select num 
            ,row_number() over(order by num) as rn1
            ,row_number() over(order by num desc) as rn2
        from tmp
    )as t 
    where rn1 = rn2 or abs(rn1-rn2) = 1
    

    此处需要注意一个问题,上述SQL代码用MySQL跑时,会报错,需要设置下参数,SET sql_mode='NO_UNSIGNED_SUBTRACTION'

    还有,我们不得不考虑这样一种情况,如果待求中位数的数据中存在相等的数怎么办?比如下图的示例,出现了多个重复数据,对于相同的值使用row_number()函数可能不能实现像我们预期那样的正排倒排,此时若按照rn1 = rn2或abs(rn1 - rn2)相差1这两个条件进行限制只能得到6,但实际上中位数为2和6的平均数。

    因此为了达到预期想要的正排倒排的效果,可以使用主键id跟着要排序的数据进行正排倒排,保证正排和倒排数据的编号走向处处相反。

    select avg(num)
    from 
    (
        select id
            ,num 
            ,row_number() over(order by num, id) as rn1
            ,row_number() over(order by num desc, id desc) as rn2
        from tmp
    )as t 
    where rn1 = rn2 or abs(rn1-rn2) = 1
    

    难道求中位数只能通过排序?不排序可以找到中位数吗?我们来看看方法三。

    方法三:自连接比较法

    思路介绍:

    我们可以想一想,除了被动排序编号,这些数据是不是可以主动一把?一个数A可以主动去跟别的数作比较,如果比别的数小则+1,比别的数大则-1,这+1,-1加和是不是能表示这个数的“地位”,也就是变相的表征如果按大小排序,是排在什么样的位置上。是不是也就意味着+1,-1加和得到的结果(绝对值)越小,这个数越处于居中位置?

    举个例子。

    有这么一组数据:1,2,3,4,5,6。按照刚刚描述,对它们分别求取一个加和结果margin和margin的绝对值。

    从图上可以看到,3和4对应的margin的绝对值最小,因此它们两个就是居中的数。通过这个例子是否能get此方法?是否能得到某个处于中间位置的值,或某两个处于中间位置的值?

    当然上述示例比较简单,再多考虑一下,这种操作对于有重复值的适用吗?

    我们看图中这个示例,数据中存在多个重复值,按刚刚的思路,margin绝对值最小的num即为中位数,但此示例中显然不是,2和6的均值才是中位数。

    此时要想沿用之前的思路,就得加限制条件,也就是统计下与该数相等的数的个数,记为equal,毕竟个数会影响到num的位置。选出equal大于或等于margin绝对值的num,也就是2和6。

    按照目前的思路,使用相关语句实现:

    select avg(num)
    from 
    (
        select t1.num 
            ,abs(sum(sign(t2.num-t1.num))) as margin
            ,sum(if(t1.num = t2.num,1,0)) as equal
        from 
        (
            select num 
            from tmp 
        )as t1 
        inner join 
        (
            select num 
            from tmp
        )as t2 
        group by t1.num 
    )as t 
    where equal >= margin
    

    以上便是我今天分享的三种使用SQL进行中位数求取的方法。当然大家也可以考虑下是否存在某些现成的计算分位数的函数,毕竟中位数就是二分位数,直接使用函数可比写SQL来的容易。如此看来,此考题的目的就是考你对于中位数的理解,考你的思路和方法了。

    至于与中位数相关的笔试题目我这边就不做赘述了,大家可以去网站上搜搜看,有类似的题目,现实中也有相关应用。比如求各科成绩的中位数、各部门员工薪资的中位数等等。实例有很多,可以自己结合现成函数或上述方法操作看看。

    如果你有更好地求中位数的方法或文中有何不妥之处,欢迎交流~可以通过

    ◆ ◆ ◆  ◆ ◆
    麟哥新书已经在当当上架了,我写了本书:《拿下Offer-数据分析师求职面试指南》,目前当当正在举行活动,大家可以用相当于原价5折的预购价格购买,还是非常划算的:
    
    
    
    数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以扫描下方管理员二维码,进群前一定要关注公众号奥,关注后让管理员帮忙拉进群,期待大家的加入。
    管理员二维码:
    猜你喜欢
    ● 卧槽!原来爬取B站弹幕这么简单● 厉害了!麟哥新书登顶京东销量排行榜!● 笑死人不偿命的知乎沙雕问题排行榜
    ● 用Python扒出B站那些“惊为天人”的阿婆主!● 你相信逛B站也能学编程吗
    
    展开全文
  • 算法在实际生活应用

    千次阅读 2021-01-14 08:28:15
    我结合学生的生活经验和已有的知识来设计富有情趣和意义的活动,创设良好的教学情景,使学生切实体验到身边有数学,用数学可以解决生活实际问题,从而对数学产生亲切感,增强了学生对数学知识的应用意识,培养...

    流密码算法及在日常生活中的应用

    践经验和已有的知识中学习数学和理解数学。”在教学中,我结合学生的生活经验和已有的知识来设计富有情趣和意义的活动,创设良好的教学情景,使学生切实体验到身边有数学,用数学可以解决生活中的实际问题,从而对数学产生亲切感,增强了学生对数学知识的应用意识,培养学生的自主创新解决问题的能力。

    1、数学思维能力训练的生活化

    数学思维能力的训练尽量与实际生活紧密相连,在课堂教学中的教学内容要面对生活实践,为学生营造1种宽松平等而又充满智力活动的氛围,使学生自然而然地受到创新性思维的训练。由于学生的思维的创造性是1种心智技能活动,是内在的隐性活动,因此,必须借助外在的动作技能、显性活动作基础。在教学中,要结合学生的生活经验,引导学生通过“再创造”来学习知识,以培养学生的思维能力为目的,达到能力的创新。在教学《接近整百整10数加减法的简便算法》时,有这样1题“165-97=165-100+3”,学生对减100时要加上3,难以理解,我就让学生联系买东西找0的生活实际想:妈妈带了165元钱去医药商店买了1盒97元的西洋参。她付给营业员1张百元钞票(应把165元减去100元),营业员找回3元,(应加上3元)。所以,多减去的要3应该加上。这样教学,抽象的运算获得了经验的支持,具体的经验也经过1番梳理和提炼,上升为理论上的简便运算,从而又总结出“多减要加上,多加要减去,少加要再加,少减要再减”的速算规律,达到良好的教学效果。

    2、应用题教学紧密联系学生的实际生活。

    应用题训练“生活化”是指把应用题与生活中的问题联系起来,懂得生活中的1般道理,再去理解数量关系,理解了的数量关系再运用到生活中去解决实际问题。例如在教学3步计算应用题时,我把书上的例题该为和学生生活接近的问题“要求我们3年级1共有多少人?你会想什么办法知道?”于是有的学生说去问班主任每个班有多少人再加起来就可以了;还有学生说去问教导主任;还有学生说到学校的校长办公室直接查电脑就行了不用算。通过学生自己动脑筋想出了各种解决问题的办法使学生的学习欲望大增,学习兴趣高涨。通过这样的活动,学生不但掌握了知识点,更重要的是通过它让学生展开了想象的翅膀,使他们体验到学习知识的快乐,掌握了技能,激发了他们的自主创新意识。

    总而言之,“联系生活学数学”,要培养学生自主创新能力和解决问题的能力必须积极创造条件,努力培养学生主体意识。在课堂上要创设生动有趣的情境来启发诱导,在课外要积极运用数学知识解决实际问题,激发学生强烈的求知欲,让学生亲自探索、发现、解决问题,获得成功的喜悦,真正成为学习的主人。

    作为1名数学教师我们应该有意识的把日常生活中的问题数学化,使学生在我们的引导下,逐步具备在日常生活和社会生活中运用数学的“本领”,使他们认识到“数学是生活的组成部分,生活处处离不开数学”,要养成事事、时时、处处吸收运用数学知识的习惯,调动他们主动学习数学、创新性运用数学的积极性。例如,在教学中,我就提出这样的问题,你今年的身高是多少呀?身体有多重?比1比你和你的同桌谁重……这些都是小学生经常遇到的问题,而要准确地说出结果,就需要我们量1量、称1称、算1算,这些都离不开数学。再如,生活中常用的各种知识像水电费、日常购物问题均发生在身边,我们买东西、做衣服、外出旅游,都离不开数学。又如:在教学的“ 小数的初步认识”这1内容时,我在课前布置了这样1个预习题:请同学们回家后到超市去进行1项社会调查,调查同1类商品的5种不同价格,读出价格,看1看哪种牌子的最贵?哪种牌子的最便宜?算1算其中两种商品的总价是多少?向这样让学生用学过的知识来解决日常生活中的问题,不仅激发了学习兴趣,而且能提高学生用所学知识解决实际问题的能力,让数学走向生活。

    “联系生活学数学”强调了数学教学与社会生活相接轨。在传授数学知识和训练数学能力的过程中,教师自然而然地注入生活内容;在参与关心学生生活过程中,教师引导学生学会运用所学知识为自己生活服务。这样的教学设计,不仅贴近学生的生活水平,符合学生的需要心理,而且也给学生留有1些瑕想和期盼,使他们将数学知识和实际生活联系得更紧密。

    常常听到一些家长抱怨:“我的孩子能说会唱,电视广告、流行歌曲模仿得维妙维肖,就是学数学不开窍 ,10以内的加减法也学不会。”面对这种情况,这些家长更应思考:如何对孩子进行数学启蒙。我认为,家庭 数学启蒙可以在日常生活中随机进行,从中让孩子们感受到数学内容不是枯燥的数字和呆板的几加几、几减几 ,而是有趣的、有用的。

    下面,介绍一些家庭数学启蒙的方式和途径。

    一、交谈活动

    数学具有抽象性、严谨性、逻辑性等特点,而幼儿的思维具有直观形象性的特点,呆板地向他们灌输数学 知识,不符合他们的年龄特征,不仅收不到好的学习效果,反会引起他们对数学的反感和厌烦。家长可在平日 与幼儿的随机交谈中寓教于乐,将孩子轻松地引入数学领域。如节假日,家长带着孩子外出,乘公共汽车,可 和他一起数车站,若要乘8站才能到达目的地,那么,可让孩子说说现在乘过了几站,还要乘几站才能到达目的 地,如是熟悉的路还可让孩子逐一将每站的站名报出来。若乘客不多,还可以数到站时上下车的人数,比比是 上车的人多呢,还是下车的人多;前门上来了几人,中门上来了几人,合起来是几人……仅这一个话题,幼儿 就可以学习数数、比多少、加减法等。家长与孩子一起数数、算算中不就对他进行了数学启蒙了吗?又如,茶 余饭后,家长可和孩子一起玩手指游戏,边玩边数边比:一二三四五,六七八九十,十个好朋友,花样变不完 。伸出大拇指,我俩一样粗;伸出小拇指,你俩一样小:伸出一只手,中指最最高;伸出两只手,十指排排队 。再如,喝饮料时,可以问孩子,易拉罐是什么形状的?这时,家长就可以与孩子比赛,说出像圆柱体的东西 ,看谁说得多。假如经常喝饮料的话,不妨每次把空罐收起来,积少成多,以后还可让孩子按罐的大小、高矮 、粗细、颜色、品种等玩分类游戏。

    通过交谈进行数学启蒙,不需要家长们花很多时间去精心准备,只要做有心人,在日常生活中找机会,便 可自然而然地进行,从中激发孩子学习数学的兴趣。

    二、家务劳动

    现在的独生子女家庭,不少家长为了保证孩子有更多的时间发展智力,承包了所有的家务劳动。其实,在 家务劳动中也能渗透数学启蒙。如,整理衣服时,可让孩子将衣服按爸爸的、妈妈的和自己的进行折叠整理; 或按上衣、裤子和袜子进行折叠整理。整理鞋子时,可让孩子按从小到大或从大到小的顺序排放;或按鞋子的 特征:房里穿的、出门穿的;女式的、男式的;大人的、小孩的;冬天穿的和不是冬天穿的等来排放。这些劳 动在不知不觉中对孩子渗透了分类、排序能力的培养。又如,吃饭前,请孩子给每位吃饭的人分发一份餐具( 包括碗筷、勺子、碟子、餐巾纸),这就渗透了一一对应的方法。假设有一样餐具少了一件,还可让幼儿比多 少,说说哪个多,哪个少;想想用什么办法才能让它们一样多呢。这些活动均能提高幼儿的分类和数数能力。

    可见,简单的家务劳动不仅不会累了孩子,反而能使他们从小养成爱劳动的好习惯,并从中学到知识,感 受到数学是有用的。

    三、操作活动

    国内外的众多幼儿数学研究表明:只有让孩子通过动手操作、摆弄,才能逐步体验抽象的数概念。家长应 该为孩子提供学数的操作材料,如,家中常玩的扑克牌,就是孩子学数的操作材料之一。可让孩子先将数字牌 和人头牌分开,再按数字牌上的花式分开,然后,分别从1排到10。在这简单的理牌中就使孩子进行了分类练习 ,并掌握从小到大的顺序。爸爸、妈妈也可和孩子一起玩牌,比如,爸爸出一张“5”,孩子必须出"4"和"6", 并将"4"放在"5"的前面,"6"放在"5"的后面,说出5的两个相邻数是4和6,出对、说对牌归自己。爸爸和孩子轮 流出牌,最后,比比谁的牌总张数最多;或比比哪一花式的牌多,哪一花式的牌少;单数的牌多还是双数的牌 多,多几,少几。也可玩抽牌游戏,相互抽对方一张数字牌,说出合起来是几,相差几,说得又对又快者可得 对方的牌。家长切莫错过在玩牌中帮助孩子感知数的实际意义、数序、数的组成和相邻数等数概念。又如,提 供孩子一些两种颜色、大小不同的回形针,让孩子尝试着套。不难发现,孩子会按颜色或大小不同套出很多的 花样。

    同样,在操作活动中,孩子通过自由摆弄物体,获得了数学感知和经验,并对抽象的数学产生了兴趣。

    如果我的回答令您满意,请点击采纳。谢谢!!

    展开全文
  • 本文介绍平均值、几何均值、调和均值、中位数、截尾法以及众值估计的求解方法,并用matlab对实例进行求解。 各值的特点 平均值 无系统误差和粗大误差时,直接求平均的结果最接近真值,用它来表示测量结果是最为可靠...

    均值求解

    本文介绍平均值、几何均值、调和均值、中位数、截尾法以及众值估计的求解方法,并用matlab对实例进行求解。

    各值的特点

    平均值

    • 无系统误差和粗大误差时,直接求平均的结果最接近真值,用它来表示测量结果是最为可靠、简单的。
    • 估计误差小,能反映出所有的数据特征。
    • 易受到粗大误差的影响,属于非稳健估计。
    • 计算简单

    几何均值

    • 表示平均增长率或变化率。
    • 不具有最佳性、属于非稳健估计。
    • 在实际运用中使用的不多

    调和均值

    • 一般用来分析数据含有某因素倒数的影响,如:平均密度、总平均速度、平均寿命等。
    • 不具有最佳性、属于非稳健估计。
    • 在实际运用中使用的不多。

    中位数

    • 对偏态数据的偏态不敏感。
    • 估计误差比 x ˉ \bar{x} xˉ大。
    • 不能反映出数据的全部信息,但是也因此有较好的稳健性。
    • 计算复杂(需要排序)。

    截尾法均值

    • 特性介于均值与中位数之间,拥有两者共同的优缺点。
    • 可以弥补均值的非稳健性和中位值的效率低的特点。
    • 属于稳健估计法。
    • 经验表明一般情况截去数据中最小的10%和最大的%10.

    众值

    • 仅可以反映出现次数最多的数据信息,丢失的信息较多。
    • 多峰分布下,难以确定众值或众值偏差较大。
    • 估计误差和统计特性难以分析。
    • 实际应用较少。

    编程求解

    问题

    对某真值为5的数据进行8次测量,测量值分别为:5.001, 5.002, 4.998, 4.993, 5.001, 5.008, 5.500, 4.997.试分别采用最小二乘(平均值)、几何均值、调和均值、中位数、截尾法以及众值估计这组测量数据的测量值,并比较优缺点。

    matlab求解

    题目要求用多种指标:平均值、几何均值、调和均值、中位数、截尾法以及众值估计测量数据的真值,并用偏差、计算量等指标分析各个估计方法的优缺点。
    将题目所给的数据输入matlab,编程求解各个待求量,程序如下:

    clear;clc;
    %edit by callmiaoup
    %data 2021-4-20
    %Ver 1.0
    data=[5.001,5.002,4.998,4.993,5.001,5.008,5.500,4.997]; %输入数据
    ave=(sum(data)/length(data));  %平均值
    geoave=(data(1)*data(2)*data(3)*data(4)*data(5)*data(6)*data(7)*data(8))^(1/length(data));  %几何均值
    reconcileave=1/(1/data(1)+1/data(2)+1/data(3)+1/data(4)+1/data(5)+1/data(6)+1/data(7)+1/data(8))*length(data);  %调和均值
    sort=sort(data);  %排序
    mid=(sort(length(data)/2)+sort(length(data)/2+1))/2;  %中位数
    truncation=(sort(2)+sort(3)+sort(4)+sort(5)+sort(6)+sort(7))/(length(data)-2);  %截尾法
    mode=mode(data);  %众值
    
    

    运行结果如图:
    在这里插入图片描述
    使用tic-toc命令可以查看各个数据求解的耗时,将其加上。运行程序。

    结果分析

    将实测结果用表格的形式列出来:

    均值类型结果绝对误差相对误差误差排序耗时(us)耗时排序
    最小二乘均值5.06250.06251.25%6973
    几何均值5.05990.05991.20%51755
    调和均值5.05750.05751.15%41294
    中位数5.0010.0010.02%1781
    截尾法均值5.00120.00120.02%3862
    众值5.0010.0010.02%12116

    由表格可以分析出:从计算精度来看,对比求平均的计算结果和真实值,误差有小到高的算法分别为:众值、中位数、截尾均值、调和均值、几何均值、最小二乘(平均值)。其中中位数和众值误差在所有方法的对比中最低,为0.02%.
    从计算耗时来看,中位数耗时最短,其次是截尾法均值,但是这两种方法在测量耗时时均为将数据升序排列的时间计算其中,所以一段样本在未经处理时,中位数和截尾法均值的计算时长是不短的。其次是最常用的平均值,耗时在100us以内。耗时最长的是众值,在程序求解众值时,因为需要不短搜索与储存出现次数最多的数值,所以对于计算能力和存储空间的要求都较高,这也是众值在实际运用中不常采用的原因之一。

    总结

    随机误差影响下测量数据表现为某种随机变量,其分布中心位置理论上可用期望值(数学期望/均值)表征。求均值的方法很多,使用的领域和不尽相同,没有绝对好于绝对不好的方法,我们需要在实际使用时找到最适合当前数据的均值。

    展开全文
  • iOS之深入解析Hash在iOS应用

    万次阅读 2021-10-19 15:43:24
    也就是说,它通过把关键码值映射到表一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。 给定表 M,存在函数 f(key),对任意给定的关键字值 key,代入函数后若能得到...

    一、哈希表定义

    • 哈希表(hash table,也叫散列表),是根据键(key)直接访问访问在内存储存位置的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。
    • 给定表 M,存在函数 f(key),对任意给定的关键字值 key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表 M 为哈希(Hash)表,函数f(key)为哈希(Hash)函数。
    • 若关键字为 k,则其值存放在 f(k) 的存储位置上,由此不需比较便可直接取得所查记录,称这个对应关系 f 为散列函数,按这个思想建立的表为散列表。
    • 对不同的关键字可能得到同一散列地址,即 k1≠k2,而 f(k1)=f(k2),这种现象称为冲突(英译:Collision)。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数f(k)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表或散列,所得的存储位置称散列地址。
    • 若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突。
    • 哈希表本质是一个数组,数组中的每一个元素成为一个箱子,箱子中存放的是键值对,根据下标 index 从数组中取 value。关键是如何获取 index,这就需要一个固定的函数(哈希函数),将 key 转换成 index。
    • 不论哈希函数设计的如何完美,都可能出现不同的 key 经过 hash 处理后得到相同的 hash 值,这时候就需要处理哈希冲突。

    二、哈希表优缺点

    • 优点:哈希表可以提供快速的操作。
    • 缺点:
      • 哈希表通常是基于数组的,数组创建后难于扩展;
      • 没有一种简便的方法可以以任何一种顺序〔例如从小到大)遍历表中的数据项。
    • 综上,如果不需要有序遍历数据,井且可以提前预测数据量的大小,那么哈希表在速度和易用性方面是无与伦比的。

    三、哈希查找步骤

    • 使用哈希函数将被查找的键映射(转换)为数组的索引,理想情况下(hash 函数设计合理)不同的键映射的数组下标也不同,所有的查找时间复杂度为 O(1)。但是实际情况下不是这样的,所以哈希查找的第二步就是处理哈希冲突。
    • 处理哈希碰撞冲突,方法有很多,比如拉链法、线性探测法。

    四、哈希表存储过程

    • 使用 hash 函数根据 key 得到哈希值 h;
    • 如果箱子的个数为 n,那么值应该存放在底(h%n)个箱子中,h%n 的值范围为 [0, n-1];
    • 如果该箱子非空(已经存放了一个值)即不同的 key 得到了相同的h产生了哈希冲突,此时需要使用拉链法或者开放定址线性探测法解决冲突。

    五、常用哈希函数

    • 哈希查找第一步就是使用哈希函数将键映射成索引,这种映射函数就是哈希函数。
    • 如果有一个保存 0 ~ M 数组,那么就需要一个能够将任意键转换为该数组范围内的索引(0 ~ M-1)的哈希函数,哈希函数需要易于计算并且能够均匀分布所有键。
    • 举个简单的例子,使用手机号码后三位就比前三位作为 key 更好,因为前三位手机号码的重复率很高;再比如使用身份证号码出生年月位数要比使用前几位数要更好。
    • 在实际中,我们的键并不都是数字,有可能是字符串,还有可能是几个值的组合等,所以需要实现自己的哈希函数:
      • 直接寻址法;
      • 数字分析法;
      • 平方取中法;
      • 折叠法;
      • 随机数法;
      • 除留余数法。
    • 要想设计一个优秀的哈希算法并不容易,根据经验,总结了需要满足的几点要求:
      • 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);
      • 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;
      • 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;
      • 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。

    六、负载因子

    • 负载因子 = 总键值对数/数组的个数。
    • 负载因子是哈希表的一个重要属性,用来衡量哈希表的空/满程度,一定程度也可以提现查询的效率。负载因子越大,意味着哈希表越满,越容易导致冲突,性能也就越低。所以当负载因子大于某个常数(一般是0.75)时,哈希表将自动扩容。
    • 哈希表扩容时,一般会创建两倍于原来的数组长度,因此即使 key 的哈希值没有变化,对数组个数取余的结果会随着数组个数的扩容发生变化,因此键值对的位置都有可能发生变化,这个过程也成为重哈希(rehash)。

    七、哈希表扩容

    • 在数组比较多的时候,需要重新哈希并移动数据,性能影响较大。
    • 虽然能够使负载因子降低,但并不总是能有效提高哈希表的查询性能。
    • 比如哈希函数设计的不合理,导致所有的 key 计算出的哈希值都相同,那么即使扩容他们的位置还是在同一条链表上,变成了线性表,性能极低,查询的时候时间复杂度就变成了 O(n)。

    八、哈希冲突的解决方法

    ① 拉链法

    • 简单来说就是数组 + 链表,将键通过 hash 函数映射为大小为 M 的数组的下标索引,数组的每一个元素指向一个链表,链表中的每一个结点存储着 hash 出来的索引值为结点下标的键值对。
    • Java 8 解决哈希冲突采用的就是拉链法,在处理哈希函数设计不合理导致链表很长时(链表长度超过 8 切换为红黑树,小于 6 重新退化为链表),将链表切换为红黑树能够保证插入和查找的效率,缺点是当哈希表比较大时,哈希表扩容会导致瞬时效率降低。
    • Redis 解决哈希冲突采用的也是拉链法,通过增量式扩容解决了 Java 8 中的瞬时扩容导致的瞬时效率降低的缺点,同时拉链法的实现方式(新插入的键值对放在链表头部)带来了两个好处:
      • 头插法可以节省插入耗时,如果插到尾部,则需要时间复杂度为 O(n) 的操作找到链表尾部,或者需要额外的内存地址来保存尾部链表的位置;
      • 头插法可以节省查找耗时,对于一个数据系统来说,最新插入的数据往往可能频繁的被查询。
    • 与开放定址线性探测发相比,拉链法有如下几个优点:
      • 拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
      • 由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
      • 开放定址线性探测法为减少冲突,要求装填因子 α 较小,故当结点规模较大时会浪费很多空间。而拉链法中可取 α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
      • 在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放定址线性探测发构造的散列表,删除结点不能简单地将被删结 点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径。这是因为各种开放定址线性探测发中,空地址单元(即开放地址)都是查找失败的条件。因此在用开放定址线性探测发处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记,而不能真正删除结点。
    • 拉链法的缺点:指针需要额外的空间,故当结点规模较小时,开放定址线性探测发较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放定址线性探测发中的冲突,从而提高平均查找速度。

    ② 开放定址线性探测法

    • 使用两个大小为 N 的数组(一个存放 keys,另一个存放 values),使用数组中的空位解决碰撞,当碰撞发生时(即一个键的 hash 值对应数组的下标被两外一个键占用)直接将下标索引加一(index += 1),这样会出现三种结果:
      • 未命中(数组下标中的值为空,没有占用):keys[index] = key,values[index] = value;
      • 命中(数组下标中的值不为空,占用):keys[index] == key,values[index] == value;
      • 命中(数组下标中的值不为空,占用):keys[index] != key,继续 index += 1,直到遇到结果 1 或 2 停止。
    • 开放定址线性探测法缺点
      • 容易产生堆积问题;
      • 不适于大规模的数据存储;
      • 散列函数的设计对冲突会有很大的影响;
      • 插入时可能会出现多次冲突的现象,删除的元素是多个冲突元素中的一个,需要对后面的元素作处理,实现较复杂;
      • 结点规模很大时会浪费很多空间。

    ③ 再散列法

    • Hi=RHi(key),i=1,2,…,k RHi 均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间;

    ④ 建立一个公共溢出区

    九、Hash 表的平均查找长度

    • Hash 表的平均查找长度包括查找成功时的平均查找长度和查找失败时的平均查找长度:
      • 查找成功时的平均查找长度=表中每个元素查找成功时的比较次数之和/表中元素个数;
      • 查找不成功时的平均查找长度相当于在表中查找元素不成功时的平均比较次数,可以理解为向表中插入某个元素,该元素在每个位置都有可能,然后计算出在每个位置能够插入时需要比较的次数,再除以表长即为查找不成功时的平均查找长度。
    • 给定一组数据 {32,14,23,01,42,20,45,27,55,24,10,53},假设散列表的长度为 13(最接近 n 的质数),散列函数为 H(k) = k,分别画出用“线性探测法”和“拉链法”解决冲突时构造的哈希表,并求出在等概率下情况,这两种方法查找成功和查找不成功的平均查找长度。
      • 拉链法:
        • 查找成功时的平均查找长度:ASL = (16 + 24 + 31 + 41)/12 = 7/4;
        • 查找不成功时的平均查找长度:ASL = (4 + 2 + 2 + 1 + 2 + 1)/13。

    在这里插入图片描述

      • 线性探测法:
        • 查找成功时查找次数 = 插入元素时的比较次数,查找成功的平均查找长度:ASL = (1 + 2 + 1 + 4 + 3 + 1 + 1 + 1 + 3 + 9 + 1 + 1 + 3)/12 = 2.5;
        • 查找不成功时的查找次数 = 第 n 个位置不成功时的比较次数为,第 n 个位置到第 1 个没有数据位置的距离:如第 0 个位置取值为 1,第 1个位置取值为 2。查找不成功时的平均查找长度:ASL = ( 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12/13 = 91/13。

    十、Apple 方案选择

    • 解决哈希冲突的拉链法和开放定址线性探测法,Apple 都在使用,具体使用哪一种是根据存储数据的生命周期和特性决定的:
      • @synchronized 使用的是拉链法,拉链法多用于存储的数据是通用类型,能够被反复利用,就像@synchronized 存储的是锁是一种无关业务的实现结构,程序运行时多个对象使用同一个锁的概率相当高,有效的节省了内存。
      • weak 对象 associatedObject 采用的是开放定址线性探测法,开放定址线性探测法用于存储的数据是临时的,用完尽快释放,就像 associatedObject,weak。

    十一、字符串的 hash 方法

    • [NSString hash] 出现同样的 hash 值问题:
    At least there are special circumstances for which this unreliability kicks in.
    
    Comparing [a hash] and [b hash] of two different NSString is safe when:
    
    the strings' length is shorter or equal to 96 characters.
    [a length] is different to [b length].
    the concatinated first, middle, and last 32 characters of a differ to the concatinated components of b.
    Otherwise every difference between the first and the middle 32 chars, as well as every difference between the middle and the last 32 characters, are not used while producing the [NSString hash] value.
    
    • [NSString hash] 这个方法对 <=96 个字符的字符串是安全的,如果比 96 个字符长,会大大增加碰撞的概率:
    #define HashEverythingLimit 96
    
    #define HashNextFourUniChars(accessStart, accessEnd, pointer) \
        {result = result * 67503105 + (accessStart 0 accessEnd) * 16974593  + (accessStart 1 accessEnd) * 66049  + (accessStart 2 accessEnd) * 257 + (accessStart 3 accessEnd); pointer += 4;}
    
    #define HashNextUniChar(accessStart, accessEnd, pointer) \
        {result = result * 257 + (accessStart 0 accessEnd); pointer++;}
    
    
    CF_INLINE CFHashCode __CFStrHashCharacters(const UniChar *uContents, CFIndex len, CFIndex actualLen) {
        CFHashCode result = actualLen;
        // ****X 这里HashEverythingLimit = 96
        if (len <= HashEverythingLimit) {
            // ****X 若字符串长度在96以内,对所有的字符做hash运算得到一个结果
            
            const UniChar *end4 = uContents + (len & ~3);
            const UniChar *end = uContents + len;
            while (uContents < end4) HashNextFourUniChars(uContents[, ], uContents);    // First count in fours
            while (uContents < end) HashNextUniChar(uContents[, ], uContents);      // Then for the last <4 chars, count in ones...
        } else {
            // ****X 若字符串长度超过96
            
            const UniChar *contents, *end;
            // ****X 取前32个字符做hash运算
        contents = uContents;
            end = contents + 32;
            while (contents < end) HashNextFourUniChars(contents[, ], contents);
            // ****X 取中间32个字符做hash运算
        contents = uContents + (len >> 1) - 16;
            end = contents + 32;
            while (contents < end) HashNextFourUniChars(contents[, ], contents);
            // ****X 取最后32个字符做hash运算
        end = uContents + len;
            contents = end - 32;
            while (contents < end) HashNextFourUniChars(contents[, ], contents);
        }
        return result + (result << (actualLen & 31));
    }
    
    • 如果长度大于 96,只有前、中、后 32 个字符做了哈希运算,也就是说在这些字符相同的情况下,其他任意位置的字符发生改变,Hash 值都不会变。
    • 在工程中使用字符串的 hash 方法作为数据是否发生改变的依据,发现方法返回的 hash 值为一个很大的负数,这是因为数值大小超出了数据类型能够表达的范围。可以使用 md5 算法代替系统的 hash 算法。

    十二、Hash 在 iOS 中的应用分析

    ① 关联对象 AssociatedObject 的底层实现采用的数据存储结构(Hash 表 + Hash 表)

    • 关联对象采用的是 HashMap 嵌套 HashMap 的结构存储数据的,简单来说就是根据对象从第一个 HashMap 中取出存储对象所有关联对象的第二个 HashMap,然后根据属性名从第二个 HashMap 中取出属性对应的值和策略。
    • 设计关联对象的初衷:通过传入对象 + 属性名字,就可以找到属性值,方案设计实现好后,查找一个对象的关联对象的基本步骤:
      • 已知条件一:对象,因此引出第一个 HashMap(AssociationsHashMap),用一个能唯一代表对象的值作为 key,用存储对象的所有关联对象的结构(名字:值+策略)作为 value;
      • 已知条件二:属性名字,因此引出第二个 HashMap(ObjectAssociationMap),用属性名字作为key,用属性名字对应的结构体(值+策略)作为 value。

    ② weak 底层实现采用的数据存储结构(Hash 表 + 数组)

    • weak 采用的是一个全局的 HashMap 嵌套数组的结构存储数据的,销毁对象(weak 指针指向的对象)的时候,根据对象从 HashMap 中找到存放所有指向该对象的 weak 指针的数组,然后将数组中的所有元素都置为 nil。
    • weak 的最大特点就是在对象销毁时,自动置 nil,减少访问野指针的风险,这也是设计 weak 的初衷。
    • 方案设计实现好后,weak 指针置 nil 的基本步骤:
      • 对象 dealloc 的时候,从全局的 HashMap 中,根据一个唯一代表对象的值作为 key,找到存储所有指向该对象的 weak 指针的数组;
      • 将数组中的所有元素都置为 nil。
    • 深入了解请参考:iOS之深入解析weak关键字的底层原理

    ③ KVO 底层实现采用的数据存储结构(Hash 表 + 数组)

    ④ iOS App 签名的原理(MD5 + 哈希表 + 非对称加密 RSA)

    • 一致性哈希算法 + 非对称加解密算法:
      • 数字签名:传递数据时会将原始的数据和数字签名一起发送,对方拿到数据后,通过同样的 Hash 算法得到原始数据的 Hash 的值,然后通过非对称加密,将数字签名中的校验 Hash 值解密出来,最后对比两个 Hash 值是否一致。
      • 代码签名:代码签名就是对可执行文件或脚本进行数字签名,用来确认软件在签名后未被修改或损坏的措施。它的原理和数字签名类似,只不过把签名的不是数据,而是代码。
    • 深入了解请参考:iOS逆向之深入解析App签名的双向验证机制和原理

    ⑤ 对象的引用计数存储的位置(Hash 表)

    if 对象支持TaggedPointer {
        return 直接将对象的指针值作为引用计数返回
    } 
    else if 设备是64位环境 && Objective-C2.0 {
        return 对象isa指针的一部分空间(bits_extra_rc)
    }
    else {
        return hash表
    }
    

    ⑥ NSDictionary 的实现原理(Hash 表)

    • NSMapTable 实现:
      • NSDictionary 是使用 NSMapTable 实现的,采用拉链法解决哈希冲突:
    typedef struct {
       NSMapTable *table;
       NSInteger i;
       struct _NSMapNode *j;
    } NSMapEnumerator;
    
      • 上述结构体描述了遍历一个 NSMapTable 时的一个指针对象,其中包含 table 对象自身的指针,计数值和节点指针:
    typedef struct {
       NSUInteger (*hash)(NSMapTable *table,const void *);
       BOOL (*isEqual)(NSMapTable *table,const void *,const void *);
       void (*retain)(NSMapTable *table,const void *);
       void (*release)(NSMapTable *table,void *);
       NSString  *(*describe)(NSMapTable *table,const void *);
       const void *notAKeyMarker;
    } NSMapTableKeyCallBacks;
    
      • 上述结构体中存放的是几个函数指针,用于计算 key 的 hash 值,判断 key 是否相等,retain,release 操作:
    typedef struct {
       void (*retain)(NSMapTable *table,const void *);
       void (*release)(NSMapTable *table,void *);
       NSString *(*describe)(NSMapTable *table, const void *);
    } NSMapTableValueCallBacks;
    
      • 上述存放的三个函数指针,定义在对 NSMapTable 插入一对 key、value 时,对 value 对象的操作:
    @interface NSMapTable : NSObject {
       NSMapTableKeyCallBacks *keyCallBacks;
       NSMapTableValueCallBacks *valueCallBacks;
       NSUInteger count;
       NSUInteger nBuckets;
       struct _NSMapNode **buckets;
    }
    
      • 从上面的结构真的能看出 NSMapTable 是一个“哈希表 + 链表”的数据结构吗?在 NSMapTbale 中插入或者删除一个对象的寻找时间 = O(1) + O(m) ,m 为最坏时可能为 n:
        • O(1):对 key 进行 hash 得到 bucket 的位置;
        • O(m):不同的 key 得到相同的 hash 值的 value 存放到链表中,遍历链表的时间。
      • 上面的结论和对应的解释似乎很合理?下面我们继续分析。
    • _CFDictionary 封装:
      – NSDictionary 是对 _CFDictionary 的封装,解决哈希冲突使用的是开放定址线性探测法:
    struct __CFDictionary {
        CFRuntimeBase _base;
        CFIndex _count;
        CFIndex _capacity;
        CFIndex _bucketsNum;
        uintptr_t _marker;
        void *_context;
        CFIndex _deletes;
        CFOptionFlags _xflags;
        const void **_keys;
        const void **_values;
    };
    
      • 从上面的数据结构可以看出 NSDictionary 内部使用了两个指针数组分别保存 keys 和 values,采用的是连续方式存储键值对。拉链法会将 key 和 value 包装成一个结果存储(链表结点),而 Dictionary 的结构拥有 keys 和 values 两个数组(开放寻址线性探测法解决哈希冲突的用的就是两个数组),说明两个数据是被分开存储的,不像是拉链法。
      • NSDictionary 使用开放定址线性探测法解决哈希冲突的原理:NSDictionary 设置的 key 和 value,key 值会根据特定的 hash 函数算出建立的空桶数组,keys 和 values 同样多,然后存储数据的时候,根据 hash 函数算出来的值,找到对应的 index 下标,如果下标已有数据,开放定址法后移动插入,如果空桶数组到达数据阀值,这个时候就会把空桶数组扩容,然后重新哈希插入。
      • 这样一来,把一些不连续的 key-value 值插入到了能建立起关系的 hash 表中,当查找的时候,key 根据哈希算法算出来索引,然后根据索引,直接 index 访问 hash 表 keys 和 hash 表 values,这样查询速度就可以和连续线性存储的数据一样接近 O(1),只是占用空间有点大,性能就很强悍。
      • 如果删除的时候,也会根据 _maker 标记逻辑上的删除,除非 NSDictionary(NSDictionary 本体的hash 值就是 count)内存被移除。
      • NSDictionary 之所以采用这种设计:
        • 出于查询性能的考虑;
        • NSDictionary 在使用过程中总是会很快的被释放,不会长期占用内存。
    • NSDictionary 的存储过程:
      • 通过方法 - (void)setObject:(id)anObject forKey:(id)aKey; 可以看出 key 必须遵循 NSCopy 协议,也就是说 NSDictionary 的 key 是 copy 一份新的,而 value 是浅拷贝的(如果想深拷贝可以使用 NSMapTable)。
      • key 还必须要继承 NSObject,并且重写 -(NSUInteger)hash; 和 -(BOOL)isEqual:(id)object; 两个方法:
        • 第一个函数用于计算 hash 值;
        • 第二个函数用来判断当哈希值相同的时候 value 是否相同(解决哈希冲突)。

    ⑦ Runloop 与线程的存储关系

    • 线程和 Runloop 之间是一一(子线程可以没有)对应的,其关系是保存在一个全局的 Dictionary 里。
    • 线程刚创建时并没有 Runloop,如果你不主动获取,那它一直都不会有。
    • Runloop 的创建是发生在第一次获取时,Runloop 的销毁是发生在线程结束时,只能在一个线程的内部获取其 Runloop(主线程除外)。
    • Runloop 保存在一个全局的可变字典中,key 是 pthread_t,value 是 cfrunloopref,即 Hash 表。
    • 深入了解请参考:iOS之深入解析Runloop的底层原理
    展开全文
  • 计算机在日常生工作应用

    千次阅读 2021-06-17 11:16:42
    计算机在日常生活、工作应用随着信息时代的到来,人们在物质需求不断得到满足的同时,对各种信息的需求也日益增强,计算机也逐渐成为人们日常...2. 运算精度高(一般可达十几、几十、甚至几百以上的有效...
  • 嵌入式系统在生活有哪些应用

    千次阅读 2021-07-08 02:24:28
    该楼层疑似违规已被系统折叠隐藏此楼查看此楼1、嵌入式系统在生活有哪些应用 嵌入式系统的应用主要有消费电子领域和工控领域; 和我们生活更紧密的是消费电子领域,比方说车载电脑,掌上电脑,PMP,智能手机等2、...
  • 概述 单片机应用种,操作各种芯片,都要操作对应的寄存器,一些芯片时常出现,低位在前高位在后,有时通过逻辑分析仪抓到波形又是反向,在编写程序时,每次需要都要...//uint32_t翻转 uint32_t Reverse32Bit...
  • excel取后面几位数

    千次阅读 2021-01-14 10:41:59
    而在实际应用中保留1或2小数即可,因此需要对计算结果重新取小数位数,但问题随之而来,有些结果是整数,再保留小数显然不合适,所以就要实现有小数时保留小数,小数点后为 0 时只保留整数。另外,当一些单元格...
  • 来源:腾讯研究院编辑:陈近梅2021年1月9日,在腾讯研究院举办的“腾讯科技向善暨数字未来大会2021”上,《变量:2021数字科技前沿应用趋势》报告正式发布。该报告由腾讯研究院发起...
  • 计算机关于小数点的一点疑问.老师说过“计算机不能存小数点,约定‘定点’来存储.”设置了固定的小数点位置,...一般地说,小数点可约定固定在任何数位之后,但常用下列两种形式: ①定点纯小数:约定小数点位置固...
  • “本文从增强现实技术在一些行业的实际场景应用举例,以便帮助我们更好的理解增强现实技术。”增强现实核心技术产业联盟丨来源realcat丨编辑一、生产和工作场景1、屏幕生成:在任何时候都可以生...
  • 盘点那些生活的云计算应用场景

    千次阅读 2021-05-07 09:49:09
    然而除了推动产业的云上升级,云计算也落地了多个日常应用场景,不知不觉改变着我们的生活。 智能家居 智能家居从技术上分析:就是一个家用的小型物联网,通过各类传感器采集信息,并通过对采集的数据...
  • 文章首先阐述机器学习技术在网络空间安全应用研究应用流程,然后从系统安全,网络安全和应用安全三个层面介绍了机器学习在网络空间安全领域的解决方案,归纳了这些解决方案的安全特征及常用的机器学习算法,...
  • 密码算法在比特币应用

    千次阅读 2021-10-18 15:58:16
    因此,从实际应用角度来说,比特币是不可篡改和不可伪造的。加上它本身具有一定的成本和稀缺性,因此具有一定的信用。因此,比特币具有货币的特征。 2 比特币的特点 总结以下,比特币具有如下特点: 不依靠特定货币...
  • 点击上方蓝字关注我们大数据技术在疫情精准防控应用李刚,郑佳,尹华山,黄文超广州市数字政府运营中心,广东 广州 510623摘要:以X市为例,针对超大城市的实际情况,基于大数据处...
  • 话题:在微型计算机,应用最普遍的西文字符编码是什么回答:美国佬的ASCII,没办法,计算机是他们发明的。参考回答:ASCII码话题:微机常用的西文字符编码是什么?回答:微机普遍使用的字符编码是ASCII码吗? 完全...
  • 数位进制转换详解

    千次阅读 2021-01-16 20:24:26
    二进制和十进制互相转换 ...注意:权数是以十进制来表示的,相邻是两倍的关系,最大的权数必须最接近被转换的十进制(3765) 第二步,计算下3765含有多少个二进制的权数 3765 - 2048 = 1717,表
  • 首先,PC817中文数据摘要-PC817简介PC817光耦合器广泛用于计算机终端,晶闸管系统设备,测量... 它经常用作各种需要更高精确度的功能电路的耦合设备. 具有完全隔离上下电路的作用,互不影响.pc817的主要功能:1. 电...
  • 哈夫曼树及其应用

    千次阅读 2021-02-13 19:26:16
    哈夫曼树又称最优树,是一类带权路径长度最短的树,在实际中有广泛的用途 1).路径:从树的一个结点到另一个结点之间的分支构成的这两个结点之间的路径 2).路径长度:路径上的分支数目称作路径长度 3).树的路径长度...
  • 展开全部可以通过输出格式说明符来指定精确到小数点后几。比如:printf("%.5f\n", 3.1415927) // 输出_ 3.14159 (其中_ 代表空格)上面的输62616964757a686964616fe4b893e5b19e31333365653935出格式...如果实际数...
  • Android8 Launcher3 桌面应用行列修改

    千次阅读 2021-11-07 14:39:14
    Launcher3控制桌面(WorkSpace)应用图标的行列其实核心来自于InvariantDeviceProfile类,这个类初始化了Launcher3的许多参数。 根据它的成员可以看到它至少控制了Launcher3的如下参数 /** * Number of icons per ...
  • 收藏 | 强化学习应用简述

    千次阅读 2021-05-13 16:13:39
    UCB应用于搜索树得到UCT算法,在AlphaGo发挥了重要作用。 强化学习词汇 在这里汇集了一些强化学习词汇,方便读者查询。 预测 (prediction),或策略评估 (policy evaluation),用来计算一个策略的状态或动作值...
  • ☀️光天化日学C语言☀️(15)- 运算 | 的应用

    千次阅读 多人点赞 2021-07-02 06:31:57
    或 | 的应用
  • 大学计算机应用习题集(参考).doc

    千次阅读 2021-07-04 07:56:25
    第一章 信息社会与计算机—习题1....信息技术是一个综合的技术,下列设备与通信技术密切相关的是____A.计算器 B.手机 C.存储器 D.数码相机3.不是信息技术的核心技术____A.计算机技术 B.操作技术C.微电...
  • 在互联网应用中,每个终端系统可以相互交换信息。这个信息也叫报文.·报文是个大师。它可以包括你想要的任何东西,如文本、数据、电子邮件、音频、视频等。为了将报文从源目的地发送到终端系统,有必要将长报文分成...
  • 函数TEXT - 补0实现数字固定位数输出

    千次阅读 2021-01-24 15:37:02
    日常应用,可能遇到一种场景:Excel某一列单元格的数字位数不一致,实际应用中需要固定位数显示,长度不够通过补前导0。 如下所示: A列值,需要固定4长度显示为B列 使用函数TEXT 格式:TEXT(原值所在单元格,...
  • 《夜深人静写算法》 文章目录 一、前言 二、人物简介 三、右移运算符 1、右移的二进制形态 2、右移的执行结果 3、负数右移的执行结果 4、右移负数位是什么情况 四、右移运算符的应用 1、去掉低 k 2、取低位连续 ...
  • 深度好文 | 超全SLAM技术及应用介绍

    千次阅读 2021-04-18 00:22:46
    在他对 ORB-SLAM vs PTAM 的评价,似乎 PTAM 实际上常常失败(至少在 TUM RGB-D 基准上)。LSD-SLAM 在 TUM RGB-D 基准上的错误通常远高于预期。 基于特征的方法 vs 直接方法 演讲五:Tango 项目和用于图像到图像...
  • 那么它的每秒的传输速率(速, 也叫比特率、取样率)是 22050*16*2 = 705600(bit/s), 换算成字节单位就是 705600/8 = 88200(字节/秒), 播放时间:424644(总字节) / 88200(每秒字节) ≈ 4.8145578(秒)。...
  • 关于操作符/操作 的操作方法和应用 附加(整形提升)(C语言) 1.了解什么是操作(二进制) 2.关于操作符的详解( ‘&’ ‘|’ ‘~’ ) 3.位移操作符(">>","<<") 4.异或的一些妙用 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 540,519
精华内容 216,207
关键字:

中位数的实际应用