cover_image

如何开发亲戚关系计算器

M小白 技术杂学铺
2019年01月18日 10:15

如何开发亲戚关系计算器

M小白 | 文

更多内容见mwhitelab.com

图片

作为一个会编程的准程序员,过年就要做一些与众不同的事。


本文章为技术杂学铺公众号第173篇推文,第1篇娱乐性科普文章。


又到了过年的时候,每到这个时候,你总是能见到自己几乎没印象但父母就是很熟的亲戚。


而且关系凌乱到你自己都说不清。


图片


不信?那就来几道测试题。


2019年亲戚关系测试题正式开始。请完成如下填空。


  1. 爸爸的姐姐的女儿的女儿 = ________

  2. 妈妈的姐姐的弟弟的女儿 = ________

  3. 爷爷的弟弟的女儿的儿子 = ________

  4. 妈妈的妈妈的弟弟的儿子 = ________


参考答案如下:


  1. 表外甥女

  2. 舅表姐/舅表妹

  3. 堂姑表兄/堂姑表弟

  4. 舅表舅父


图片

啥?


由于不知道该如何称呼,面对陌生的亲戚时,我们只能说一句“您好”,附带一个尴尬又不失礼貌的微笑。


图片


BUT! 作为21世纪的资深网民(手机重度依赖患者),我们应该使用新时代的技术来解决这个尴尬的局面。那就是使用软件——亲戚关系计算器。


在微信小程序中搜索“亲戚计算器”会显示很多类似的程序。


图片


操作界面和普通的计算器类似,不过数字和加减乘除键都变成了“父” “母” “兄” “姐” 这样的关系。


图片


以后遇见类似有不确定该如何称呼的亲戚,直接这样用程序就可以了。


再BUT! 我们不能只能满足于使用,更应该探求其本质,了解亲戚关系计算器是如何实现的。


实现方法一:死记硬背法


该方法尝试记下所有亲戚关系的结果,当用户想要查询某一种关系时,直接查表。


假设亲戚之间的关系只有父、母、兄、弟、姐、妹、子、女八种。(先不考虑夫妻关系)


那么像父亲的父亲,哥哥的女儿这样简单的 “XX的XX” 的关系有 8*8 = 64种可能,而 “XX的XX的XX” 有8*8*8 = 512种可能,四个关系的有4096种可能!如此大量的关系,光是把这些可能一个一个地列举出来就会让程序员精神崩溃。


图片


然而这样的死记硬背法是可行的,之前我们看到的微信小程序(其源代码已公布在github上:github.com/mumuy/relationship)就是用这个方法来实现的:


我们先对关系进行简化,比如在 ‘我’ 是男性的情况下,那么‘我的儿子的父亲的XX’在正常情况下就可以化简成 ‘我的XX’。


再比如 母亲的丈夫 = 我的父亲,兄弟的父母=我的父母,姐姐的姐姐 = 姐姐等等。


接着,我们人为给出六七百条最常用的关系和其对应的称谓。任何一条用户输入的关系,其化简后如果在已知的六七百条关系中,我们则返回其对应的称谓,否则,返回不知道。


实现方法二:网状图


在亲戚关系中,所有的名词可以分为两类。


一类是称谓,也就是我们如何称呼其他人的,如父亲、母亲、爷爷、姑姑、舅舅等。


另一类是基础关系,是称谓的子集,由父亲、母亲、儿子、女儿、哥哥、弟弟、姐姐、妹妹、丈夫、妻子,这十个词组成。任何一个称谓都可以由基础关系来表达。


如 爷爷 = 父亲的父亲;姥爷 = 母亲的父亲;太爷爷 = 父亲的父亲的父亲。


圆角长方形框内为称谓,箭头为基础关系(先不考虑丈夫与妻子这两个关系)。我们可以用如下图来表示“我”的亲戚关系:


图片


我们对图中的每一个圆角长方形(称谓)计算其八种关系(父母儿女兄弟姐妹)。


比如,对于上图,我们接着计算父亲和母亲的八种关系对应的人,获得如下图:


图片


之后对于得到的这张图,接着计算每个圆角长方形(称谓)对应的关系, 不断地画下去,可以得到一张巨大的网状图。


这张网状图可以无限延伸(如父亲 的 父亲 的 父亲 的 父亲……),我们根据实际情况,将网状图扩展到足够用的地步就行了。


图片


网状图的每一个称谓和关系都是我们人为确定了。不过其工作量远远小于“死记硬背法”。因为对于一个经过四个关系的问题,如:父亲的儿子的父亲的父亲=爷爷,母亲的母亲的女儿的父亲=姥爷,一个很小的网状图就能确定这个问题的结果。而“死记硬背法”则需要记录下所有 “XX的XX的XX的XX” 对应的结果才行。



如何实现网状图


不懂编程的朋友可跳过本节往下看。


C语言可以使用结构体来表示称谓,用指针来表示关系(这里没有考虑父亲的儿子可能是自己,哥哥,弟弟多种可能)。


struct node {
 struct node *father;
 struct node *mother;
 struct node *big_bro;
 struct node *small_bro;
 struct node *big_sister;
 struct node *small_sister;
 struct node *son;
 struct node *daughter;
};


python可以使用字典。这里主要用python写一个简单的示意程序,具体代码见github

(https://github.com/DrMofu/relationship):


1.建立数据库(该工作量十分庞大,这里只展示几个例子):


me = {'f':'父亲','m':'母亲','bb':'哥哥','sb':'弟弟','bs':'姐姐','ss':'妹妹','son':'儿子','dau':'女儿'}

father = {'f':'爷爷','m':'奶奶','bb':'伯父','sb':'叔叔','bs':'姑妈','ss':'姑妈','son':['我','哥哥','弟弟'],'dau':['我','姐姐','妹妹']}

mother = {'f':'姥爷','m':'姥姥','bb':'大舅','sb':'小舅','bs':'大姨','ss':'小姨','son':['我','哥哥','弟弟'],'dau':['我','姐姐','妹妹']}

…………


2.建立中文名与变量的对应关系:

图片
图片


3.使用一个函数,封装所有操作:

图片


4. 使用:

图片


一些细节


首先,是性别:如果‘我’是女性,那么‘我的父亲的儿子’可以为[‘哥哥’,‘弟弟’],而不可以包含‘我’。(上述代码没实现)


另外,关于夫妻关系:在正常情况下,男性称谓只可以有‘妻子’,女性称谓只可以有‘丈夫’。(上述代码没实现)


第三,多种可能:‘我的父亲的儿子’ 可以是[‘我’,‘哥哥’,‘弟弟’],再若是再往后计算,如‘我的父亲的儿子的儿子’ ,需要同时考虑‘我的儿子’,‘哥哥的儿子’,‘弟弟的儿子’这三种可能。(上述代码已实现)


最后,给出一个线上的亲戚关系计算器

http://www.mwhitelab.com/relationship

该计算器为开源代码,由mumuy开发。


参考资料


“亲戚关系计算器”算法实现

https://www.jianshu.com/p/74290f1ae838


“亲戚关系”程序github源代码

https://github.com/mumuy/relationship


图片

解锁更多精彩内容


阅读原文
修改于2019年01月28日
继续滑动看下一个
技术杂学铺
向上滑动看下一个