13算法案例
A. 十三张扑克算法
积分规则算法如下:
1、牌面大小顺序:A>K>Q>J>10>9>8>7>6>5>4>3>2。
2、牌型大小顺序:一条龙>同花顺>四条>葫芦>同花>顺子>三条>两对>对子>散牌(乌龙)。
3、赢一墩:同一墩,大于其他某个玩家,自己加1注(头墩加1注,中墩加2注,底墩加3注)。
4、输一墩:同一墩,小于其他某个玩家,自己减1注(头墩减1注,中墩减2注,底墩减3注)。
5、强碰(打和):同一墩,与其他玩家大小一样,自己加0注。
游戏规则:
四人中一人为庄家,(也可以四人对比,) 庄家把除去大小王的一副牌牌分成四份,每份十三张。开牌前,各闲家向庄家下注。
各人把十三张牌排成三段(道),称头(道)、二道及尾(道)。头有三张,二道及尾各五张。头道必须小于二道,二道必须小于尾道,否则称为“相公”。凡“相公”者全赔。
头段因为只有三张牌,因此不算顺、花。只可能是不成花式(称无头),一对或三条。各人排好牌后,打开牌跟庄家比较大小。头跟头比,二道跟二道比,尾跟尾比。
比较时,先比牌型。牌型相同时,比点数。部分玩法的规则,比点数时由最大点数的牌比起,相同时比第二大的牌,如此类推。倘若完全相同,比最大点数牌的花色。
部分玩法的规则订成对庄家稍为有利:只比点数最大的一只牌。倘若相同,一律由庄家胜。任何一方遇上以下的组合通吃,称为“报到”。
B. 13×14的数学最快算法
13的二次方+13=169+13=182
C. 13开根号是多少
√13是一个无理数,等于3.605551275464.....
开根号就像求一个数的几次方的反义词一样,比如3的2次方是9,那么9开根号2就是3。在中学阶段,涉及开平方的计算,一是查数学用表,一是利用计算器。而在解题时用的最多的是利用分解质因数来解决。
根号是一个数学符号。根号是用来表示对一个数或一个代数式进行开方运算的符号。若aⁿ=b,那么a是b开n次方的n次方根或a是b的1/n次方。开n次方手写体和印刷体用表示,被开方的数或代数式写在符号左方√ ̄的右边和符号上方一横部分的下方共同包围的区域中,而且不能出界。
(3)13算法案例扩展阅读:
1、写根号:
先在格子中间画向右上角的短斜线,然后笔画不断画右下中斜线,同样笔画不断画右上长斜线再在格子接近上方的地方根据自己的需要画一条长度适中的横线,不够再补足。(这里只重点介绍笔顺和写法,可以根据印刷体参考本条模仿写即可,不硬性要求)
2、写被开方的数或式子:
被开方的数或代数式写在符号左方v形部分的右边和符号上方一横部分的下方共同包围的区域中,而且不能出界,若被开方的数或代数式过长,则上方一横必须延长确保覆盖下方的被开方数或代数式。
3、写开方数或者式子:
开n次方的n写在符号√ ̄的左边,n=2(平方根)时n可以忽略不写,但若是立方根(三次方根)、四次方根等,是必须书写。
一般来说能够开方开的尽的,算一两次基本结果就出来了。举个例子:计算469225的平方根。首先我们发现600^2<469225<700^2,我们可以挑选650作为第一次计算的数。即算 (650+469225/650)/2得到685.9。而685附近只有685^2末尾数字是5,因此685^2=469225
对于那些开方开不尽的数,用这种方法算两三次精度就很可观了,一般达到小数点后好几位。实际中这种算法也是计算机用于开方的算法。
D. 13乘3有几种不同的算法
1、13×3=39
2、13×3=13+13+13=39
3、13×3=(10+3)×3=10×3+3×3=39
E. 二十四点1~13各种算法及运算过程
首先要对789很敏感
无论什么数 先往789上凑
其余的不知道怎么说。。。每什么明显规律
F. 分治算法的应用实例
下面通过实例加以说明: 给你一个装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。比较硬币1与硬币2的重量。假如硬币1比硬币2轻,则硬币1是伪造的;假如硬币2比硬币1轻,则硬币2是伪造的。这样就完成了任务。假如两硬币重量相等,则比较硬币3和硬币4。同样,假如有一个硬币轻一些,则寻找伪币的任务完成。假如两硬币重量相等,则继续比较硬币5和硬币6。按照这种方式,可以最多通过8次比较来判断伪币的存在并找出这一伪币。
另外一种方法就是利用分而治之方法。假如把1 6硬币的例子看成一个大的问题。第一步,把这一问题分成两个小问题。随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组。这样,就把1 6个硬币的问题分成两个8硬币的问题来解决。第二步,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。最后,在第三步中,用第二步的结果得出原先1 6个硬币问题的答案。若仅仅判断硬币是否存在,则第三步非常简单。无论A组还是B组中有伪币,都可以推断这1 6个硬币中存在伪币。因此,仅仅通过一次重量的比较,就可以判断伪币是否存在。
假设需要识别出这一伪币。把两个或三个硬币的情况作为不可再分的小问题。注意如果只有一个硬币,那么不能判断出它是否就是伪币。在一个小问题中,通过将一个硬币分别与其他两个硬币比较,最多比较两次就可以找到伪币。这样,1 6硬币的问题就被分为两个8硬币(A组和B组)的问题。通过比较这两组硬币的重量,可以判断伪币是否存在。如果没有伪币,则算法终止。否则,继续划分这两组硬币来寻找伪币。假设B是轻的那一组,因此再把它分成两组,每组有4个硬币。称其中一组为B1,另一组为B2。比较这两组,肯定有一组轻一些。如果B1轻,则伪币在B1中,再将B1又分成两组,每组有两个硬币,称其中一组为B1a,另一组为B1b。比较这两组,可以得到一个较轻的组。由于这个组只有两个硬币,因此不必再细分。比较组中两个硬币的重量,可以立即知道哪一个硬币轻一些。较轻的硬币就是所要找的伪币。 在n个元素中找出最大元素和最小元素。我们可以把这n个元素放在一个数组中,用直接比较法求出。算法如下:
void maxmin1(int A[],int n,int *max,int *min)
{ int i;
*min=*max=A[0];
for(i=0;i <= n;i++)
{ if(A[i]> *max) *max= A[i];
if(A[i] < *min) *min= A[i];
}
}
上面这个算法需比较2(n-1)次。能否找到更好的算法呢?我们用分治策略来讨论。
把n个元素分成两组:
A1={A[1],...,A[int(n/2)]}和A2={A[INT(N/2)+1],...,A[N]}
分别求这两组的最大值和最小值,然后分别将这两组的最大值和最小值相比较,求出全部元素的最大值和最小值。如果A1和A2中的元素多于两个,则再用上述方法各分为两个子集。直至子集中元素至多两个元素为止。
例如有下面一组元素:-13,13,9,-5,7,23,0,15。用分治策略比较的算法如下:
void maxmin2(int A[],int i,int j,int *max,int *min)
/*A存放输入的数据,i,j存放数据的范围,初值为0,n-1,*max,*min 存放最大和最小值*/
{ int mid,max1,max2,min1,min2;
if (j==i) {最大和最小值为同一个数;return;}
if (j-1==i) {将两个数直接比较,求得最大会最小值;return;}
mid=(i+j)/2;
求i~mid之间的最大最小值分别为max1,min1;
求mid+1~j之间的最大最小值分别为max2,min2;
比较max1和max2,大的就是最大值;
比较min1和min2,小的就是最小值;
} 题目:在一个(2^k)*(2^k)个方格组成的棋盘上,有一个特殊方格与其他方格不同,称为特殊方格,称这样的棋盘为一个特殊棋盘。我们要求对棋盘的其余部分用L型方块填满(注:L型方块由3个单元格组成。即围棋中比较忌讳的愚形三角,方向随意),且任何两个L型方块不能重叠覆盖。L型方块的形态如下:
题目的解法使用分治法,即子问题和整体问题具有相同的形式。我们对棋盘做一个分割,切割一次后的棋盘如图1所示,我们可以看到棋盘被切成4个一样大小的子棋盘,特殊方块必定位于四个子棋盘中的一个。假设如图1所示,特殊方格位于右上角,我们把一个L型方块(灰色填充)放到图中位置。这样对于每个子棋盘又各有一个“特殊方块”,我们对每个子棋盘继续这样分割,直到子棋盘的大小为1为止。
用到的L型方块需要(4^k-1)/3 个,算法的时间是O(4^k),是渐进最优解法。
本题目的C语言的完整代码如下(TC2.0下调试),运行时,先输入k的大小,(1<=k<=6),然后分别输入特殊方格所在的位置(x,y), 0<=x,y<=(2^k-1)。 #include<stdio.h>//#include<conio.h>//#include<math.h>inttitle=1;intboard[64][64];voidchessBoard(inttr,inttc,intdr,intdc,intsize){ints,t;if(size==1)return;t=title++;s=size/2;if(dr<tr+s&&dc<tc+s)chessBoard(tr,tc,dr,dc,s);else{board[tr+s-1][tc+s-1]=t;chessBoard(tr,tc,tr+s-1,tc+s-1,s);}if(dr<tr+s&&dc>=tc+s)chessBoard(tr,tc+s,dr,dc,s);else{board[tr+s-1][tc+s]=t;chessBoard(tr,tc+s,tr+s-1,tc+s,s);}if(dr>=tr+s&&dc<tc+s)chessBoard(tr+s,tc,dr,dc,s);else{board[tr+s][tc+s-1]=t;chessBoard(tr+s,tc,tr+s,tc+s-1,s);}if(dr>=tr+s&&dc>=tc+s)chessBoard(tr+s,tc+s,dr,dc,s);else{board[tr+s][tc+s]=t;chessBoard(tr+s,tc+s,tr+s,tc+s,s);}}voidmain(){intdr=0,dc=0,s=1,i=0,j=0;printf(printinthesizeofchess:
);scanf(%d,&s);printf(printinspecalpointx,y:
);scanf(%d%d,&dr,&dc);if(dr<s&&dc<s){chessBoard(0,0,dr,dc,s);for(i=0;i<s;i++){for(j=0;j<s;j++){printf(%4d,board[i][j]);}printf(
);}}elseprintf(thewrongspecalpoint!!
);getch();}
G. 一个2一个3一个5等于13有多少种算法
1,2的3次方+5=13
2,2*5+3=13
3,3*5-2=13
共三种算法。
H. 黄金分割点的算法,要具体的。给个数字13。要所有算的步骤。谢勒
黄金分割点
(golden section ratio)
在分割时.在长度为全长的约0.618处进行分割.就叫作黄金分割.这个分割点就叫做黄金分割点
把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。其比值是一个无理数,用分数表示为√5-1/2,取其前三位数字的近似值是0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个十分有趣的数字,我们以0.618来近似表示,通过简单的计算就可以发现:
1/0.618=1.618
(1-0.618)/0.618=0.618
这个数值的作用不仅仅体现在诸如绘画、雕塑、音乐、建筑等艺术领域,而且在管理、工程设计等方面也有着不可忽视的作用。
让我们首先从一个数列开始,它的前面几个数是:1、1、2、3、5、8、13、21、34、55、89、144…..这个数列的名字叫做"菲波那契数列",这些数被称为"菲波那契数"。特点是即除前两个数(数值为1)之外,每个数都是它前面两个数之和。
菲波那契数列与黄金分割有什么关系呢?经研究发现,相邻两个菲波那契数的比值是随序号的增加而逐渐趋于黄金分割比的。即f(n)/f(n-1)-→0.618…。由于菲波那契数都是整数,两个整数相除之商是有理数,所以只是逐渐逼近黄金分割比这个无理数。但是当我们继续计算出后面更大的菲波那契数时,就会发现相邻两数之比确实是非常接近黄金分割比的。
一个很能说明问题的例子是五角星/正五边形。五角星是非常美丽的,我们的国旗上就有五颗,还有不少国家的国旗也用五角星,这是为什么?因为在五角星中可以找到的所有线段之间的长度关系都是符合黄金分割比的。正五边形对角线连满后出现的所有三角形,都是黄金分割三角形。
由于五角星的顶角是36度,这样也可以得出黄金分割的数值为2Sin18度。
黄金分割点约等于0.618:1
是指把一线段分为两部分,使得原来线段的长跟较长的那部分的比为黄金分割的点。线段上有两个这样的点。
利用线段上的两黄金分割点,可作出正五角星,正五边形。
2000多年前,古希腊雅典学派的第三大算学家欧道克萨斯首先提出黄金分割。所谓黄金分割,指的是把长为L的线段分为两部分,使其中一部分对于全部之比,等于另一部分对于该部分之比。而计算黄金分割最简单的方法,是计算斐波那契数列1,1,2,3,5,8,13,21,...后二数之比2/3,3/5,4/8,8/13,13/21,...近似值的。
黄金分割在文艺复兴前后,经过阿拉伯人传入欧洲,受到了欧洲人的欢迎,他们称之为"金法",17世纪欧洲的一位数学家,甚至称它为"各种算法中最可宝贵的算法"。这种算法在印度称之为"三率法"或"三数法则",也就是我们现在常说的比例方法。
其实有关"黄金分割",我国也有记载。虽然没有古希腊的早,但它是我国古代数学家独立创造的,后来传入了印度。经考证。欧洲的比例算法是源于我国而经过印度由阿拉伯传入欧洲的,而不是直接从古希腊传入的。
因为它在造型艺术中具有美学价值,在工艺美术和日用品的长宽设计中,采用这一比值能够引起人们的美感,在实际生活中的应用也非常广泛,建筑物中某些线段的比就科学采用了黄金分割,舞台上的报幕员并不是站在舞台的正中央,而是偏在台上一侧,以站在舞台长度的黄金分割点的位置最美观,声音传播的最好。就连植物界也有采用黄金分割的地方,如果从一棵嫩枝的顶端向下看,就会看到叶子是按照黄金分割的规律排列着的。在很多科学实验中,选取方案常用一种0.618法,即优选法,它可以使我们合理地安排较少的试验次数找到合理的西方和合适的工艺条件。正因为它在建筑、文艺、工农业生产和科学实验中有着广泛而重要的应用,所以人们才珍贵地称它为"黄金分割"。
黄金分割(Golden Section)是一种数学上的比例关系。黄金分割具有严格的比例性、艺术性、和谐性,蕴藏着丰富的美学价值。应用时一般取1.618 ,就像圆周率在应用时取3.14一样。
发现历史
由于公元前6世纪古希腊的毕达哥拉斯学派研究过正五边形和正十边形的作图,因此现代数学家们推断当时毕达哥拉斯学派已经触及甚至掌握了黄金分割。
公元前4世纪,古希腊数学家欧多克索斯第一个系统研究了这一问题,并建立起比例理论。
公元前300年前后欧几里得撰写《几何原本》时吸收了欧多克索斯的研究成果,进一步系统论述了黄金分割,成为最早的有关黄金分割的论着。
中世纪后,黄金分割被披上神秘的外衣,意大利数家帕乔利称中末比为神圣比例,并专门为此着书立说。德国天文学家开普勒称黄金分割为神圣分割。
到19世纪黄金分割这一名称才逐渐通行。黄金分割数有许多有趣的性质,人类对它的实际应用也很广泛。最着名的例子是优选学中的黄金分割法或0.618法,是由美国数学家基弗于1953年首先提出的,70年代在中国推广。
|..........a...........|
+-------------+--------+ -
| | | .
| | | .
| B | A | b
| | | .
| | | .
| | | .
+-------------+--------+ -
|......b......|..a-b...|
通常用希腊字母 表示这个值。
黄金分割奇妙之处,在于其比例与其倒数是一样的。例如:1.618的倒数是0.618,而1.618:1与1:0.618是一样的。
确切值为根号5+1/2
黄金分割数是无理数,前面的2000位为:
0.6180339887 4989484820 4586834365 6381177203 0917980576 : 50
2862135448 6227052604 6281890244 9707207204 1893911374 : 100
8475408807 5386891752 1266338622 2353693179 3180060766 : 150
7263544333 8908659593 9582905638 3226613199 2829026788 : 200
0675208766 8925017116 9620703222 1043216269 5486262963 : 250
1361443814 9758701220 3408058879 5445474924 6185695364 : 300
8644492410 4432077134 4947049565 8467885098 7433944221 : 350
2544877066 4780915884 6074998871 2400765217 0575179788 : 400
3416625624 9407589069 7040002812 1042762177 1117778053 : 450
1531714101 1704666599 1466979873 1761356006 7087480710 : 500
1317952368 9427521948 4353056783 0022878569 9782977834 : 550
7845878228 9110976250 0302696156 1700250464 3382437764 : 600
8610283831 2683303724 2926752631 392473 1671112115 : 650
8818638513 3162038400 5222165791 2866752946 5490681131 : 700
7159934323 5973494985 0904094762 1322298101 7261070596 : 750
1164562990 9816290555 2085247903 5240602017 2799747175 : 800
3427775927 7862561943 2082750513 1218156285 5122248093 : 850
9471234145 1702237358 0577278616 0086883829 5230459264 : 900
7878017889 9219902707 7690389532 1968198615 1437803149 : 950
9741106926 0886742962 2675756052 3172777520 3536139362 : 1000
1076738937 6455606060 5921658946 6759551900 4005559089 : 1050
5022953094 2312482355 2122124154 4400647034 0565734797 : 1100
6639723949 4994658457 8873039623 0903750339 9385621024 : 1150
2369025138 6804145779 9569812244 5747178034 1731264532 : 1200
2041639723 2134044449 4873023154 1767689375 2103068737 : 1250
8803441700 9395440962 7955898678 7232095124 2689355730 : 1300
9704509595 6844017555 1988192180 2064052905 5189349475 : 1350
9260073485 2282101088 1946445442 2231889131 9294689622 : 1400
0023014437 7026992300 780308 1807545192 8877050210 : 1450
9684249362 7135925187 6077788466 5836150238 9134933331 : 1500
2231053392 3213624319 2637289106 7050339928 2265263556 : 1550
2090297986 4247275977 2565508615 4875435748 2647181414 : 1600
5127000602 3890162077 7322449943 5308899909 5016803281 : 1650
1219432048 1964387675 8633147985 7191139781 5397807476 : 1700
1507722117 5082694586 3932045652 0989698555 6781410696 : 1750
8372884058 7461033781 0544439094 3683583581 3811311689 : 1800
9385557697 5484149144 5341509129 5407005019 4775486163 : 1850
0754226417 2939468036 7319805861 8339183285 9913039607 : 1900
2014455950 4497792120 7612478564 5916160837 0594987860 : 1950
0697018940 9886400764 4361709334 1727091914 3365013715 : 2000
我们常常听说有“黄金分割”这个词,“黄金分割”当然不是指的怎样分割黄金,这是一个比喻的说法,就是说分割的比例像黄金一样珍贵。那么这个比例是多少呢?是0.618。人们把这个比例的分割点,叫做黄金分割点,把0.618叫做黄金数。并且人们认为如果符合这一比例的话,就会显得更美、更好看、更协调。在生活中,对“黄金分割”有着很多的应用。
最完美的人体:肚脐到脚底的距离/头顶到脚底的距离=0.618
最漂亮的脸庞:眉毛到脖子的距离/头顶到脖子的距离=0.618
I. 蛇形分组法的具体例子
蛇行分组法:首先将运动员按成绩排序,再根据需排的组数,按蛇行走向将运动员排列分成不同的小组;如果同组中有多个同单位的运动员,只能就近上下调整.然后抽签排定各组的比赛顺序和运动员的比赛道次
A B C D
1 2 3 4
8 7 6 5
9 10 11 12
16 15 14 13
算法.
1)把1,2号挑出来.(1/2)
2)把3,4号从右向左分别配给2,1号.(1/4, 2/3)
3)把5,6,7,8号从左向右分别配给前4号.(1/5, 4/6, 2/7, 3/8)
4)把9-16号从右向左分别配给前8号.(1/16, 5/15, 4/14, 6/13, 2/12, 7/11, 3/10, 8/9)
........
上面算法的基本思想是:
把1,2号种子选出来, 为了避免他们过早相遇, 我们用3,4号选手分别配给他们, 即插入他们中间形成(1/4)(2/3)的对阵. 然后再用5,6号选择把(1/4)拆开形成(1/5)(4/6)的对阵, 用7,8号选手把(2/3)拆开形成(2/7)(3/8)的对阵......
每次插入新的选手时, 使用蛇形次序, 即第一次从右到左, 第二次从左到右....
经过多次拆分插入后, 每次获得的对阵表如同下面的三角形所示:
1/2
1/4,│ 2/3
1/5, 4/6,│ 2/7, 3/8
1/16, 5/15, 4/14, 6/13,│ 2/12, 7/11, 3/10, 8/9
如果是32个选手, 就继续把17配给1号, 18配给16号, 19配5, 20配15, 21配4, 22配14.........即上面最后一行, 由左到右依次分配.
这样种子们就分散开了. 相邻组的胜者进行淘汰赛也不会有种子过早相遇. 其实上述四个步骤中的配对也就是种子们获胜后的配对形式. 上述算法将所有排好后, 相邻两组的四个人可以组成一个小组打循环赛.
J. hadoop的maprece常见算法案例有几种
基本MapRece模式
计数与求和
问题陈述:
有许多文档,每个文档都有一些字段组成。需要计算出每个字段在所有文档中的出现次数或者这些字段的其他什么统计值。例如,给定一个log文件,其中的每条记录都包含一个响应时间,需要计算出平均响应时间。
解决方案:
让我们先从简单的例子入手。在下面的代码片段里,Mapper每遇到指定词就把频次记1,Recer一个个遍历这些词的集合然后把他们的频次加和。
1 class Mapper
2 method Map(docid id, doc d)
3 for all term t in doc d do
4 Emit(term t, count 1)
5
6 class Recer
7 method Rece(term t, counts [c1, c2,...])
8 sum = 0
9 for all count c in [c1, c2,...] do
10 sum = sum + c
11 Emit(term t, count sum)
这种方法的缺点显而易见,Mapper提交了太多无意义的计数。它完全可以通过先对每个文档中的词进行计数从而减少传递给Recer的数据量:
1 class Mapper
2 method Map(docid id, doc d)
3 H = new AssociativeArray
4 for all term t in doc d do
5 H{t} = H{t} + 1
6 for all term t in H do
7 Emit(term t, count H{t})
如果要累计计数的的不只是单个文档中的内容,还包括了一个Mapper节点处理的所有文档,那就要用到Combiner了:
1 class Mapper
2 method Map(docid id, doc d)
3 for all term t in doc d do
4 Emit(term t, count 1)
5
6 class Combiner
7 method Combine(term t, [c1, c2,...])
8 sum = 0
9 for all count c in [c1, c2,...] do
10 sum = sum + c
11 Emit(term t, count sum)
12
13 class Recer
14 method Rece(term t, counts [c1, c2,...])
15 sum = 0
16 for all count c in [c1, c2,...] do
17 sum = sum + c
18 Emit(term t, count sum)
应用:Log 分析, 数据查询
整理归类
问题陈述:
有一系列条目,每个条目都有几个属性,要把具有同一属性值的条目都保存在一个文件里,或者把条目按照属性值分组。 最典型的应用是倒排索引。
解决方案:
解决方案很简单。 在 Mapper 中以每个条目的所需属性值作为 key,其本身作为值传递给 Recer。 Recer 取得按照属性值分组的条目,然后可以处理或者保存。如果是在构建倒排索引,那么 每个条目相当于一个词而属性值就是词所在的文档ID。
应用:倒排索引, ETL
过滤 (文本查找),解析和校验
问题陈述:
假设有很多条记录,需要从其中找出满足某个条件的所有记录,或者将每条记录传换成另外一种形式(转换操作相对于各条记录独立,即对一条记录的操作与其他记录无关)。像文本解析、特定值抽取、格式转换等都属于后一种用例。
解决方案:
非常简单,在Mapper 里逐条进行操作,输出需要的值或转换后的形式。
应用:日志分析,数据查询,ETL,数据校验
分布式任务执行
问题陈述:
大型计算可以分解为多个部分分别进行然后合并各个计算的结果以获得最终结果。
解决方案: 将数据切分成多份作为每个 Mapper 的输入,每个Mapper处理一份数据,执行同样的运算,产生结果,Recer把多个Mapper的结果组合成一个。
案例研究: 数字通信系统模拟
像 WiMAX 这样的数字通信模拟软件通过系统模型来传输大量的随机数据,然后计算传输中的错误几率。 每个 Mapper 处理样本 1/N 的数据,计算出这部分数据的错误率,然后在 Recer 里计算平均错误率。
应用:工程模拟,数字分析,性能测试
排序
问题陈述:
有许多条记录,需要按照某种规则将所有记录排序或是按照顺序来处理记录。
解决方案: 简单排序很好办 – Mappers 将待排序的属性值为键,整条记录为值输出。 不过实际应用中的排序要更加巧妙一点, 这就是它之所以被称为MapRece 核心的原因(“核心”是说排序?因为证明Hadoop计算能力的实验是大数据排序?还是说Hadoop的处理过程中对key排序的环节?)。在实践中,常用组合键来实现二次排序和分组。
MapRece 最初只能够对键排序, 但是也有技术利用可以利用Hadoop 的特性来实现按值排序。想了解的话可以看这篇博客。
按照BigTable的概念,使用 MapRece来对最初数据而非中间数据排序,也即保持数据的有序状态更有好处,必须注意这一点。换句话说,在数据插入时排序一次要比在每次查询数据的时候排序更高效。
应用:ETL,数据分析
非基本 MapRece 模式
迭代消息传递 (图处理)
问题陈述:
假设一个实体网络,实体之间存在着关系。 需要按照与它比邻的其他实体的属性计算出一个状态。这个状态可以表现为它和其它节点之间的距离, 存在特定属性的邻接点的迹象, 邻域密度特征等等。
解决方案:
网络存储为系列节点的结合,每个节点包含有其所有邻接点ID的列表。按照这个概念,MapRece 迭代进行,每次迭代中每个节点都发消息给它的邻接点。邻接点根据接收到的信息更新自己的状态。当满足了某些条件的时候迭代停止,如达到了最大迭代次数(网络半径)或两次连续的迭代几乎没有状态改变。从技术上来看,Mapper 以每个邻接点的ID为键发出信息,所有的信息都会按照接受节点分组,recer 就能够重算各节点的状态然后更新那些状态改变了的节点。下面展示了这个算法:
1 class Mapper
2 method Map(id n, object N)
3 Emit(id n, object N)
4 for all id m in N.OutgoingRelations do
5 Emit(id m, message getMessage(N))
6
7 class Recer
8 method Rece(id m, [s1, s2,...])
9 M = null
10 messages = []
11 for all s in [s1, s2,...] do
12 if IsObject(s) then
13 M = s
14 else // s is a message
15 messages.add(s)
16 M.State = calculateState(messages)
17 Emit(id m, item M)
一个节点的状态可以迅速的沿着网络传全网,那些被感染了的节点又去感染它们的邻居,整个过程就像下面的图示一样:
案例研究: 沿分类树的有效性传递
问题陈述:
这个问题来自于真实的电子商务应用。将各种货物分类,这些类别可以组成一个树形结构,比较大的分类(像男人、女人、儿童)可以再分出小分类(像男裤或女装),直到不能再分为止(像男式蓝色牛仔裤)。这些不能再分的基层类别可以是有效(这个类别包含有货品)或者已无效的(没有属于这个分类的货品)。如果一个分类至少含有一个有效的子分类那么认为这个分类也是有效的。我们需要在已知一些基层分类有效的情况下找出分类树上所有有效的分类。
解决方案:
这个问题可以用上一节提到的框架来解决。我们咋下面定义了名为 getMessage和 calculateState 的方法:
1 class N
2 State in {True = 2, False = 1, null = 0},
3 initialized 1 or 2 for end-of-line categories, 0 otherwise
4 method getMessage(object N)
5 return N.State
6 method calculateState(state s, data [d1, d2,...])
7 return max( [d1, d2,...] )
案例研究:广度优先搜索
问题陈述:需要计算出一个图结构中某一个节点到其它所有节点的距离。
解决方案: Source源节点给所有邻接点发出值为0的信号,邻接点把收到的信号再转发给自己的邻接点,每转发一次就对信号值加1:
1 class N
2 State is distance,
3 initialized 0 for source node, INFINITY for all other nodes
4 method getMessage(N)
5 return N.State + 1
6 method calculateState(state s, data [d1, d2,...])
7 min( [d1, d2,...] )
案例研究:网页排名和 Mapper 端数据聚合
这个算法由Google提出,使用权威的PageRank算法,通过连接到一个网页的其他网页来计算网页的相关性。真实算法是相当复杂的,但是核心思想是权重可以传播,也即通过一个节点的各联接节点的权重的均值来计算节点自身的权重。
1 class N
2 State is PageRank
3 method getMessage(object N)
4 return N.State / N.OutgoingRelations.size()
5 method calculateState(state s, data [d1, d2,...])
6 return ( sum([d1, d2,...]) )
要指出的是上面用一个数值来作为评分实际上是一种简化,在实际情况下,我们需要在Mapper端来进行聚合计算得出这个值。下面的代码片段展示了这个改变后的逻辑 (针对于 PageRank 算法):
1 class Mapper
2 method Initialize
3 H = new AssociativeArray
4 method Map(id n, object N)
5 p = N.PageRank / N.OutgoingRelations.size()
6 Emit(id n, object N)
7 for all id m in N.OutgoingRelations do
8 H{m} = H{m} + p
9 method Close
10 for all id n in H do
11 Emit(id n, value H{n})
12
13 class Recer
14 method Rece(id m, [s1, s2,...])
15 M = null
16 p = 0
17 for all s in [s1, s2,...] do
18 if IsObject(s) then
19 M = s
20 else
21 p = p + s
22 M.PageRank = p
23 Emit(id m, item M)
应用:图分析,网页索引
值去重 (对唯一项计数)
问题陈述: 记录包含值域F和值域 G,要分别统计相同G值的记录中不同的F值的数目 (相当于按照 G分组).
这个问题可以推而广之应用于分面搜索(某些电子商务网站称之为Narrow Search)
Record 1: F=1, G={a, b}
Record 2: F=2, G={a, d, e}
Record 3: F=1, G={b}
Record 4: F=3, G={a, b}
Result:
a -> 3 // F=1, F=2, F=3
b -> 2 // F=1, F=3
d -> 1 // F=2
e -> 1 // F=2
解决方案 I:
第一种方法是分两个阶段来解决这个问题。第一阶段在Mapper中使用F和G组成一个复合值对,然后在Recer中输出每个值对,目的是为了保证F值的唯一性。在第二阶段,再将值对按照G值来分组计算每组中的条目数。
第一阶段:
1 class Mapper
2 method Map(null, record [value f, categories [g1, g2,...]])
3 for all category g in [g1, g2,...]
4 Emit(record [g, f], count 1)
5
6 class Recer
7 method Rece(record [g, f], counts [n1, n2, ...])
8 Emit(record [g, f], null )
第二阶段:
1 class Mapper
2 method Map(record [f, g], null)
3 Emit(value g, count 1)
4
5 class Recer
6 method Rece(value g, counts [n1, n2,...])
7 Emit(value g, sum( [n1, n2,...] ) )
解决方案 II:
第二种方法只需要一次MapRece 即可实现,但扩展性不强。算法很简单-Mapper 输出值和分类,在Recer里为每个值对应的分类去重然后给每个所属的分类计数加1,最后再在Recer结束后将所有计数加和。这种方法适用于只有有限个分类,而且拥有相同F值的记录不是很多的情况。例如网络日志处理和用户分类,用户的总数很多,但是每个用户的事件是有限的,以此分类得到的类别也是有限的。值得一提的是在这种模式下可以在数据传输到Recer之前使用Combiner来去除分类的重复值。
1 class Mapper
2 method Map(null, record [value f, categories [g1, g2,...] )
3 for all category g in [g1, g2,...]
4 Emit(value f, category g)
5
6 class Recer
7 method Initialize
8 H = new AssociativeArray : category -> count
9 method Rece(value f, categories [g1, g2,...])
10 [g1', g2',..] = ExcludeDuplicates( [g1, g2,..] )
11 for all category g in [g1', g2',...]
12 H{g} = H{g} + 1
13 method Close
14 for all category g in H do
15 Emit(category g, count H{g})
应用:日志分析,用户计数
互相关
问题陈述:有多个各由若干项构成的组,计算项两两共同出现于一个组中的次数。假如项数是N,那么应该计算N*N。
这种情况常见于文本分析(条目是单词而元组是句子),市场分析(购买了此物的客户还可能购买什么)。如果N*N小到可以容纳于一台机器的内存,实现起来就比较简单了。
配对法
第一种方法是在Mapper中给所有条目配对,然后在Recer中将同一条目对的计数加和。但这种做法也有缺点:
使用 combiners 带来的的好处有限,因为很可能所有项对都是唯一的
不能有效利用内存
1 class Mapper
2 method Map(null, items [i1, i2,...] )
3 for all item i in [i1, i2,...]
4 for all item j in [i1, i2,...]
5 Emit(pair [i j], count 1)
6
7 class Recer
8 method Rece(pair [i j], counts [c1, c2,...])
9 s = sum([c1, c2,...])
10 Emit(pair[i j], count s)
Stripes Approach(条方法?不知道这个名字怎么理解)
第二种方法是将数据按照pair中的第一项来分组,并维护一个关联数组,数组中存储的是所有关联项的计数。The second approach is to group data by the first item in pair and maintain an associative array (“stripe”) where counters for all adjacent items are accumulated. Recer receives all stripes for leading item i, merges them, and emits the same result as in the Pairs approach.
中间结果的键数量相对较少,因此减少了排序消耗。
可以有效利用 combiners。
可在内存中执行,不过如果没有正确执行的话也会带来问题。
实现起来比较复杂。
一般来说, “stripes” 比 “pairs” 更快
1 class Mapper
2 method Map(null, items [i1, i2,...] )
3 for all item i in [i1, i2,...]
4 H = new AssociativeArray : item -> counter
5 for all item j in [i1, i2,...]
6 H{j} = H{j} + 1
7 Emit(item i, stripe H)
8
9 class Recer
10 method Rece(item i, stripes [H1, H2,...])
11 H = new AssociativeArray : item -> counter
12 H = merge-sum( [H1, H2,...] )
13 for all item j in H.keys()
14 Emit(pair [i j], H{j})
应用:文本分析,市场分析
参考资料:Lin J. Dyer C. Hirst G. Data Intensive Processing MapRece
用MapRece 表达关系模式
在这部分我们会讨论一下怎么使用MapRece来进行主要的关系操作。
筛选(Selection)
1 class Mapper
2 method Map(rowkey key, tuple t)
3 if t satisfies the predicate
4 Emit(tuple t, null)
投影(Projection)
投影只比筛选稍微复杂一点,在这种情况下我们可以用Recer来消除可能的重复值。
1 class Mapper
2 method Map(rowkey key, tuple t)
3 tuple g = project(t) // extract required fields to tuple g
4 Emit(tuple g, null)
5
6 class Recer