用二叉树实现家谱运算
C++语言: 二叉树实现的简单家谱树
/
File Name: BiTreecpp
Author: Geng Lequn[glq2000@126com]
Thur July 1 2010
Discription: 建立二叉家谱树,实现输入任意两个人的名字,查找得到其关系
/
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <mathh>
using namespace std;
typedef struct _Node
{
string sex; //性别 m 男; f 女
string name; //此人的姓名
string spause; //配偶的姓名
unsigned short level; //层次 辈分最高一层为1,下一层为为2,以此类推
struct _Node l_child; //指向其第一个孩子的指针
struct _Node r_brother; //指向其某一个兄弟姐妹的指针, 即左孩子为其后代,右孩子为其兄弟姐妹
struct _Node btr; //指向其父亲或者母亲的指针
_Node():level(0),l_child(NULL),r_brother(NULL),btr(NULL){cout<<"constructor"<<endl;}
~_Node(){cout<<name<<" destructor"<<endl;}
}Node, PNode;
void CreateBiTreePreOrder(PNode &pn, PNode pback, unsigned short depth);//建立二叉家谱树,以先序方式
void VisitBiTreePreOrder(PNode root); //前序遍历此二叉树
void TellRelation(PNode root); //判断两人关系
void DestroyBiTreePostOrder(PNode root); //销毁二叉树,释放节点占用的空间
void FindPersonMiddleOrder(PNode root, string name, PNode &presult); //返回家谱中指向某人的指针,找不到返回NULL
Node root=NULL; //全局变量,二叉树的根节点
unsigned findPersonFlag = 0; //标志位,0 没找到; 1 找到,找到后就不再搜索直接返回;利用此flag可避免将整个tree遍历一遍(若该name在tree中存在的话)
int main()
{
cout<<"请按先序遍历的顺序根据提示输入家谱信息,不存在则输入\"#\""<<endl;
CreateBiTreePreOrder(root, NULL, 1);//建立二叉家谱树,以先序方式
VisitBiTreePreOrder(root); //前序遍历此二叉树
TellRelation(root); //判断两人关系
DestroyBiTreePostOrder(root); //销毁二叉树
getchar();getchar();getchar();
return 0;
}
/
function:建立二叉家谱树,以先序方式
argument:
pn: 指向二叉树节点的引用
pback: pn这个节点的btr指针的值,即指向其parent的指针
depth: 该节点的层次,分最高一层为1,下一层为为2,以此类推
/
void CreateBiTreePreOrder(PNode &pn, PNode pback, unsigned short depth)
{
string str;
cin>>str; //输入该人信息,格式是 sex-name-spausename,如不存在则输入#
if(str == "#") //如: M-tom-marry, 表示此人叫tom, 男性, 配偶名字marry
{
pn = NULL;
return;
}
//如果是自定义的struct/class,应该使用构造函数。如果是内建数据类型,
//比如int,应该memset。 当然,更好的建议是使用vector取代new出来的数组
pn = new Node;
//处理输入的字符串
vector<string> v;
for(size_t b=0, e=strfind('-'); ; e=strfind('-', b))
{
if(e == string::npos)
{
vpush_back(strsubstr(b));
break;
}
else
vpush_back(strsubstr(b, e-b));
b = e+1;
}
//初始化该节点
pn->sex = v[0];
pn->name = v[1];
pn->spause = v[2];
pn->btr = pback;
pn->level = depth;
//递归建立左右子树的节点
CreateBiTreePreOrder(pn->l_child, pn, depth+1); //注意后两个参数的值
CreateBiTreePreOrder(pn->r_brother, pback, depth); //注意后两个参数的值
}
/
function: 前序遍历此二叉树
/
void VisitBiTreePreOrder(PNode pn)
{
if(!pn)
return;
cout<<endl<<"sex:"<<pn->sex<<endl;
cout<<"name:"<<pn->name<<endl;
cout<<"spause:"<<pn->spause<<endl;
cout<<"level:"<<pn->level<<endl;
cout<<"father's name:"<<((pn->btr == NULL)"NULL":pn->btr->name)<<endl;
cout<<"======================"<<endl;
VisitBiTreePreOrder(pn->l_child);
VisitBiTreePreOrder(pn->r_brother);
}
/
function: 中序遍历找到家谱中的一个人,返回其指针,若找不到,返回NULL
isSpause 1表示是找到的节点的配偶 0表示不是所找到的节点的配偶
/
void FindPersonMiddleOrder(PNode pn, string name, PNode &presult)
{
if(!pn)
return;
FindPersonMiddleOrder(pn->l_child, name, presult);
if(findPersonFlag) return;
if(name == pn->name || name == pn->spause)
{
presult = pn;
findPersonFlag = 1; //全局标志位,0 没找到; 1 找到,找到后就不再搜索直接返回;利用此全局flag可避免将整个tree遍历一遍(若该name在tree中存在的话)
return; //下次使用前不要忘记置为0
}
FindPersonMiddleOrder(pn->r_brother, name, presult);
}
/
function: 判断两人关系,若两人中至少一人不在树中,则两人无关系
若两人在树中,先判断两人是否同层次,若同层,判断是否是亲兄弟姐妹;
若不同层,设辈分大的人为A,辈分小的人为B,判断A和B是亲的还是表的,
比如,A为男性,且比B大一倍,判断A是否为B的爸爸,或亲叔叔(舅舅),或表叔叔(舅舅)
简单起见,此处没有区分是叔叔还是舅舅
比如,A为男性,且比B大两倍,判断A是否为B的亲爷爷(姥爷),或亲爷爷(姥爷)的亲兄弟
,或亲爷爷(姥爷)的表兄弟
简单起见,此处没有区分是叔叔和舅舅等做进一步区分
简单起见,查询时只输入节点中的name,不查询spause,否则处理起来太麻烦
/
void TellRelation(PNode pn)
{
string name1, name2;
//p1指向name1, p2指向name2, pbig指向辈分大的,psmall指向辈分小的
PNode p1 = NULL, p2 = NULL, pbig = NULL, psmall = NULL;
int differ = 0; //两人辈分数的差别
string title;
Label:
cout<<endl<<"输入想查询关系的两个人的名字,不想查则将两人名字输成#:"<<endl;
while(cin>>name1 && cin>>name2)
{
if(name1=="#" && name2=="#") return;
p1 = NULL; p2 = NULL; //因为程序是循环执行的,需要将上次遗留的值清掉
findPersonFlag = 0;
FindPersonMiddleOrder(root, name1, p1);
findPersonFlag = 0;
FindPersonMiddleOrder(root, name2, p2);
if(!p1 || !p2) //若有一个为空或都为空,说明至少有一个人不在家谱中,故两人无亲缘关系
{
cout<<name1<<((!p1)" 不在":" 在")<<" 家谱树中"<<endl;
cout<<name2<<((!p2)" 不在":" 在")<<" 家谱树中"<<endl;
cout<<name1<<" 和 "<<name2<<" 间没有关系"<<endl<<endl;
goto Label;
}
differ = (int)abs(p1->level - p2->level);
if(!differ) //辈分一样大
{
if(p1->sex == p2->sex)
{
if(p1->sex == "M") title = "兄弟关系";
else title = "姐妹关系";
}
else title = "兄妹(姐弟)关系";
if(p1->btr == p2->btr) //parent相同
cout<<name1<<" 和 "<<name2<<" 间是 "<<" 亲 "<<title<<endl;
else
cout<<name1<<" 和 "<<name2<<" 间是 "<<" 表 "<<title<<endl;
}
else //辈分不一样大
{
if(p1->level < p2->level) {pbig = p1; psmall = p2;}
else {pbig = p2; psmall = p1;}
switch(differ)
{
case 1:
if(psmall->btr == pbig)
title = ((pbig->sex == "M")"爸爸":"妈妈");
else
{
if(psmall->btr->btr == pbig->btr)
title = ((pbig->sex == "M")"亲叔(舅)":"亲姑(姨)");
else
title = ((pbig->sex == "M")"表叔(舅)":"表姑(姨)");
}
break;
case 2:
if(psmall->btr->btr == pbig)
title = ((pbig->sex == "M")"爷爷(姥爷)":"奶奶(姥姥)");
else
{
string tmp = ((pbig->sex == "M")"兄弟":"姐妹");
if(psmall->btr->btr->btr == pbig->btr)
title = ((psmall->btr->btr->sex == "M")"爷爷(姥爷)的亲":"奶奶(姥姥)的亲") + tmp;
else
title = ((psmall->btr->btr->sex == "M")"爷爷(姥爷)的表":"奶奶(姥姥)的表") + tmp;
}
break;
default:
string tmp2;
PNode pt = psmall;
int n = differ-2; //计算"老"字 (即grand这个字) 出现的个数
for(int i=0; i<n; ++i)
tmp2 += "老";
for(int i=0; i<differ; ++i)
pt = pt->btr;
if(pt == pbig)
title = tmp2 + ((pbig->sex == "M")"爷爷(姥爷)":"奶奶(姥姥)");
else
{
string tmp3 = ((pbig->sex == "M")"兄弟":"姐妹");
if(pt->btr == pbig->btr)
{title = tmp2 + ((pt->sex == "M")"爷爷(姥爷)的亲":"奶奶(姥姥)的亲"); title+=tmp3;}
else
{title = tmp2 + ((pt->sex == "M")"爷爷(姥爷)的表":"奶奶(姥姥)的表"); title+=tmp3;}
}
break;
}
cout<<pbig->name<<" 是 "<<psmall->name<<" 的 "<<title<<endl;
}
goto Label;
}
}
/
function: 后序遍历销毁此二叉树,释放节点占用的内存空间
/
void DestroyBiTreePostOrder(PNode pn)
{
if(!pn) return;
DestroyBiTreePostOrder(pn->l_child);
DestroyBiTreePostOrder(pn->r_brother);
delete pn;
}
传承家谱程序是专门做树形家谱的程序,而且输出为WORD文档,也可以图形输出。 输出树形谱系为TXT文件,可以输出任意大小的树形谱系,避免了版面上的限制。 可以在百度搜一下。需要注册方可使用。还有电脑excel也可以做,具体教程如下:http://jingyanbaiducom/article/414eccf6197fc86b431f0a0chtml
祭祀共分九个仪程,即迎神、奠玉帛、进组、初献、亚献、终献、撤撰、送神、望瘗等。各仪程演奏不同的乐章(附录)。跳文、武“八佾”舞(由64人组成的古代天子专用的舞蹈)。清乾隆七年额定地坛设文、武、乐舞生480人,执事生90人。可见当时乐舞队伍之庞大。每进行一项仪程,皇帝都要分别向正位、各配位、各从位行三跪九叩礼,从迎神至送神要下跪70多次、叩头200多下,历时两小时之久。如此大的活动量对帝王来说是个很大的负担,所以皇帝到年迈体衰时,一般不亲诣致祭,而派遣亲王或皇子代为行礼。如清代康熙皇帝在位61年,前40年中亲诣地坛致祭26次,而后21年则全部由亲王、皇子代祭。
祭地现场的纪律要求极严。皇帝经常旨渝:陪把官员,必须虔诚整肃,不许迟到早退,不许咳嗽吐痰,不许走动喧哗,不许闲人偷觑,不许紊乱次序。否则,无论何人,一律严惩。据史料记载:清嘉庆二十四年五月甘四日,因恭修皇祗室内乾隆皇帝之神座,而派遣成亲王代行祭告礼。由于成亲王向列圣配位行“终献”礼时,亲。乱了先东后西之次序,事后被革职退居宅邱闭门思过,并罚扣半俸10年,照郡王食俸。此例可见君王对祭地礼仪之严肃认真。 祭祀结束后,按制度规定要向有关官员分赐食肉,叫“颁胙”。祭前,由太常寺负责登记造册,并发给胙单,(取肉证)至各衙门。,祭毕,各衙门持昨单各自到祭所领取。据记载:宗人府、内阁各10斤,六部、理藩院、都察院、通政使司、大理寺、乐部、京[]道各7斤,太常寺蛮仪卫、詹事府、顺天府、太仆寺、光禄寺、鸿胪寺、六科五城各5斤,翰林院、起居注、国子监、太医院、钦天监、中书科各4斤。 祭地对平民百姓并无好处,特别是大兴、宛平两县既要派驻坛户守坛,又要负担200多名厨差役夫,还要摊派祭祀所需的杂费银两。当然,对这两县的官员来说,倒是件有名有利的大好事。
殿内分别置香案、设香炉、蜡台等贡器,主殿香案北侧设贡桌,陈设酒醴、贡果、糕点、杯箸;东南侧设小贡桌,放香炉、鞭炮等乐队、乐工设东墙位置。
祭祖程序如下:
一、主持、礼宾进入岗位,做好祭祖准备,负责组织整个祭祖活动
二、祭祖者恭临殿前:祭祖团选一名代表为主祭人,带领全体陪祭人员列队进入祭祖区。
三、安氏宗亲祭祖典礼开始。全体肃立(所有祭祖人员向前跨半步,脱帽、鞠躬、肃立)。主祭人一人换装。(主祭者换红色唐装)
四、祭祀
(一)奏乐
(二)鸣炮
(三)击鼓 (击鼓十一响代表“全世界七大洲四大洋安氏族人” )。
(四)鸣钟
(五)拂尘 (由执事拂尘)。
(六)上香(由四名礼宾带领众祭祖者醒香、捧香、纳香、行叩拜礼)。
(七)行三献礼(礼宾先生行礼、乐工奏乐)。
通赞:向祭者班齐,陪祭者序立主,祭者就位。
引赞:就位。
通赞:盥洗。
引赞:诣盥洗所、浴手、净巾。
通赞:参神。
引赞:诣香案前,就位、跪、上香、受爵、酹酒、祭酒、奠爵、叩首、起、复位。
通赞:进鱼米。
引赞:诣酒樽到神位前,就位、跪、上香、受爵、酹酒、祭酒、奠酒、奠爵、叩首、起、复位。
通赞:行初献礼,盥洗。
引赞:诣盥洗所,浴手、净巾、复位。
通赞:进炙肝、进割肉、进时食。
引赞:诣酒樽到。
受爵、酹酒、祭酒、叩首、起、复位。
通赞:诣神位前。
引赞:就位、跪、进馔。
通赞:读祝文。
引赞:诣香案前,跪。
通赞:读祝文。
陪通赞:叩首、起、复位。
礼通赞:行亚献,盥洗。
引赞:诣盥洗所,浴手、净巾、复位。
通赞:进炙肝、进割肉、进时食。
引赞:诣酒樽到。
通赞:诣神位前。
引赞:就位、跪、进馔、受爵、酹酒、祭酒、叩首、起、复位。
通赞:行终献礼,盥洗。
引赞:诣盥洗所,浴手、净巾、复位。
通赞:进炙肝、进割肉、进时食。
引赞:诣酒樽到。
通赞:诣神位前。
引赞:就位、跪、进馔、受爵、酹酒、祭酒、叩首、起、复位。
通赞:撤馔(此时,两位向祭生各端一碟时食回来,放在院中香案上,揖、叩首、复回原位)。
通赞:点茶(此时,两位向祭生各端一碟糕点,贡在神案两旁,叩首,复回原位)。
通赞:告礼成。
引赞:礼成。
通赞:辞神。
陪通:跪、叩首、起。
通赞:执祝生捧祝,执爵生捧爵,执杯生捧杯(均放在香案上)。
焚祝文(主祭者焚祝,并奠酒)。
引赞:各移燎位(此时,祝文捧在贡桌上,将祝文放在香炉上,用黄钱、香烛、酒礼,鸣炮)焚祝。
通赞:望燎,送神。
五、祭祖仪式结束,游宫开始。
备注:主持穿红色唐装、礼宾穿深蓝色唐装、主祭者穿红色唐装。
完整的家谱一般包括:谱序,首事名录,字辈世系行号,家训,家谱中当然看把每个家族成员记载进去啊。
简言之,每个家族都有不同的族规家训。家谱中较为常见者,大致包括了以下内容:(一)、注重家法、国法(二)、和睦宗族、乡里(三)、孝顺父母、敬长辈(四)、合乎礼教、正名分(五)、祖宗祭祀、墓祭程序。
总之关于修家谱的东西很多, 需要修谱的朋友还是建议找专业的修谱的人咨询。-百姓通谱
用二叉树实现家谱运算
本文2023-09-22 02:57:56发表“资讯”栏目。
本文链接:https://www.lezaizhuan.com/article/19686.html