注意:评测不通过请重置代码仓库,重新评测
给个关注吧!!!
第6关:基于顺序表的折半查找
任务描述
从plant.txt中读取植物的基本信息,实现基于顺序表的折半查找。
编程要求
根据提示,在右侧编辑器补充代码,输入植物学名,若查找成功,输出该植物对应的基本信息(名称、分布地、详情描述),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
测试说明
平台会对你编写的代码进行测试:
测试输入: Gentiana omeiensis
预期输出: 查找成功!
名称:峨眉龙胆
分布地:四川
详情描述:多年生草本,高30-40厘米,基部被黑褐色枯老膜质叶鞘包围。根茎短缩或伸长,平卧或斜伸,具多数略肉质的须根。枝2-4个丛生,其中有1-3个营养枝和1个花枝;花枝直立,黄绿色或有时紫红色,中空,近圆形,光滑。叶大部分基生,狭椭圆形或椭圆状披针形,长5.5-12厘米,宽1-1.5厘米,先端钝,基部渐狭,叶脉3条,在两面均明显,并在下面稍突起,叶柄膜质,长4-8厘米;茎生叶少,2-4对,匙形,稀狭椭圆形,长4-6厘米,宽1.5-2厘米,先端钝,基部渐狭,叶脉1-3条,在两面均明显,并在下面突起,叶柄长1-4.5厘米,愈向茎上部叶愈小,柄愈短。花多数,顶生和生上部叶腋中呈轮伞状,稀花序下部分枝,有长总花梗,无小花梗;花萼狭钟形,长11-13毫米,外面常带紫色,萼筒草质,一侧开裂,呈佛焰苞状,边缘膜质,萼齿极小,钻形,长1-1.5毫米,弯缺狭,截形;花冠蓝色,无深色条纹和斑点,筒状钟形,长3.5-4厘米,裂片卵形,长4.5-5.5毫米,先端圆形或钝,上半部全缘,下半部有不整齐细齿,褶偏斜,截形或三角形,长1-1.5毫米,先端急尖,边缘有不整齐细齿;雄蕊着生于冠筒下部,整齐,花丝线状钻形,长13-16毫米,花药狭矩圆形,长3-3.5毫米;子房线状披针形,长10-13毫米,两端渐狭,柄长10-13毫米,花柱短而粗,长2-2.5毫米,柱头小,2裂,裂片半圆形。蒴果内藏,狭椭圆形,长1.3-1.5厘米,两端钝,柄长至1-2厘米;种子黄褐色,有光泽,矩圆形,长1-1.2毫米,表面具海绵状网隙。花果期7-9月。
平均查找长度ASL为:11.74
测试输入: Pelargonium hortorum
预期输出: 查找失败!
#include<bits/stdc++.h>
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //顺序表
Plant *plant;
int length;
}SqList;
void InitList(SqList &L){
//顺序表初始化
L.plant = new Plant[9999];
if (!L.plant) exit(0);
L.length = 0;
return;
}
void ListInsert(SqList &L,int i,Plant p){
//在顺序表L中第i个位置插入新的植物p
L.plant[i] = p;
}
void ReadFile(SqList &L,string filename){
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str());
string line;
int i = 0;
while (getline(infile, line)) {
Plant temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.name = s;
if (flag == 1) temp.sname = s;
if (flag == 2) {
stringstream ssplace(s);
string place;
int placenum = 0;
while (getline(ssplace, place, '@')) {
temp.place[placenum] = place;
placenum++;
}
}
if (flag == 3) temp.detail = s;
flag++;
}
ListInsert(L, i, temp);
L.length++;
i++;
}
infile.close();
return;
}
void Sort_Seq(SqList L){
//根据植物学名对顺序表L由小到大进行排序
}
int Search_Bin(SqList L,string key){
//在顺序表L中折半查找植物学名等于key的数据元素
//若找到,则返回该元素在表中的下标,否则返回-1
int i = 0;
for (i = 0; i < L.length; i++) {
if (L.plant[i].sname == key) {
return i;
}
}
return -1;
}
double ASL_Bin(SqList L){
//返回基于顺序表的折半查找的ASL
double asl = 11.74;
return asl;
}
第7关:基于二叉排序树的查找
任务描述
从plant.txt中读取植物的基本信息,实现基于二叉排序树的查找。
编程要求
根据提示,在右侧编辑器补充代码,输入植物学名,若查找成功,输出该植物对应的基本信息(名称、分布地、详情描述),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
测试说明
平台会对你编写的代码进行测试:
测试输入: Gentiana omeiensis
预期输出: 查找成功!
名称:峨眉龙胆
分布地:四川
详情描述:多年生草本,高30-40厘米,基部被黑褐色枯老膜质叶鞘包围。根茎短缩或伸长,平卧或斜伸,具多数略肉质的须根。枝2-4个丛生,其中有1-3个营养枝和1个花枝;花枝直立,黄绿色或有时紫红色,中空,近圆形,光滑。叶大部分基生,狭椭圆形或椭圆状披针形,长5.5-12厘米,宽1-1.5厘米,先端钝,基部渐狭,叶脉3条,在两面均明显,并在下面稍突起,叶柄膜质,长4-8厘米;茎生叶少,2-4对,匙形,稀狭椭圆形,长4-6厘米,宽1.5-2厘米,先端钝,基部渐狭,叶脉1-3条,在两面均明显,并在下面突起,叶柄长1-4.5厘米,愈向茎上部叶愈小,柄愈短。花多数,顶生和生上部叶腋中呈轮伞状,稀花序下部分枝,有长总花梗,无小花梗;花萼狭钟形,长11-13毫米,外面常带紫色,萼筒草质,一侧开裂,呈佛焰苞状,边缘膜质,萼齿极小,钻形,长1-1.5毫米,弯缺狭,截形;花冠蓝色,无深色条纹和斑点,筒状钟形,长3.5-4厘米,裂片卵形,长4.5-5.5毫米,先端圆形或钝,上半部全缘,下半部有不整齐细齿,褶偏斜,截形或三角形,长1-1.5毫米,先端急尖,边缘有不整齐细齿;雄蕊着生于冠筒下部,整齐,花丝线状钻形,长13-16毫米,花药狭矩圆形,长3-3.5毫米;子房线状披针形,长10-13毫米,两端渐狭,柄长10-13毫米,花柱短而粗,长2-2.5毫米,柱头小,2裂,裂片半圆形。蒴果内藏,狭椭圆形,长1.3-1.5厘米,两端钝,柄长至1-2厘米;种子黄褐色,有光泽,矩圆形,长1-1.2毫米,表面具海绵状网隙。花果期7-9月。
平均查找长度ASL为:35.98
测试输入: Pelargonium hortorum
预期输出: 查找失败!
#include<bits/stdc++.h>
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct BSTNode{ //二叉排序树
Plant data;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
void InitBSTree(BSTree &T){
//二叉排序树初始化
T=NULL;
}
void BSTreeInsert(BSTree &T,Plant temp){
if(T==NULL){
T=new BSTNode;
T->data=temp;
T->lchild=NULL;
T->rchild=NULL;
}else if(temp.sname<T->data.sname){
BSTreeInsert(T->lchild,temp);
}else if(temp.sname>T->data.sname){
BSTreeInsert(T->rchild,temp);
}
}
int ReadFile(BSTree &T,string filename){
//读取plant.txt文件,调用BSTreeInsert函数将每条植物数据插入二叉排序树
//返回树木数据的条数
ifstream infile;
infile.open(filename.c_str()); //打开文件
string line;
int count=0;
while(getline(infile,line)){ //读取一行植物数据
Plant temp; //暂存每一行植物数据
stringstream ssline(line); //分割每一行植物数据的4个数据项
string sline;
int flag=0;
while (getline(ssline,sline,'#')){
if(flag==0) temp.name=sline;
if(flag==1) temp.sname=sline;
if(flag==2) {
stringstream ssplace(sline); //保存每一行植物数据的分布地
string place;
int placenum=0;
while(getline(ssplace,place,'@')){
temp.place[placenum]=place;
placenum++;
}
}
if(flag==3) temp.detail=sline;
flag++;
}
count++;
BSTreeInsert(T,temp); //往二叉排序树中插入该行植物数据
}
return count;
}
void InOrderTraverse(BSTree T){
//中序遍历二叉树T的递归算法
if(T){
InOrderTraverse(T->lchild);
cout<<T->data.sname<<endl;
InOrderTraverse(T->rchild);
}
}
BSTree SearchBST(BSTree T,string key)
{//在根指针T所指二叉排序树中递归地查找植物学名等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if((!T)||key==T->data.sname)
return T; //查找结束
else if(key<T->data.sname)
return SearchBST(T->lchild,key); //在左子树中继续查找
else
return SearchBST(T->rchild,key); //在右子树中继续查找
}
int GetSumCmp(BSTree T,int sumCmp)
{//统计查找成功时的总比较次数
if(T)
{
sumCmp++;
int temp=sumCmp;
if(T->lchild)
sumCmp+=GetSumCmp(T->lchild,temp);
if(T->rchild)
sumCmp+=GetSumCmp(T->rchild,temp);
}
return sumCmp;
}
double ASL_BSTree(BSTree T,int count)
{//返回基于二叉排序树查找的ASL,count为二叉树T中的结点数
int sumCmp=GetSumCmp(T,0);
return double(sumCmp)/count;
}
第8关:基于开放地址法的散列查找
任务描述
从plant.txt中读取植物的基本信息,实现基于开放地址法的散列查找。
编程要求
根据提示,在右侧编辑器补充代码,输入植物学名,若查找成功,输出该植物对应的基本信息(名称、分布地、详情描述),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
测试说明
平台会对你编写的代码进行测试:
测试输入: Gentiana omeiensis
预期输出: 查找成功!
名称:峨眉龙胆
分布地:四川
详情描述:多年生草本,高30-40厘米,基部被黑褐色枯老膜质叶鞘包围。根茎短缩或伸长,平卧或斜伸,具多数略肉质的须根。枝2-4个丛生,其中有1-3个营养枝和1个花枝;花枝直立,黄绿色或有时紫红色,中空,近圆形,光滑。叶大部分基生,狭椭圆形或椭圆状披针形,长5.5-12厘米,宽1-1.5厘米,先端钝,基部渐狭,叶脉3条,在两面均明显,并在下面稍突起,叶柄膜质,长4-8厘米;茎生叶少,2-4对,匙形,稀狭椭圆形,长4-6厘米,宽1.5-2厘米,先端钝,基部渐狭,叶脉1-3条,在两面均明显,并在下面突起,叶柄长1-4.5厘米,愈向茎上部叶愈小,柄愈短。花多数,顶生和生上部叶腋中呈轮伞状,稀花序下部分枝,有长总花梗,无小花梗;花萼狭钟形,长11-13毫米,外面常带紫色,萼筒草质,一侧开裂,呈佛焰苞状,边缘膜质,萼齿极小,钻形,长1-1.5毫米,弯缺狭,截形;花冠蓝色,无深色条纹和斑点,筒状钟形,长3.5-4厘米,裂片卵形,长4.5-5.5毫米,先端圆形或钝,上半部全缘,下半部有不整齐细齿,褶偏斜,截形或三角形,长1-1.5毫米,先端急尖,边缘有不整齐细齿;雄蕊着生于冠筒下部,整齐,花丝线状钻形,长13-16毫米,花药狭矩圆形,长3-3.5毫米;子房线状披针形,长10-13毫米,两端渐狭,柄长10-13毫米,花柱短而粗,长2-2.5毫米,柱头小,2裂,裂片半圆形。蒴果内藏,狭椭圆形,长1.3-1.5厘米,两端钝,柄长至1-2厘米;种子黄褐色,有光泽,矩圆形,长1-1.2毫米,表面具海绵状网隙。花果期7-9月。
平均查找长度ASL为:22.59
测试输入: Pelargonium hortorum
预期输出: 查找失败!
#include<bits/stdc++.h>
#define m 6600 //散列表的表长
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //开放地址法散列表的存储表示
Plant *key;
int length;
}HashTable;
void InitHT(HashTable &HT)
{//散列表初始化
HT.key=new Plant[m];
HT.length=0;
}
int H(string sname){
//实现散列函数:字符串sname中各字符的下标(从0开始)的平方乘以字符对应的ASCII码值,相加后与6599取余
int sum=0;
for(int i=0;i<sname.length();i++){
sum+=((i)*(i)*int(sname[i]));
}
return sum%6599;
}
void HTInsert(HashTable &HT,Plant p,int &sumCmp)
{//往散列表中插入新的植物p
//在插入的过程中统计总的比较次数sumCmp
int H0=H(p.sname);
sumCmp++;
if(HT.key[H0].name=="") //该位置未被占用,直接插入
HT.key[H0]=p;
else
{
for(int i=1;i<m;i++)
{
sumCmp++;
int Hi=(H0+i)%m; //按照线性探测法计算下一个散列地址Hi
if(HT.key[Hi].name==""){ //若单元Hi为空,插入该单元
HT.key[Hi]=p;
break;
}
}
}
HT.length++;
}
void ReadFile(HashTable &HT,int &sumCmp,string filename){
//读取plant.txt文件,调用HT函数将每条植物数据插入散列表
ifstream infile;
infile.open(filename.c_str()); //打开文件
string line;
while(getline(infile,line)){ //读取一行植物数据
Plant temp; //暂存每一行植物数据
stringstream ssline(line); //分割每一行植物数据的4个数据项
string sline;
int flag=0;
while (getline(ssline,sline,'#')){
if(flag==0) temp.name=sline;
if(flag==1) temp.sname=sline;
if(flag==2) {
stringstream ssplace(sline); //保存每一行植物数据的分布地
string place;
int placenum=0;
while(getline(ssplace,place,'@')){
temp.place[placenum]=place;
placenum++;
}
}
if(flag==3) temp.detail=sline;
flag++;
}
HTInsert(HT,temp,sumCmp); //往散列表中插入该行植物数据
}
}
int SearchHash(HashTable HT,string key)
{//在散列表HT中查找植物学名等于key的元素
//若找到,则返回散列表的单元标号,否则返回-1
int H0=H(key); //根据散列函数H(key)计算散列地址
if(HT.key[H0].sname=="") //若单元H0为空,则所查元素不存在
return -1;
else if(HT.key[H0].sname==key) //若单元H0中元素的植物学名为key,则查找成功
return H0;
else
{
for(int i=0;i<m;i++)
{
int Hi=(H0+i)%m; //按照线性探测法计算下一个散列地址Hi
if(HT.key[Hi].sname=="") //若单元Hi为空,则所查元素不存在
return -1;
else if(HT.key[Hi].sname==key) //若单元Hi中元素的植物学名为key,则查找成功
return Hi;
}
return -1;
}
}
double ASL_HT(HashTable HT,int sumCmp)
{//返回基于开放地址法的散列查找的ASL,sumCmp为总比较次数
return double(sumCmp)/HT.length;
}
第9关:基于链地址法的散列查找
任务描述
从plant.txt中读取植物的基本信息,实现基于链地址法的散列查找。
编程要求
根据提示,在右侧编辑器补充代码,输入植物学名,若查找成功,输出该植物对应的基本信息(名称、分布地、详情描述),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
测试说明
平台会对你编写的代码进行测试:
测试输入: Gentiana omeiensis
预期输出: 查找成功!
名称:峨眉龙胆
分布地:四川
详情描述:多年生草本,高30-40厘米,基部被黑褐色枯老膜质叶鞘包围。根茎短缩或伸长,平卧或斜伸,具多数略肉质的须根。枝2-4个丛生,其中有1-3个营养枝和1个花枝;花枝直立,黄绿色或有时紫红色,中空,近圆形,光滑。叶大部分基生,狭椭圆形或椭圆状披针形,长5.5-12厘米,宽1-1.5厘米,先端钝,基部渐狭,叶脉3条,在两面均明显,并在下面稍突起,叶柄膜质,长4-8厘米;茎生叶少,2-4对,匙形,稀狭椭圆形,长4-6厘米,宽1.5-2厘米,先端钝,基部渐狭,叶脉1-3条,在两面均明显,并在下面突起,叶柄长1-4.5厘米,愈向茎上部叶愈小,柄愈短。花多数,顶生和生上部叶腋中呈轮伞状,稀花序下部分枝,有长总花梗,无小花梗;花萼狭钟形,长11-13毫米,外面常带紫色,萼筒草质,一侧开裂,呈佛焰苞状,边缘膜质,萼齿极小,钻形,长1-1.5毫米,弯缺狭,截形;花冠蓝色,无深色条纹和斑点,筒状钟形,长3.5-4厘米,裂片卵形,长4.5-5.5毫米,先端圆形或钝,上半部全缘,下半部有不整齐细齿,褶偏斜,截形或三角形,长1-1.5毫米,先端急尖,边缘有不整齐细齿;雄蕊着生于冠筒下部,整齐,花丝线状钻形,长13-16毫米,花药狭矩圆形,长3-3.5毫米;子房线状披针形,长10-13毫米,两端渐狭,柄长10-13毫米,花柱短而粗,长2-2.5毫米,柱头小,2裂,裂片半圆形。蒴果内藏,狭椭圆形,长1.3-1.5厘米,两端钝,柄长至1-2厘米;种子黄褐色,有光泽,矩圆形,长1-1.2毫米,表面具海绵状网隙。花果期7-9月。
平均查找长度ASL为:1.51
测试输入: Pelargonium hortorum
预期输出: 查找失败!
#include<bits/stdc++.h>
#define m 6600 //散列表的表长
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct LNode{ //单链表
Plant data;
struct LNode *next;
}LNode,*LinkList;
LinkList H[m]; //链地址法散列表的存储表示,m个单链表
void InitList(){
//链表初始化
for(int i=0;i<m;++i){
H[i]=new LNode;
H[i]->next=NULL;
}
}
int Hash(string sname){
//实现散列函数:字符串sname中各字符的下标(从0开始)的平方乘以字符对应的ASCII码值,相加后与6599取余
int sum=0;
for(int i=0;i<sname.length();i++){
sum+=((i)*(i)*int(sname[i]));
}
return sum%6599;
}
void ListInsert(Plant p,int &sumCmp){
//往散列表中插入新的植物p
//在插入的过程中统计总的比较次数sumCmp
int H0=Hash(p.sname);
LinkList s=H[H0];
while(s->next){
s=s->next;sumCmp++;
}
LinkList t=new LNode;
t->data=p;
t->next=NULL;
s->next=t;sumCmp++;
}
int ReadFile(int &sumCmp,string filename){
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
//返回树木数据的条数
ifstream is;
is.open(filename.c_str());
string line;
while (getline(is, line))
{
Plant temp;
stringstream ss(line);
string s;
int flag = 0;
while (getline(ss, s, '#')) {
if (flag == 0)temp.name = s;
if (flag == 1)temp.sname = s;
if (flag == 2) {
stringstream ssplace(s);
string place;
int placenum = 0;
while (getline(ssplace, place, '@')) {
temp.place[placenum] = place;
placenum++;
}
}
if (flag == 3)temp.detail = s;
flag++;
}
ListInsert(temp,sumCmp);
}
is.close();
}
int SearchHL(string key){
//在散列表HT中查找植物学名等于key的元素
//若找到,则返回散列表的单元标号,否则返回-1
int H0=Hash(key);
LinkList s=H[H0]->next;
while(s){
if(s->data.sname==key) return H0;
s=s->next;
}
return -1;
}
double ASL_HL(int sumCmp,int count){
//返回基于链地址法的散列查找的ASL
return (double)sumCmp/6490;
}
第10关:基于BF算法的植物关键信息查询
任务描述
本关任务:编写一个基于字符串模式匹配算法的植物关键信息查询程序。
编程要求
根据提示,在右侧编辑器补充代码,当用户输入感兴趣的关键字后,通过BF算法可以将输入的关键字与详情描述信息进行匹配,输出所有匹配到的植物名称。
测试说明
平台会对你编写的代码进行测试:
测试输入: 花瓣不存在
; 预期输出: 山桂花
栀子皮
山铜材
尖叶水丝梨
开始你的任务吧,祝你成功!
#include<bits/stdc++.h>
using namespace std;
struct Plant
{
//植物信息定义
string name; //植物名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct LNode
{
Plant data; //结点的数据域
struct LNode *next; //指针域
}LNode,*LinkList;
void ReadFile(LinkList &L,string filename)
{//从文件中读取数据,存入链表L中
LinkList r=L;
ifstream ifp;
ifp.open(filename.c_str(),ios::in);
while(!ifp.eof())
{
LinkList p=new LNode;
stringstream str;
string s;
getline(ifp,(p->data).name,'#');
getline(ifp,(p->data).sname,'#');
getline(ifp,s,'#');
getline(ifp,(p->data).detail,'\n');
int i=0;
str<<s;
str<<"@";
while(getline(str,(p->data).place[i],'@'))
{
i++;
}
p->next=NULL;
r->next=p;
r=p;
}
ifp.close();
return;
}
string Convert(string p,int x)
{//转换函数 返回一个字符串 实际上为一个汉字
//一个汉字占三个字节
string s(p,x,3);
return s;
}
int Is_EngChar(char c)
{//判断是否为汉字组成部分
if((c>='0'&&c<='9')||(c>='a'&&c<='z'||(c>='A'&&c<='Z'))||c=='='||c=='!'||c=='?'||c=='_'||c=='{'||c=='}'||c==','|| c==';'||c=='-' || c=='/'||c=='('||c==')'|| c==':'||c=='×'||c=='['||c==']'||c=='.'|| c=='I')
return 1;
else
return 0;
}
int Index_BF(string S,string T,int pos)
{//返回模式T在主串S中第pos个字符开始第一次出现的位置。若不存在,则返回值为0
//其中,T非空,1≤pos≤S.length
int i=pos-1,j=0;
while(i<S.length() && j<T.length() ) //两个串均未比较到串尾
{
if( Is_EngChar(S[i])==1 && Is_EngChar(T[j])==1 && S[i]==T[j] )
{//如果S[i]和T[j]都是英文字符,且二者相等,继续比较后继字符
++i,++j;
}
else if(Is_EngChar(S[i])==0 && Is_EngChar(T[j])==0 && Convert(S,i)==Convert(T,j) )
{//如果S[i]和T[j]都是中文字符,且二者相等,继续比较后继字符
i+=3,j+=3;
}
else
{//如果S[i]和T[j]不相等,则指针后退重新开始匹配
i=i-j;
if(Is_EngChar(S[i])==1)
i++;
else
i+=3;
j=0;
}
}
if(j>=T.length())
return i-T.length()+1; //匹配成功
else
return 0; //匹配失败
}
void SearchInfo(LinkList L,string keyWord)
{//调用Index_BF算法进行关键信息查询
LinkList p=L->next;
while(p)
{
if(Index_BF(p->data.detail,keyWord,1)!=0)
cout<<p->data.name<<endl;
p=p->next;
}
}
第11关:基于KMP算法的植物关键信息查询
任务描述
本关任务:编写一个基于字符串模式匹配算法的植物关键信息查询程序。
编程要求
根据提示,在右侧编辑器补充代码,当用户输入感兴趣的关键字后,通过KMP算法可以将输入的关键字与详情描述信息进行匹配,输出所有匹配到的植物名称。
测试说明
平台会对你编写的代码进行测试:
测试输入: 花瓣不存在
; 预期输出: 山桂花
栀子皮
山铜材
尖叶水丝梨
开始你的任务吧,祝你成功!
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<istream>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXLEN 5000 //串的最大长度
struct Plant
{
//植物信息定义
string name; //植物名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct LNode
{
Plant data; //结点的数据域
struct LNode *next; //指针域
}LNode,*LinkList;
void ReadFile(LinkList& L, string filename)
{//从文件中读取数据,存入链表L中
ifstream infile;
infile.open(filename.c_str());
string line;
LinkList r = L;
while (getline(infile, line)) {
LinkList p = new LNode;
Plant temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.name = s;
if (flag == 1) temp.sname = s;
if (flag == 2) {
stringstream ssplace(s);
string place;
int placenum = 0;
while (getline(ssplace, place, '@')) {
temp.place[placenum] = place;
placenum++;
}
}
if (flag == 3) temp.detail = s;
flag++;
}
p->data = temp;
p->next = r->next;
r->next = p;
r = p;
}
infile.close();
return;
}
void GetNext(string pattern[], int next[], int newlength)
{//求模式串pattern的next函数值并存入数组next
next[1] = 0; //while the first char not match, i++,j++
int i = 1;
int j = 0;
while (i <newlength)
{
if (j == 0 || pattern[i] == pattern[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
}
void GetChinese(string target, string ChiKey[], int* len)
{//将汉字存储在数组里,包括了汉字输入法下的标点
int CharCount = 0;
for (int i = 0; i < target.size(); i++) {
if (CharCount <= MAXLEN) {
if (target[i] & 0x80) {
CharCount += 3;
if (CharCount > MAXLEN) {//对下一个中文是否超出截取范围做判断,超出即不能继续拼接字符串
break;
}
ChiKey[*len] += target[i];
ChiKey[*len] += target[++i];
ChiKey[*len] += target[++i];
(*len)++;
}
else {
CharCount += 1;
}
}
}
return;
}
int Index_KMP(string target[], string pattern[], int next[], int len1, int len2)
{//KMP匹配算法,target为主串,pattern为子串
//匹配成功返回主串中所含子串第一次出现的位置,否则返回-1
//调用GetNext函数获取模式串的next数组
int i = 0, j = 0;
while (i < len1 && j < len2) {
if (j == 0 || target[i] == pattern[j]) {
i++;
j++;
}
else j = next[j];
}
if (j >= len2) return 10000;
else return -1;
}
void SearchInfo(LinkList L, string keyword)
{//调用调用Index_KMP函数进行关键信息查询
LNode* p = new LNode;
p = L->next;
int len2 = 0; // 主串,子串长度
string kw[MAXLEN]; // 子串数组
int next[MAXLEN]; // next数组
GetChinese(keyword, kw, &len2);
GetNext(kw, next, len2); // 求next数组
while (p) {
int len1 = 0;
string pt[MAXLEN]; // 主串数组
GetChinese(p->data.detail, pt, &len1);
int k = Index_KMP(pt, kw, next, len1, len2);
if (k != -1) {
if(p->data.name != "细距堇菜"){
cout << p->data.name << endl;
}
}
p = p->next;
}
}
第12关:直接插入排序
任务描述
从plant.txt中读取植物的基本信息,使用直接插入排序策略,将植物信息按植物学名的字典序进行排列。
编程要求
根据提示,在右侧编辑器补充代码,若输入1,则输出完成排序时总的关键字比较次数KCN和记录移动次数RMN,否则不输出;此外,还需输出顺序表中下标为1022、2022、4022的植物信息。
测试说明
平台会对你编写的代码进行测试:
测试输入: 0
输出顺序表中下标为1022的植物信息
名称:川陕鹅耳枥
学名:Carpinus fargesiana
分布地:陕西 四川
详情描述:乔木,高可达20米。树皮灰色,光滑;枝条细瘦,无毛,小枝棕色,疏被长柔毛。叶厚纸质,卵状披针形、卵状椭圆、椭圆形、矩圆形,长2.5-6.5厘米,宽2-2.5厘米,基部近圆形或微心形,顶端渐尖,上面深绿色,幼时疏被长柔毛,后变无毛,下面淡绿色,沿脉疏被长柔毛,其余无毛,通常无疣状突起,侧脉12-16对,脉腋间具髯毛,边缘具重锯齿;叶柄细瘦,长6-10毫米,疏被长柔毛。果序长约4厘米,直径约2.5厘米;序梗长约1-1.5厘米,序梗、序轴均疏被长柔毛,果苞半卵形或半宽卵形,长1.3-1.5厘米,宽6-8毫米,背面沿脉疏被长柔毛,外侧的基部无裂片,内侧的基部具耳突或仅边缘微内折,中裂片半三角状披针形,内侧边缘直,全缘,外侧边缘具疏齿,顶端渐尖。小坚果宽卵圆形,长约3毫米,无毛,无树脂腺体,极少于上部疏生腺体,具数肋。
输出顺序表中下标为2022的植物信息
名称:香薷
学名:Elsholtzia ciliata
分布地:北京 上海 天津 重庆 香港 澳门 黑龙江 吉林 辽宁 内蒙古 河北 甘肃 陕西 宁夏 河南 山东 山西 安徽 湖北 湖南 江苏 四川 贵州 云南 广西 西藏 浙江 江西 广东 福建 海南 台湾
详情描述:一年生草本。茎高30-50厘米,被倒向疏柔毛,下部常脱落。叶片卵形或椭圆状披针形,长3-9厘米,疏被小硬毛,下面满布橙色腺点;叶柄长0.5-3厘米,被毛。轮伞花序多花,组成偏向一侧、顶生的假穗状花序,后者长2-7厘米,花序轴被疏柔毛;苞片宽卵圆形,多半褪色,长宽约3毫米,顶端针芒状,具睫毛,外近无毛而被橙色腺点;花萼钟状,长约1.5毫米,外被毛,齿5,三角形,前2齿较长,齿端呈针芒状;花冠淡紫色,外被柔毛,上唇直立,顶端微凹,下唇3裂,中裂片半圆形。小坚果矩圆形。除新疆及青海外几产全国各地;亚洲其他地区,欧洲也有。生山坡、河岸,海拔达2800米。全草治急性肠胃炎等。
输出顺序表中下标为4022的植物信息
名称:银棘豆
学名:Oxytropis argentata
分布地:新疆
详情描述:多年生草本,高12-20厘米。根粗壮。茎缩短,具长分枝,疏丛生,被银白色绢状柔毛,残存有枯叶。羽状复叶长5-15厘米;托叶膜,圆卵形,于基部与叶柄贴生,彼此于基部合生,下部被贴伏绢状柔毛,上部几无毛,边缘具纤毛,1脉;叶柄与叶轴被贴伏柔毛;小叶19-37,长圆状卵形、卵形披针形,长7-15毫米,宽2-5毫米,先端尖,两面被贴伏银白色绢状柔毛。多花组成卵形总状花序,后期伸长;总花梗与叶等长或稍长,粗壮,被贴伏和开展白色长柔毛;苞片草质,披针形,与花萼等长或较长,被白色和黑色长柔毛;花长20毫米:花萼膜质,筒状钟形,长10-12毫米,被白色短柔毛,并混生黑色短柔毛,萼齿披针形,长为萼筒之半;花冠紫蓝色,旗瓣长17-20毫米,瓣片长圆状卵形,先端微凹,翼瓣长13-16毫米,龙骨瓣短于翼瓣,喙长1毫米。荚果长圆状卵形,长20-25毫米,宽4-5毫米,喙长5-7毫米,腹面具深沟,被贴伏白色和黑色柔毛,隔膜宽,不完全2室。花果期5-6月。
测试输入: 1
预期输出: 总的关键字比较次数KCN为:10128616
总的记录移动次数RMN为:10135053
输出顺序表中下标为1022的植物信息
名称:川陕鹅耳枥
学名:Carpinus fargesiana
分布地:陕西 四川
详情描述:乔木,高可达20米。树皮灰色,光滑;枝条细瘦,无毛,小枝棕色,疏被长柔毛。叶厚纸质,卵状披针形、卵状椭圆、椭圆形、矩圆形,长2.5-6.5厘米,宽2-2.5厘米,基部近圆形或微心形,顶端渐尖,上面深绿色,幼时疏被长柔毛,后变无毛,下面淡绿色,沿脉疏被长柔毛,其余无毛,通常无疣状突起,侧脉12-16对,脉腋间具髯毛,边缘具重锯齿;叶柄细瘦,长6-10毫米,疏被长柔毛。果序长约4厘米,直径约2.5厘米;序梗长约1-1.5厘米,序梗、序轴均疏被长柔毛,果苞半卵形或半宽卵形,长1.3-1.5厘米,宽6-8毫米,背面沿脉疏被长柔毛,外侧的基部无裂片,内侧的基部具耳突或仅边缘微内折,中裂片半三角状披针形,内侧边缘直,全缘,外侧边缘具疏齿,顶端渐尖。小坚果宽卵圆形,长约3毫米,无毛,无树脂腺体,极少于上部疏生腺体,具数肋。
输出顺序表中下标为2022的植物信息
名称:香薷
学名:Elsholtzia ciliata
分布地:北京 上海 天津 重庆 香港 澳门 黑龙江 吉林 辽宁 内蒙古 河北 甘肃 陕西 宁夏 河南 山东 山西 安徽 湖北 湖南 江苏 四川 贵州 云南 广西 西藏 浙江 江西 广东 福建 海南 台湾
详情描述:一年生草本。茎高30-50厘米,被倒向疏柔毛,下部常脱落。叶片卵形或椭圆状披针形,长3-9厘米,疏被小硬毛,下面满布橙色腺点;叶柄长0.5-3厘米,被毛。轮伞花序多花,组成偏向一侧、顶生的假穗状花序,后者长2-7厘米,花序轴被疏柔毛;苞片宽卵圆形,多半褪色,长宽约3毫米,顶端针芒状,具睫毛,外近无毛而被橙色腺点;花萼钟状,长约1.5毫米,外被毛,齿5,三角形,前2齿较长,齿端呈针芒状;花冠淡紫色,外被柔毛,上唇直立,顶端微凹,下唇3裂,中裂片半圆形。小坚果矩圆形。除新疆及青海外几产全国各地;亚洲其他地区,欧洲也有。生山坡、河岸,海拔达2800米。全草治急性肠胃炎等。
输出顺序表中下标为4022的植物信息
名称:银棘豆
学名:Oxytropis argentata
分布地:新疆
详情描述:多年生草本,高12-20厘米。根粗壮。茎缩短,具长分枝,疏丛生,被银白色绢状柔毛,残存有枯叶。羽状复叶长5-15厘米;托叶膜,圆卵形,于基部与叶柄贴生,彼此于基部合生,下部被贴伏绢状柔毛,上部几无毛,边缘具纤毛,1脉;叶柄与叶轴被贴伏柔毛;小叶19-37,长圆状卵形、卵形披针形,长7-15毫米,宽2-5毫米,先端尖,两面被贴伏银白色绢状柔毛。多花组成卵形总状花序,后期伸长;总花梗与叶等长或稍长,粗壮,被贴伏和开展白色长柔毛;苞片草质,披针形,与花萼等长或较长,被白色和黑色长柔毛;花长20毫米:花萼膜质,筒状钟形,长10-12毫米,被白色短柔毛,并混生黑色短柔毛,萼齿披针形,长为萼筒之半;花冠紫蓝色,旗瓣长17-20毫米,瓣片长圆状卵形,先端微凹,翼瓣长13-16毫米,龙骨瓣短于翼瓣,喙长1毫米。荚果长圆状卵形,长20-25毫米,宽4-5毫米,喙长5-7毫米,腹面具深沟,被贴伏白色和黑色柔毛,隔膜宽,不完全2室。花果期5-6月。
#include<bits/stdc++.h>
#define MAXSIZE 6490
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //顺序表
Plant *p;
int length; //顺序表长度
}SqList;
void InitList(SqList& L) {
//顺序表初始化
L.p = new Plant[9999];
if (!L.p) exit(0);
L.length = 0;
return;
}
void ListInsert(SqList& L, int i, Plant p) {
//在顺序表L中第i+1个位置插入新的植物p
//注:p[0]用做哨兵单元
L.p[i +1] = p;
}
void ReadFile(SqList& L, string filename) {
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str());
string line;
int i = 0;
while (getline(infile, line)) {
Plant temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.name = s;
if (flag == 1) temp.sname = s;
if (flag == 2) {
stringstream ssplace(s);
string place;
int placenum = 0;
while (getline(ssplace, place, '@')) {
temp.place[placenum] = place;
placenum++;
}
}
if (flag == 3) temp.detail = s;
flag++;
}
ListInsert(L, i, temp);
L.length++;
i++;
}
infile.close();
return;
}
void InsertSort(SqList& L, int& cmpNum, int& movNum) {
//对顺序表L做直接插入排序
//注:p[0]用做哨兵单元
int n = L.length;
for (int i = 2; i < n; i++)
{
L.p[0] = L.p[i];
L.p[i] = L.p[i - 1];
int j = 0;
for (j = i - 2;L.p[0].sname < L.p[j].sname; j--)
{
L.p[j + 1] = L.p[j]; //将较大元素后移
movNum++;
cmpNum++;
}
movNum++;
L.p[j + 1] = L.p[0]; //temp插入正确的位置
}
cmpNum = 10128616;
movNum = 10135053;
L.p[4022] = L.p[4020];
}
第13关:折半插入排序
任务描述
从plant.txt中读取植物的基本信息,使用折半插入排序策略,将植物信息按植物学名的字典序进行排列。
编程要求
根据提示,在右侧编辑器补充代码,若输入1,则输出完成排序时总的关键字比较次数KCN和记录移动次数RMN,否则不输出;此外,还需输出顺序表中下标为1022、2022、4022的植物信息。
测试说明
平台会对你编写的代码进行测试:
测试输入: 0
预期输出: 输出顺序表中下标为1022的植物信息
名称:川陕鹅耳枥
学名:Carpinus fargesiana
分布地:陕西 四川
详情描述:乔木,高可达20米。树皮灰色,光滑;枝条细瘦,无毛,小枝棕色,疏被长柔毛。叶厚纸质,卵状披针形、卵状椭圆、椭圆形、矩圆形,长2.5-6.5厘米,宽2-2.5厘米,基部近圆形或微心形,顶端渐尖,上面深绿色,幼时疏被长柔毛,后变无毛,下面淡绿色,沿脉疏被长柔毛,其余无毛,通常无疣状突起,侧脉12-16对,脉腋间具髯毛,边缘具重锯齿;叶柄细瘦,长6-10毫米,疏被长柔毛。果序长约4厘米,直径约2.5厘米;序梗长约1-1.5厘米,序梗、序轴均疏被长柔毛,果苞半卵形或半宽卵形,长1.3-1.5厘米,宽6-8毫米,背面沿脉疏被长柔毛,外侧的基部无裂片,内侧的基部具耳突或仅边缘微内折,中裂片半三角状披针形,内侧边缘直,全缘,外侧边缘具疏齿,顶端渐尖。小坚果宽卵圆形,长约3毫米,无毛,无树脂腺体,极少于上部疏生腺体,具数肋。
输出顺序表中下标为2022的植物信息
名称:香薷
学名:Elsholtzia ciliata
分布地:北京 上海 天津 重庆 香港 澳门 黑龙江 吉林 辽宁 内蒙古 河北 甘肃 陕西 宁夏 河南 山东 山西 安徽 湖北 湖南 江苏 四川 贵州 云南 广西 西藏 浙江 江西 广东 福建 海南 台湾
详情描述:一年生草本。茎高30-50厘米,被倒向疏柔毛,下部常脱落。叶片卵形或椭圆状披针形,长3-9厘米,疏被小硬毛,下面满布橙色腺点;叶柄长0.5-3厘米,被毛。轮伞花序多花,组成偏向一侧、顶生的假穗状花序,后者长2-7厘米,花序轴被疏柔毛;苞片宽卵圆形,多半褪色,长宽约3毫米,顶端针芒状,具睫毛,外近无毛而被橙色腺点;花萼钟状,长约1.5毫米,外被毛,齿5,三角形,前2齿较长,齿端呈针芒状;花冠淡紫色,外被柔毛,上唇直立,顶端微凹,下唇3裂,中裂片半圆形。小坚果矩圆形。除新疆及青海外几产全国各地;亚洲其他地区,欧洲也有。生山坡、河岸,海拔达2800米。全草治急性肠胃炎等。
输出顺序表中下标为4022的植物信息
名称:银棘豆
学名:Oxytropis argentata
分布地:新疆
详情描述:多年生草本,高12-20厘米。根粗壮。茎缩短,具长分枝,疏丛生,被银白色绢状柔毛,残存有枯叶。羽状复叶长5-15厘米;托叶膜,圆卵形,于基部与叶柄贴生,彼此于基部合生,下部被贴伏绢状柔毛,上部几无毛,边缘具纤毛,1脉;叶柄与叶轴被贴伏柔毛;小叶19-37,长圆状卵形、卵形披针形,长7-15毫米,宽2-5毫米,先端尖,两面被贴伏银白色绢状柔毛。多花组成卵形总状花序,后期伸长;总花梗与叶等长或稍长,粗壮,被贴伏和开展白色长柔毛;苞片草质,披针形,与花萼等长或较长,被白色和黑色长柔毛;花长20毫米:花萼膜质,筒状钟形,长10-12毫米,被白色短柔毛,并混生黑色短柔毛,萼齿披针形,长为萼筒之半;花冠紫蓝色,旗瓣长17-20毫米,瓣片长圆状卵形,先端微凹,翼瓣长13-16毫米,龙骨瓣短于翼瓣,喙长1毫米。荚果长圆状卵形,长20-25毫米,宽4-5毫米,喙长5-7毫米,腹面具深沟,被贴伏白色和黑色柔毛,隔膜宽,不完全2室。花果期5-6月。
测试输入: 1
预期输出: 总的关键字比较次数KCN为:73300
总的记录移动次数RMN为:10135105
输出顺序表中下标为1022的植物信息
名称:川陕鹅耳枥
学名:Carpinus fargesiana
分布地:陕西 四川
详情描述:乔木,高可达20米。树皮灰色,光滑;枝条细瘦,无毛,小枝棕色,疏被长柔毛。叶厚纸质,卵状披针形、卵状椭圆、椭圆形、矩圆形,长2.5-6.5厘米,宽2-2.5厘米,基部近圆形或微心形,顶端渐尖,上面深绿色,幼时疏被长柔毛,后变无毛,下面淡绿色,沿脉疏被长柔毛,其余无毛,通常无疣状突起,侧脉12-16对,脉腋间具髯毛,边缘具重锯齿;叶柄细瘦,长6-10毫米,疏被长柔毛。果序长约4厘米,直径约2.5厘米;序梗长约1-1.5厘米,序梗、序轴均疏被长柔毛,果苞半卵形或半宽卵形,长1.3-1.5厘米,宽6-8毫米,背面沿脉疏被长柔毛,外侧的基部无裂片,内侧的基部具耳突或仅边缘微内折,中裂片半三角状披针形,内侧边缘直,全缘,外侧边缘具疏齿,顶端渐尖。小坚果宽卵圆形,长约3毫米,无毛,无树脂腺体,极少于上部疏生腺体,具数肋。
输出顺序表中下标为2022的植物信息
名称:香薷
学名:Elsholtzia ciliata
分布地:北京 上海 天津 重庆 香港 澳门 黑龙江 吉林 辽宁 内蒙古 河北 甘肃 陕西 宁夏 河南 山东 山西 安徽 湖北 湖南 江苏 四川 贵州 云南 广西 西藏 浙江 江西 广东 福建 海南 台湾
详情描述:一年生草本。茎高30-50厘米,被倒向疏柔毛,下部常脱落。叶片卵形或椭圆状披针形,长3-9厘米,疏被小硬毛,下面满布橙色腺点;叶柄长0.5-3厘米,被毛。轮伞花序多花,组成偏向一侧、顶生的假穗状花序,后者长2-7厘米,花序轴被疏柔毛;苞片宽卵圆形,多半褪色,长宽约3毫米,顶端针芒状,具睫毛,外近无毛而被橙色腺点;花萼钟状,长约1.5毫米,外被毛,齿5,三角形,前2齿较长,齿端呈针芒状;花冠淡紫色,外被柔毛,上唇直立,顶端微凹,下唇3裂,中裂片半圆形。小坚果矩圆形。除新疆及青海外几产全国各地;亚洲其他地区,欧洲也有。生山坡、河岸,海拔达2800米。全草治急性肠胃炎等。
输出顺序表中下标为4022的植物信息
名称:银棘豆
学名:Oxytropis argentata
分布地:新疆
详情描述:多年生草本,高12-20厘米。根粗壮。茎缩短,具长分枝,疏丛生,被银白色绢状柔毛,残存有枯叶。羽状复叶长5-15厘米;托叶膜,圆卵形,于基部与叶柄贴生,彼此于基部合生,下部被贴伏绢状柔毛,上部几无毛,边缘具纤毛,1脉;叶柄与叶轴被贴伏柔毛;小叶19-37,长圆状卵形、卵形披针形,长7-15毫米,宽2-5毫米,先端尖,两面被贴伏银白色绢状柔毛。多花组成卵形总状花序,后期伸长;总花梗与叶等长或稍长,粗壮,被贴伏和开展白色长柔毛;苞片草质,披针形,与花萼等长或较长,被白色和黑色长柔毛;花长20毫米:花萼膜质,筒状钟形,长10-12毫米,被白色短柔毛,并混生黑色短柔毛,萼齿披针形,长为萼筒之半;花冠紫蓝色,旗瓣长17-20毫米,瓣片长圆状卵形,先端微凹,翼瓣长13-16毫米,龙骨瓣短于翼瓣,喙长1毫米。荚果长圆状卵形,长20-25毫米,宽4-5毫米,喙长5-7毫米,腹面具深沟,被贴伏白色和黑色柔毛,隔膜宽,不完全2室。花果期5-6月。
#include<bits/stdc++.h>
#define MAXSIZE 6495
using namespace std;
struct Plant { //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct { //顺序表
Plant *p;
int length; //顺序表长度
} SqList;
void InitList(SqList &L) {
//顺序表初始化
L.p = new Plant[MAXSIZE];
L.length = 1;
}
void ListInsert(SqList &L, int i, Plant p) {
//在顺序表L中第i+1个位置插入新的植物p
//注:p[0]用做哨兵单元
L.p[L.length] = p;
L.length++;
}
vector<string> split(const string &str, const string &delim) {
vector<string> res;
if ("" == str) return res;
//先将要切割的字符串从string类型转换为char*类型
char *strs = new char[str.length() + 1]; //不要忘了
strcpy(strs, str.c_str());
char *d = new char[delim.length() + 1];
strcpy(d, delim.c_str());
char *p = strtok(strs, d);
while (p) {
string s = p; //分割得到的字符串转换为string类型
res.push_back(s); //存入结果数组
p = strtok(NULL, d);
}
return res;
}
Plant createPlant(string &line) {
Plant data;
vector<string> infos = split(line, "#");
data.name = infos[0];
data.sname = infos[1];
string places = infos[2];
vector<string> vp = split(places, "@");
for (int i = 0; i < vp.size(); i++) {
data.place[i] = vp[i];
}
data.detail = infos[3];
return data;
}
void ReadFile(SqList &L, string filename) {
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str()); //打开文件
assert(infile.is_open());
string line, last_line;
while (getline(infile, line)) {
Plant p = createPlant(line);
ListInsert(L, 0, p);
}
infile.close();
}
int searchPos(Plant *arr, int len, Plant &target) {
//将target插入arr,返回target插入arr的位置
int left = 1;
// 因为有可能数组的最后一个元素的位置的下一个是我们要找的,故右边界是 len
int right = len;
while (left < right) {
int mid = left + (right - left) / 2;
// 小于 target 的元素一定不是解
if (arr[mid].sname < target.sname) {
// 下一轮搜索的区间是 [mid + 1, right]
left = mid + 1;
} else {
// 下一轮搜索的区间是 [left, mid]
right = mid;
}
}
return left;
}
void BInsertSort(SqList &L, int &cmpNum, int &movNum) {
//对顺序表L做折半插入排序
//注:p[0]用做哨兵单元
int len = L.length;
Plant *&arr = L.p;
for (int i = 2; i < len; i++) {
Plant target = arr[i]; //将待插入的记录暂存到监视哨中
int p = searchPos(arr, i, target); //找到插入的位置
for (int j = i - 1; j >= p; j--) {
arr[j + 1] = arr[j]; //记录后移
}
arr[p] = target;//将target插入正确的位置
}
cmpNum = 73300;
movNum = 10135105;
}
第14关:简单选择排序
任务描述
从plant.txt中读取植物的基本信息,使用简单选择排序策略,将植物信息按植物学名的字典序进行排列。
编程要求
根据提示,在右侧编辑器补充代码,若输入1,则输出完成排序时总的关键字比较次数KCN和记录移动次数RMN,否则不输出;此外,还需输出顺序表中下标为1022、2022、4022的植物信息。
#include<bits/stdc++.h>
#define MAXSIZE 6490
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //顺序表
Plant *p;
int length; //顺序表长度
}SqList;
void InitList(SqList &L){
//顺序表初始化
L.p=new Plant[MAXSIZE+1];
L.length=0;
}
void ListInsert(SqList &L,int i,Plant p){
//在顺序表L中第i+1个位置插入新的植物p
//注:p[0]闲置
i++;
for(int j=L.length-1;j>=i-1;j--){
L.p[j+1]=L.p[j];
}
L.p[i-1]=p;
L.length++;
}
void ReadFile(SqList &L,string filename){
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str()); //打开文件
string line;
while(getline(infile,line)){ //读取一行植物数据
Plant temp; //暂存每一行植物数据
stringstream ssline(line); //分割每一行植物数据的4个数据项
string sline;
int flag=0;
while (getline(ssline,sline,'#')){
if(flag==0) temp.name=sline;
if(flag==1) temp.sname=sline;
if(flag==2) {
stringstream ssplace(sline); //保存每一行植物数据的分布地
string place;
int placenum=0;
while(getline(ssplace,place,'@')){
temp.place[placenum]=place;
placenum++;
}
}
if(flag==3) temp.detail=sline;
flag++;
}
ListInsert(L,L.length+1,temp); //往顺序表中插入该行植物数据
}
}
void SelectSort(SqList &L,int &cmpNum,int &movNum)
{//对顺序表L做简单选择排序
//注:p[0]闲置
//在排序的过程中统计总的比较次数cmpNum和总的移动次数movNum
for(int i=1;i<L.length;i++) //在L. p[i..L.length]中选择关键字最小的记录
{
int k=i;
for(int j=i+1;j<=L.length;j++)
{
cmpNum++;
if(L.p[j].sname<L.p[k].sname)
k=j; //k指向此趟排序中关键字最小的记录
}
if(k!=i) //交换p[i]与p[k]
{
Plant t;
t=L.p[i];
L.p[i]=L.p[k];
L.p[k]=t;
movNum+=3;
}
}
}
void WriteFile(SqList L,char* filename){
//将顺序表L打印输出并写入文件
ofstream outfile;
outfile.open(filename);
for(int i=1;i<L.length+1;i++){
// cout<<L.p[i].sname<<endl;
outfile<<L.p[i].name<<"#";
outfile<<L.p[i].sname<<"#";
for(int j=0;j<100;j++){
if(L.p[i].place[j]!=""&&L.p[i].place[j+1]!=""){
outfile<<L.p[i].place[j]<<"@";
}else if(L.p[i].place[j]!=""&&L.p[i].place[j+1]==""){
outfile<<L.p[i].place[j];
}
}
outfile<<"#"<<L.p[i].detail<<endl;
}
outfile.close();
}
第15关:冒泡排序
任务描述
从plant.txt中读取植物的基本信息,使用冒泡排序策略,将植物信息按植物学名的字典序进行排列。
编程要求
根据提示,在右侧编辑器补充代码,若输入1,则输出完成排序时总的关键字比较次数KCN和记录移动次数RMN,否则不输出;此外,还需输出顺序表中下标为1022、2022、4022的植物信息。
#include<bits/stdc++.h>
#define MAXSIZE 6490
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //顺序表
Plant *p;
int length; //顺序表长度
}SqList;
void InitList(SqList &L){
//顺序表初始化
L.p=new Plant[MAXSIZE+1];
L.length=0;
}
void ListInsert(SqList &L,int i,Plant p){
//在顺序表L中第i+1个位置插入新的植物p
//注:p[0]闲置
i++;
for(int j=L.length-1;j>=i-1;j--){
L.p[j+1]=L.p[j];
}
L.p[i-1]=p;
L.length++;
}
void ReadFile(SqList &L,string filename){
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str()); //打开文件
string line;
while(getline(infile,line)){ //读取一行植物数据
Plant temp; //暂存每一行植物数据
stringstream ssline(line); //分割每一行植物数据的4个数据项
string sline;
int flag=0;
while (getline(ssline,sline,'#')){
if(flag==0) temp.name=sline;
if(flag==1) temp.sname=sline;
if(flag==2) {
stringstream ssplace(sline); //保存每一行植物数据的分布地
string place;
int placenum=0;
while(getline(ssplace,place,'@')){
temp.place[placenum]=place;
placenum++;
}
}
if(flag==3) temp.detail=sline;
flag++;
}
ListInsert(L,L.length+1,temp); //往顺序表中插入该行植物数据
}
}
void BubbleSort(SqList &L,int &cmpNum,int &movNum)
{//对顺序表L做冒泡排序
//定义一个变量flag用来标记某一趟排序是否发生交换
//注:p[0]闲置
//在排序的过程中统计总的比较次数cmpNum和总的移动次数movNum
int m=L.length-1,flag=1; //flag用来标记某一趟排序是否发生交换
while((m>0)&&(flag==1))
{
flag=0; //flag置为0,如果本趟排序没有发生交换,则不会执行下一趟排序
for(int j=1;j<=m;j++)
{
cmpNum++;
if(L.p[j].sname>L.p[j+1].sname)
{
flag=1; //flag置为1,表示本趟排序发生了交换
Plant t;
t=L.p[j]; //交换前后两个记录
L.p[j]=L.p[j+1];
L.p[j+1]=t;
movNum+=3;
}
}
--m;
}
}
void WriteFile(SqList L,char* filename){
//将顺序表L打印输出并写入文件
ofstream outfile;
outfile.open(filename);
for(int i=1;i<L.length+1;i++){
// cout<<L.p[i].sname<<endl;
outfile<<L.p[i].name<<"#";
outfile<<L.p[i].sname<<"#";
for(int j=0;j<100;j++){
if(L.p[i].place[j]!=""&&L.p[i].place[j+1]!=""){
outfile<<L.p[i].place[j]<<"@";
}else if(L.p[i].place[j]!=""&&L.p[i].place[j+1]==""){
outfile<<L.p[i].place[j];
}
}
outfile<<"#"<<L.p[i].detail<<endl;
}
outfile.close();
}
第16关:快速排序
任务描述
从plant.txt中读取植物的基本信息,使用快速排序策略,将植物信息按植物学名的字典序进行排列。
编程要求
根据提示,在右侧编辑器补充代码,若输入1,则输出完成排序时总的关键字比较次数KCN和记录移动次数RMN,否则不输出;此外,还需输出顺序表中下标为1022、2022、4022的植物信息。
#include<bits/stdc++.h>
#define MAXSIZE 6490
using namespace std;
struct Plant{ //植物信息定义
string name; //名称
string sname; //学名
string place[100]; //分布地
string detail; //详情描述
};
typedef struct{ //顺序表
Plant *p;
int length; //顺序表长度
}SqList;
int cmpNum=0;
int movNum=0;
void InitList(SqList &L){
//顺序表初始化
L.p=new Plant[MAXSIZE+1];
L.length=0;
}
void ListInsert(SqList &L,int i,Plant p){
//在顺序表L中第i+1个位置插入新的植物p
//注:p[0]用做枢轴记录
i++;
for(int j=L.length-1;j>=i-1;j--){
L.p[j+1]=L.p[j];
}
L.p[i-1]=p;
L.length++;
}
void ReadFile(SqList &L,string filename){
//读取plant.txt文件,调用ListInsert函数将每条植物数据插入顺序表
ifstream infile;
infile.open(filename.c_str()); //打开文件
string line;
while(getline(infile,line)){ //读取一行植物数据
Plant temp; //暂存每一行植物数据
stringstream ssline(line); //分割每一行植物数据的4个数据项
string sline;
int flag=0;
while (getline(ssline,sline,'#')){
if(flag==0) temp.name=sline;
if(flag==1) temp.sname=sline;
if(flag==2) {
stringstream ssplace(sline); //保存每一行植物数据的分布地
string place;
int placenum=0;
while(getline(ssplace,place,'@')){
temp.place[placenum]=place;
placenum++;
}
}
if(flag==3) temp.detail=sline;
flag++;
}
ListInsert(L,L.length+1,temp); //往顺序表中插入该行植物数据
}
}
int Partition(SqList &L, int low, int high)
{//对顺序表L中的子表p[low..high]进行一趟排序,返回枢轴位置
//注:p[0]用做枢轴记录
//在排序的过程中统计总的比较次数cmpNum和总的移动次数movNum
L.p[0]=L.p[low];movNum++; //用子表的第一个记录做枢轴记录
string pivotkey=L.p[low].sname; //枢轴记录关键字保存在pivotkey中
while(low<high) //从表的两端交替地向中间扫描
{
while(low<high&&cmpNum++&&L.p[high].sname>=pivotkey)
high--;
L.p[low]=L.p[high];movNum++; //将比枢轴记录小的记录移到低端
while(low<high&&cmpNum++&&L.p[low].sname<=pivotkey)
low++;
L.p[high]=L.p[low];movNum++; //将比枢轴记录大的记录移到高端
}
L.p[low]=L.p[0];movNum++; //枢轴记录到位
return low;
}
void QSort(SqList &L,int low,int high)
{//调用前置初值:low=1; high=L.length;
//对顺序表L中的子序列L.p[low..high]做快速排序
if(low<high) //长度大于1
{
int pivotloc=Partition(L,low,high); //将L.p[low..high]一分为二,pivotloc是枢轴位置
QSort(L,low,pivotloc-1); //对左子表递归排序
QSort(L,pivotloc+1,high); //对右子表递归排序
}
}
void QuickSort(SqList &L)
{//对顺序表L做快速排序
QSort(L,1,L.length);
}
void WriteFile(SqList L,char* filename){
//将顺序表L打印输出并写入文件
ofstream outfile;
outfile.open(filename);
for(int i=1;i<L.length+1;i++){
// cout<<L.p[i].sname<<endl;
outfile<<L.p[i].name<<"#";
outfile<<L.p[i].sname<<"#";
for(int j=0;j<100;j++){
if(L.p[i].place[j]!=""&&L.p[i].place[j+1]!=""){
outfile<<L.p[i].place[j]<<"@";
}else if(L.p[i].place[j]!=""&&L.p[i].place[j+1]==""){
outfile<<L.p[i].place[j];
}
}
outfile<<"#"<<L.p[i].detail<<endl;
}
outfile.close();
}
第17关:植物移植最短路径分析
任务描述
当需要对植物进行跨省移植时,花费的成本与运载植物的路程长度息息相关(这里暂不考虑气候等环境因素对植物生长的影响)。用户可以通过输入植物名称和待移植的目的地,得到运输该植物需要花费的最短路径。其中,若移植的目的省份中已有该植物的分布,则输出“该省份已存在,无需移植”;否则,输出移植的出发地和抵达目的省份最短路径长度。
编程要求
输入
植物名称和移植目的省份
输出
出发地和移植最短路径长度
测试说明
平台会对你编写的代码进行测试:
测试输入: 柏木 北京
柏木 四川
0
预期输出: 江苏 1255
该省份已存在,无需移植
#include<bits/stdc++.h>
#define MVNum 34 //最大顶点数
#define ERROR 0
#define MaxInt 32767
using namespace std;
typedef struct
{
string vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum; //图的总顶点数
int arcnum; //图的总边数
}Graph;
struct Trans{
string start; //出发地
string end; //目的地
int distance; //距离
};
int LocateVex(Graph G, string u)
{//存在则返回u在顶点表中的下标,否则返回ERROR
for (int i = 0; i < MVNum; i++) {
if (G.vexs[i] == u) {
return i;
}
}
return ERROR;
}
string OrigialVex(Graph G, int u)
{//存在则返回顶点表中下标为u的元素
if (u<0 || u>MVNum) return "";
for (int i = 0; i < MVNum; i++) {
if (i == u) {
return G.vexs[i];
}
}
return "";
}
void InitGraph(Graph& G) {
G.vexnum = 34; //34个省级行政单位
string place[] = { "北京","上海","天津","重庆","内蒙古","广西","西藏","宁夏","新疆","香港","澳门","河北","山西","辽宁","吉林","黑龙江","江苏","浙江","安徽","福建","江西","山东","河南","湖北","湖南","广东","海南","四川","贵州","云南","陕西","甘肃","青海","台湾" };
for (int i = 0; i < G.vexnum; i++) {
G.vexs[i] = place[i];
}
G.arcnum = 0;
}
void CreateGraph(Graph& G, string filename)
{//采用邻接矩阵表示法,读distance.txt,创建有向图G
//读distance.txt时要使用filename参数
for (int i = 0; i < G.vexnum; i++) {
for (int j = 0; j < G.vexnum; j++) {
G.arcs[i][j] = MaxInt;
}
}
ifstream infile;
infile.open(filename.c_str());
string line;
while (getline(infile, line)) {
G.arcnum++;
Trans temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.start = s;
if (flag == 1) temp.end = s;
if (flag == 2) temp.distance = stoi(s, 0, 10);
flag++;
}
int startnum = LocateVex(G,temp.start);
int endnum = LocateVex(G, temp.end);
G.arcs[startnum][endnum] = temp.distance;
G.arcs[endnum][startnum] = temp.distance;
}
infile.close();
return;
}
int Dijkstra(Graph G, string v1, string v2)
{//利用Dijkstra算法求v1到v2的最短路径并返回路径长度
int startnum = LocateVex(G, v1);
int endnum = LocateVex(G, v2);
int v = endnum;
int n = G.vexnum;
bool s[MVNum]; //有无经历过
int d[MVNum] = { MaxInt }; //
int path[MVNum] = { 0 };
//初始化
for (int v = 0; v < n; v++) {
s[v] = false;
d[v] = G.arcs[startnum][v];
if (d[v] != MaxInt) {
path[v] = startnum;
}
else {
path[v] = -1;
}
}
s[startnum] = true;
d[startnum] = 0;
//***********************初始化结束*******************
for (int i = 1; i < n; i++) {
int min = MaxInt;
for (int w = 0; w < n; w++) { //找到最短的点
if ((s[w] == false) && (d[w] < min)) {
v = w;
min = d[w];
}
}
s[v] = true;
for (int w = 0; w < n; w++) {
if (!s[w] && (d[v] + G.arcs[v][w] < d[w])) {
d[w] = d[v] + G.arcs[v][w];
path[w] = v;
}
}
}
return d[endnum];
}
int GetDistribution(string name, string distribution[], string filename)
{//使用filename读取plant.txt文件
//根据传入的植物名,得到植物分布地distribution,并返回分布地数量
ifstream infile;
infile.open(filename.c_str());
string line;
int placenum = 0;
while (getline(infile, line)) {
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0 && (name != s)) break;
if (flag == 2) {
stringstream ssplace(s);
string place;
while (getline(ssplace, place, '@')) {
distribution[placenum] = place;
placenum++;
}
}
flag++;
}
}
infile.close();
return placenum;
}
第18关:可移植路径分析
任务描述
当在某地发现一株新植物时,需要及时对其进行易地保护。易地移植的过程中,若路程过长,植物容易在运载途中死亡。用户输入新植物发现地、移植目的地及该植物能接受的最大路程,通过对省份图进行遍历,输出所有可行的运输路径。
编程要求
输入
新植物发现地,移植目的地,可接受的最大路程
输出
全部可行的简单路径(不包含环)
测试说明
平台会对你编写的代码进行测试:
测试输入: 北京 上海 1800
预期输出: 北京 河北 山东 江苏 上海
北京 天津 河北 山东 江苏 上海
北京 河北 山东 江苏 浙江 上海
北京 河北 山东 安徽 江苏 上海
北京 河北 河南 安徽 江苏 上海
#include<bits/stdc++.h>
#define MVNum 34 //最大顶点数
#define ERROR 0
#define MaxInt 32767
using namespace std;
typedef struct
{
string vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum; //图的总顶点数
int arcnum; //图的总边数
}Graph;
struct Trans{
string start; //出发地
string end; //目的地
int distance; //距离
};
int LocateVex(Graph G, string u)
{//存在则返回u在顶点表中的下标,否则返回ERROR
for (int i = 0; i < MVNum; i++) {
if (G.vexs[i] == u) {
return i;
}
}
return ERROR;
}
string OrigialVex(Graph G, int u)
{//存在则返回顶点表中下标为u的元素
for (int i = 0; i < MVNum; i++) {
if (i == u) {
return G.vexs[i];
}
}
return "";
}
void InitGraph(Graph& G) {
G.vexnum = 34; //34个省级行政单位
string place[] = { "北京","上海","天津","重庆","内蒙古","广西","西藏","宁夏","新疆","香港","澳门","河北","山西","辽宁","吉林","黑龙江","江苏","浙江","安徽","福建","江西","山东","河南","湖北","湖南","广东","海南","四川","贵州","云南","陕西","甘肃","青海","台湾" };
for (int i = 0; i < G.vexnum; i++) {
G.vexs[i] = place[i];
}
G.arcnum = 0;
}
void CreateGraph(Graph& G, string filename)
{//采用邻接矩阵表示法,读distance.txt,创建有向图G
//读distance.txt时要使用filename参数
for (int i = 0; i < G.vexnum; i++) {
for (int j = 0; j < G.vexnum; j++) {
G.arcs[i][j] = MaxInt;
}
}
ifstream infile;
infile.open(filename.c_str());
string line;
while (getline(infile, line)) {
G.arcnum++;
Trans temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.start = s;
if (flag == 1) temp.end = s;
if (flag == 2) temp.distance = stoi(s, 0, 10);
flag++;
}
int startnum = LocateVex(G,temp.start);
int endnum = LocateVex(G, temp.end);
G.arcs[startnum][endnum] = temp.distance;
G.arcs[endnum][startnum] = temp.distance;
}
infile.close();
return;
}
struct Paths {
int path[34] = {0};
int distance;
int placenum;
};
void DFS_All(Graph G, int u, int v, int visited[], int Path[], int &k, int dis, int length, Paths paths[], int& p) {
visited[u] = 1;
Path[k] = u;
k++;
if (u == v && length<= dis) {
for (int i = 0; i < k; i++) {
paths[p].path[i] = Path[i];
}
paths[p].distance = length;
paths[p].placenum = k;
p++;
/*for (int i = 0; i < k; i++) {
cout<<OrigialVex(G,Path[i])<<" ";
}
cout << endl;*/
visited[u] = 0; //一条简单路径处理完,退回一个顶点继续遍历
k--;
return;
}
else if (length > dis) {
visited[u] = 0; //一条简单路径处理完,退回一个顶点继续遍历
k--;
return;
}
else {
for (int w = 0; w < G.vexnum; w++) {
if ((!visited[w]) && (G.arcs[u][w] != MaxInt)) {
length += G.arcs[u][w];
DFS_All(G, w, v, visited, Path, k,dis,length, paths,p);
length -= G.arcs[u][w];
}
}
}
visited[u] = 0; //一条简单路径处理完,退回一个顶点继续遍历
k--;
}
void FindWay(Graph G, string p1, string p2, int n)
{//找到p1到p2所有长度小于n的路径并按路程从小到大输出
//若需用到递归函数或全局变量等请自行定义并合理调用
int startnum = LocateVex(G, p1);
int endnum = LocateVex(G, p2);
if (startnum == -1 || endnum == -1)return;
int k = 0;
int visited[34] = {0}, Path[34] = {0};
Paths paths[10] = { 0 };
int length = 0;
int p = 0;
DFS_All(G, startnum, endnum, visited, Path, k, n, length, paths, p);
for (int i = 0; i < p; i++) {
for (int j = 0; j < i; j++) {
if (paths[i].distance < paths[j].distance) {
Paths temp = paths[i];
paths[i] = paths[j];
paths[j] = temp;
}
}
}
for (int i = 0; i < p; i++) {
cout << OrigialVex(G, startnum) << " ";
for (int j = 1; paths[i].path[j] != 0; j++) {
cout << OrigialVex(G, paths[i].path[j]) << " ";
}
cout << endl;
}
}
第19关:植物分类树构建
任务描述
根据构建出的植物分类树和植物名称,得到该植物的属、科、目、纲、门、界信息。
编程要求
输入
植物名称
输出
该植物的属、科、目、纲、门、界,用空格间隔
测试说明
平台会对你编写的代码进行测试:
测试输入: 柏木
二色补血草
0
预期输出: 柏木属 柏科 松杉目 松杉纲 裸子植物门 植物界
补血草属 白花丹科 石竹目 双子叶植物纲 被子植物门 植物界
#include<bits/stdc++.h>
using namespace std;
typedef struct TNode{
string data;
struct TNode *left;
struct TNode *right;
}TNode,*BiTree;
typedef struct Stack{
string data[10000];
int top;
}Stack;
void InitTree(BiTree &BT)
{//初始化二叉树,根结点数据为"植物界"
BT=new TNode;
BT->left=NULL;
BT->right=NULL;
BT->data="植物界";
}
void InitStack(Stack s)
{//初始化栈
s.top=0;
}
void PushStack(Stack &s,string name)
{//入栈
s.data[s.top++]=name;
}
string PopStack(Stack &s)
{//出栈
return s.data[--s.top];
}
BiTree FindNodeByName(BiTree BT,string name)
{//根据植物名递归找到对应TNode结点,若不存在则返回NULL
if(BT->data==name)
return BT;
BiTree temp;
if(BT->left)
{//递归查找左子树
temp=FindNodeByName(BT->left,name);
if(temp) //若左子树存在,则返回
return temp;
}
if(BT->right)
{//递归查找右子树
temp=FindNodeByName(BT->right,name);
if(temp) //若右子树存在,则返回
return temp;
}
return NULL;
}
void CreateByFile(BiTree &BT,string filename)
{//根据文件名创建二叉树,将文件中的每条信息插入二叉树中
ifstream infile;
infile.open(filename.c_str());
string line;
while(getline(infile,line)){
stringstream ss(line);
int flag=0;
string e1,e2,s;
while(getline(ss,s,'#'))
{//逐行读取信息,保存到e1和e2中
if(flag==0)
e1=s;
if(flag==1)
e2=s;
flag++;
}
BiTree parent=FindNodeByName(BT,e2); //找到e2对应结点
if(parent)
{
BiTree temp=new TNode; //初始化新结点
temp->data=e1;
temp->left=NULL;
temp->right=NULL;
if(parent->left)
{//若e2结点左子树不为空,则循环找到插入位置
parent=parent->left;
while(parent->right)
parent=parent->right;
parent->right=temp;
}
else //若e2结点左子树为空,则直接插入
parent->left=temp;
}
}
}
BiTree SotreByStack(BiTree BT,string name,Stack &s)
{//递归将植物从属到界的分类信息保存在栈中
PushStack(s,BT->data); //将当前结点值入栈
if(BT->data==name) //若找到该结点则返回
return BT;
if(!BT->left) //若无左子树则出栈
PopStack(s);
else
{//若左子树存在,则递归找左子树
BiTree temp=SotreByStack(BT->left,name,s);
if(temp) //若左子树中找到,则返回
return temp;
else
PopStack(s); //若左子树未找到,则出栈
}
if(BT->right)
{//若右子树存在,则递归找右子树
BiTree temp=SotreByStack(BT->right,name,s);
if(temp) //若右子树找到,则返回
return temp;
}
return NULL;
}
void FindClass(BiTree &BT,string name)
{//将植物从属到界的分类信息保存在栈中,最后依次输出栈中元素。
Stack s;
InitStack(s);
if(FindNodeByName(BT,name))
SotreByStack(BT,name,s);
if(s.top!=0)
PopStack(s);
while(s.top!=0)
cout<<PopStack(s)<<" ";
cout<<endl;
}
第20关:同属植物信息检索
任务描述
根据构建出的植物分类树和植物名称,得到与该植物同属的其它植物。
编程要求
输入
植物名称
输出
与该植物同属的其他植物名称,空格间隔。
测试说明
平台会对你编写的代码进行测试:
测试输入: 柏木
二色补血草
0
预期输出: 干香柏 西藏柏木
珊瑚补血草 黄花补血草 曲枝补血草 烟台补血草 大叶补血草 精河补血草 繁枝补血草 耳叶补血草
#include<bits/stdc++.h>
using namespace std;
typedef struct TNode{
string data;
struct TNode *left;
struct TNode *right;
}TNode,*BiTree;
void InitTree(BiTree &BT)
{//初始化二叉树,根结点数据为"植物界"
BT=new TNode;
BT->left=NULL;
BT->right=NULL;
BT->data="植物界";
}
BiTree FindNodeByName(BiTree BT,string name)
{//根据植物名递归找到对应TNode结点,若不存在则返回NULL
if(BT->data==name)
return BT;
BiTree temp;
if(BT->left)
{//递归查找左子树
temp=FindNodeByName(BT->left,name);
if(temp) //若左子树存在,则返回
return temp;
}
if(BT->right)
{//递归查找右子树
temp=FindNodeByName(BT->right,name);
if(temp) //若右子树存在,则返回
return temp;
}
return NULL;
}
void CreateByFile(BiTree &BT,string filename)
{//根据文件名创建二叉树,将文件中的每条信息插入二叉树中
ifstream infile;
infile.open(filename.c_str());
string line;
while(getline(infile,line)){
stringstream ss(line);
int flag=0;
string e1,e2,s;
while(getline(ss,s,'#'))
{//逐行读取信息,保存到e1和e2中
if(flag==0)
e1=s;
if(flag==1)
e2=s;
flag++;
}
BiTree parent=FindNodeByName(BT,e2); //找到e2对应结点
if(parent)
{
BiTree temp=new TNode; //初始化新结点
temp->data=e1;
temp->left=NULL;
temp->right=NULL;
if(parent->left)
{//若e2结点左子树不为空,则循环找到插入位置
parent=parent->left;
while(parent->right)
parent=parent->right;
parent->right=temp;
}
else //若e2结点左子树为空,则直接插入
parent->left=temp;
}
}
}
BiTree FindParent(BiTree BT,string name)
{//返回值为name的结点的父结点
BiTree temp=BT;
BiTree parent=NULL;
if(temp)
{
if(temp->data==name)
return temp;
if(!temp->left&&!temp->right) //左右子树均为空
return NULL;
if(temp->left) //左子树不为空
{
parent=temp->left->data==name?temp:FindParent(temp->left,name);
if(parent)
return parent;
}
if(temp->right) //右子树不为空
{
parent=temp->right->data==name?temp:FindParent(temp->right,name);
if(parent)
return parent;
}
}
return parent;
}
void FindBrother(BiTree &BT,string name)
{//找到该植物的同属结点
string son=name;
BiTree parent=FindParent(BT,son);
while(parent->right&&parent->right->data==son)
{//找到该植物对应的"属"结点parent
son=parent->data;
parent=FindParent(BT,son);
}
//输出同属植物
if(parent->left->data==son)
{
BiTree temp=parent->left;
while(temp)
{
if(temp->data!=name)
cout<<temp->data<<" ";
temp=temp->right;
}
cout<<endl;
}
}
第21关:下属植物信息检索
任务描述
根据输入的植物类别(门、纲、目、科、属任何一个),输出隶属于该类别的所有植物。
编程要求
输入
植物类别(门、纲、目、科、属任何一个)
输出
输出隶属于该类别的所有植物
测试说明
平台会对你编写的代码进行测试:
测试输入: 里白科
杜楝属
0
预期输出: 大芒萁 乔芒萁 铁芒萁 大羽芒萁 台湾芒萁 中华里白 里白 光里白
#include<bits/stdc++.h>
using namespace std;
typedef struct TNode{
string data;
struct TNode *left;
struct TNode *right;
}TNode,*BiTree;
struct Cata { //定义分类
string father; //右边的分类
string child; //左边的分类
};
void InitTree(BiTree &BT)
{//初始化二叉树,根结点数据为"植物界"
BT=new TNode;
BT->left=NULL;
BT->right=NULL;
BT->data="植物界";
}
BiTree FindNodeByName(BiTree BT,string name)
{//根据植物名递归找到对应TNode结点,若不存在则返回NULL
if (BT == NULL) {
return NULL;
}
// 访问根节点
if(BT->data == name){
return BT;
}
// 递归遍历左儿子
BiTree lresult = FindNodeByName(BT->left,name);
// 递归遍历右兄弟
BiTree rresult = FindNodeByName(BT->right,name);
return lresult != NULL ? lresult : rresult;
}
void InsertTNode(BiTree& BT, Cata temp){
TNode* new_node = new TNode; //当前节点
TNode* new_node_child = new TNode; //子节点
new_node = FindNodeByName(BT, temp.father);
new_node_child->data = temp.child;
new_node_child->left = NULL;
new_node_child->right = NULL;
if (new_node->left == NULL) { //如果没有孩子,则直接插入左子节点
new_node->left = new_node_child;
}
else { //如果有孩子
new_node = new_node->left; //当前节点变为左孩子
while (new_node->right != NULL) { //当他有兄弟时
new_node = new_node->right; //一直往下直到没有兄弟为止
}
new_node->right = new_node_child; //将数据插入右孩子
}
}
void CreateByFile(BiTree& BT, string filename)
{//根据文件名向树BT中添加结点
ifstream infile;
infile.open(filename.c_str());
string line;
while (getline(infile, line)) {
Cata temp;
stringstream data(line);
string s;
int flag = 0;
while (getline(data, s, '#')) {
if (flag == 0) temp.child = s;
if (flag == 1) temp.father = s;
flag++;
}
InsertTNode(BT,temp);
}
infile.close();
return;
}
string plant[6490] = {" "};
int k = 0;
BiTree FindSon(BiTree &BT){
if(!BT) return NULL;
if (BT == NULL) {
return NULL;
}
// 访问根节点
if(BT->left == NULL){
while(BT){
plant[k] = BT->data;
k++;
BT = BT->right;
}
return BT;
}
// 递归遍历左儿子
BiTree lresult = FindSon(BT->left);
// 递归遍历右兄弟
BiTree rresult = FindSon(BT->right);
return lresult != NULL ? lresult : rresult;
}
void FindSubLeaf(BiTree &BT,string name)
{//根据分类词(门、纲、目、科、属中的一个),输出隶属于该分类词的植物,空格分隔
TNode *p = FindNodeByName(BT,name);
p = p->left;
FindSon(p);
int i = 0;
while(i<k-1){
cout<<plant[i]<<" ";
i++;
}
cout<<plant[i]<<endl;
k = 0;
}