数据结构课程设计
一:选用的语言
在本次课程设计任务中,我采用的是C++作为编程语言。对此我主要的考虑如下:C++具有如下优势:
-
近乎零开销抽象
-
极高的性能及运行效率
-
极高的可底层可控性
-
极高的成熟度
-
极高的兼容性
最关键的是,结合本人自身的学习情况,比较熟悉C++,所以采用C++作为编程语言。
二:任务
1 任务描述:
- 能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。
- 从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
- 能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
- 为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)
- 赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
2 任务分析:
- 对于上述五个任务,对于任务1到任务4,首先要实现的就是对team.txt文件的读取与写入,基于这个读取与写入操作的完成,才能完成后续任务。
三:任务实现
1 文件的写入:
首先要包含头文件:
#include <fstream>
之后就可以进行创建文件流对象等操作了
ofstream o; //创建文件输出流对象,用于写入文件
o.open("team.txt", ios::app); // ios::app append 往后加
o << '\n'; //输入换行,很重要,主要是为了之后的读取操作
最后就可以根据提示进行相应就输入,以选手编号为例:
string Number; //添加参赛队伍编号
cout << "请输入参赛队伍编号:" << endl;
cin >> Number;
o << Number;
o << "#"; //根据情况判断是否要输入#号
最后的最后,把这个操作变成—Add函数,方便后续使用。
2 文件的读取:
我注意到team.txt文件中,每项数据都有空格,这不利于之后数据的使用,而C++中又没有去除字符串空格的内置函数,所以我先定义了Remove函数,去除读取的数据所有空格:
void Remove(string &s) //去除字符串中的空格
{
int index = 0;
if( !s.empty())
{
while( (index = s.find('\t',index)) != string::npos) // 需要用'\t' ,不然无法清除
{
s.erase(index,1);
}
}
}
之后,按照任务书中的要求,按照”#“来对数据进行分割读取
ifstream i; //创建文件输入流对象,用于读取文件
i.open("team.txt"); // 读取team.txt文件
string Temp; //按行读取后储存在Temp字符串
while (getline(i, Temp)) //按行读取
{
Remove(Temp); //按行读取,每一行都记录到Temp
for (int j = 0; j < 6; j++) //每行六项数据
{
int Position = Temp.find('#'); //寻找#,记录#出现的位置
string s = Temp.substr(0,Position); //字符串s记录所需要的数据
Temp = Temp.substr(Position + 1);
cout << s<<endl;
}
}
i.close(); //关闭文件
最后,可以将读取操作变成一个函数—Read,方便调用。
以下是部分的运行结果(结果太长无法全部展示):
3 二叉排序树的创建:
创建二叉排序树之前,要先把从文件中读取的数据先储存起来,对此于**2 文件的读取**中的代码第12行中的内容要做一下修改:
Team.push_back(s); //将队伍信息存入容器
在这之前要先定义一个容器Team:
vector<string> Team; //储存队伍信息的容器
然后就到了二叉排序树的创建:
定义所需的结构体 :
typedef struct
{
long long Number; //参赛作品编号
string Production; //添加参赛作品名称
string Campus; //参赛学校
string Category; //参赛类别
string StudentName; //参赛学生姓名
string TeacherName; //指导老师姓名
} ElemType;
typedef struct BSTNode
{
ElemType data; //每个结点的数据域包括参赛作品编号和其他数据项
struct BSTNode *lchild, *rchild; //左右孩子指针
} BSTNode, *BSTree;
定义创建二叉排序树的函数插入:InsertBST 和创建:CreatBST:
void InsertBST(BSTree &T, ElemType e)
{
if (!T)
{
BSTNode *S = new BSTNode; //生成新结点*S
S->data = e; //新结点*S的数据域置为e
S->lchild = S->rchild = NULL; //新结点*S作为叶子结点
T = S; //把新结点*S链接到已找到的插入位置
}
else if (e.Number < T->data.Number)
{
InsertBST(T->lchild, e);
} //将*S插入左子树
else if (e.Number > T->data.Number)
{
InsertBST(T->rchild, e);
} //将*S插入右子树
}
int Flag = 6; //全局变量,前六个为无用信息
void CreatBST(BSTree &T)
{
//依次读入一个关键字为Number的结点,将此结点插入二叉排序树T中
T = NULL; //将二叉排序树T初始化为空树
ElemType e; //容器中对应的信息放入树中
e.Number = stod(Team.at(Flag++)); // stod函数转化为整形
e.Production = Team.at(Flag++);
e.Campus = Team.at(Flag++);
e.Category = Team.at(Flag++);
e.StudentName = Team.at(Flag++);
e.TeacherName = Team.at(Flag++);
while (Flag < Team.size()-6) //前六个为无用信息
{
InsertBST(T, e);
//容器中对应的信息放入树中
e.Number = stod(Team.at(Flag++));
e.Production = Team.at(Flag++);
e.Campus = Team.at(Flag++);
e.Category = Team.at(Flag++);
e.StudentName = Team.at(Flag++);
e.TeacherName = Team.at(Flag++);
}
InsertBST(T, e);
}
验证是否成功创建二叉排序树,可以依据中序遍历,输出参赛队伍编号查看其是否为升序,对此定义了一个采用递归方法的InorderTree函数:
void InorderTree(BSTree T)
{
if (T)
{
InorderTree(T->lchild);
cout << T->data.Number << " ";
InorderTree(T->rchild);
}
}
主函数中进行相关函数调用后,输出结果如下:
成功!
4 按参赛队伍编号查找:
基于二叉排序树的查找,定义Find函数来进行依据参赛队伍编号进行查找,对于输出ASL查找成功时的平均查找长度,要创建ASL函数进行统计所有结点的深度和节点数:
首先是定义所需要的全局变量:
int VertexSum = 0; //节点数
然后是ASL函数:
int ASL(BSTree T, int depth)
{ //利用递归计算所有节点深度和
if (T)
{
VertexSum++;
return depth + ASL(T->rchild, depth + 1) + ASL(T->lchild, depth + 1);
}
else
return 0;
}
最后是Find函数:
void Find(BSTree T)
{
cout << "请输入参赛队伍的编号:" << endl;
long long Number;
cin >> Number;
BSTree TempT1; //暂时创建一颗树储存找到的信息
TempT1 = SearchBST(T, Number);
if (TempT1)
{ //找到了
cout << "参赛队伍编号:" << endl;
cout << TempT1->data.Number << endl;
cout << "参赛作品名称:" << endl;
cout << TempT1->data.Production << endl;
cout << "参赛学校:" << endl;
cout << TempT1->data.Campus << endl;
cout << "赛事类别:" << endl;
cout << TempT1->data.Category << endl;
cout << "参赛者:" << endl;
cout << TempT1->data.StudentName << endl;
cout << "指导老师:" << endl;
cout << TempT1->data.TeacherName << endl;
cout << "当前二叉树的查找成功时的平均查找长度为: " << endl;
int DepthSum = ASL(T, 0);
double ASL2 = (double)DepthSum / VertexSum;
cout << ASL2 << endl;
;
}
else
{
cout << "查找错误!请检查队伍编号是否正确!" << endl;
}
cout<<"请重新选择功能!"<<endl;
}
运行结果如下:
5 增加参赛队伍的信息:
参考1 文件的写入,补全其余代码即可。以下为实现操作的Add函数:
void Add()
{ //往txt文件添加操作
ofstream o; //创建文件输出流对象,用于写入文件
o.open("team.txt", ios::app); // ios::app append 往后加
o << '\n'; //换行,很重要
string Number; //添加参赛队伍编号
cout << "请输入参赛队伍编号:" << endl;
cin >> Number;
o << Number;
o << "#";
string Production; //添加参赛作品名称
cout << "请输入参赛作品名称:" << endl;
cin >> Production;
o << Production;
o << "#";
string Campus; //添加参赛学校
cout << "请输入参赛学校:" << endl;
cin >> Campus;
o << Campus;
o << "#";
string Category; //添加参赛类别
cout << "请输入参赛类别:" << endl;
cin >> Category;
o << Category;
o << "#";
string StudentName; //添加参赛学生姓名
cout << "请输入参赛学生姓名:" << endl;
cin >> StudentName;
o << StudentName;
o << "#";
string TeacherName; //添加指导老师姓名
cout << "请输入指导老师姓名:" << endl;
cin >> TeacherName;
o << TeacherName;
o.close(); //关闭文件
}
6 删除参赛队伍信息:
要想删除一个参赛队伍的参赛信息,首先要根据这支队伍的编号来找到这支队伍,然后要对team.txt文件中所对应的信息。我使用的操作是,先删除Team容器里的信息(Team容器在3 二叉排序树的创建首次出现),然后根据Team容器创建一个新的team1.txt,再讲原先的team.txt文件删除,最后将team1.txt改名为team.txt。实现该操作首先需要一个能根据容器创建新team1.txt,并改名的函数CreatNewTxt:
void CreatNewTxt()
{ //创建新的txt文件,用于参赛信息的修改和删除
ofstream o1; //创建文件输出流对象,用于写入文件
o1.open("team1.txt"); // 创建一个team1.txt文件
for (int i = 0; i < Team.size(); i++)
{
o1 << Team.at(i);
if (i % 6 == 5)
{
o1 << '\n'; //换行,很重要
}
else
{
o1 << "#";
}
}
o1.close(); //关闭文件
}
然后再根据编号,创建删除Team容器信息的DeleteProj函数,其中要调用CreatNewTxt函数:
int Exisit = 0; // DeleteProjet函数中,判断是否存在的标志
void DeleteProject()
{
long long DeleteNumber;
cout << "请输入要删除的参赛项目编号:" << endl;
cin >> DeleteNumber;
for (int i = 6; i < Team.size(); i += 6)
{
if (DeleteNumber == stoll(Team.at(i))) //找到要删除的编号
{
cout << "你要删除的参赛信息为:" << endl; //输出移除参赛编号以及后续的信息
cout << "参赛编号:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
cout << "参赛作品名称:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
cout << "参赛学校:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
cout << "赛事类别:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
cout << "参赛者:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
cout << "指导老师:" << endl;
cout << Team.at(i) << endl;
Team.erase(Team.begin() + i);
CreatNewTxt(); //创建新的team1文件储存信息
Exisit = 1;
remove("team.txt"); // 删除原始team文件
cout << "删除成功!" << endl;
break;
}
}
if (Exisit == 0)
{
cout << "输入的编号有误!" << endl;
}
}
运行结果如下:
然后查看team.txt文件,要删除的编号为2021009290的参赛队伍已经删除:
删除前(要删除的队伍在第一行):
删除后:
7 修改参赛队伍信息:
要修改一个参赛队伍的信息,首先要找到这个参赛队伍,然后对之前定义的Team容器里的要修改的相关信息进行修改,我认为这一步的操作与6 删除参赛队伍信息的操作很类似,具体操作如下:
CreatNewTxt函数(6 删除参赛队伍信息中出现):
void CreatNewTxt()
{ //创建新的txt文件,用于参赛信息的修改和删除
ofstream o1; //创建文件输出流对象,用于写入文件
o1.open("team1.txt"); // 创建一个team1.txt文件
for (int i = 0; i < Team.size(); i++)
{
o1 << Team.at(i);
if (i % 6 == 5)
{
o1 << '\n'; //换行,很重要
}
else
{
o1 << "#";
}
}
o1.close(); //关闭文件
}
最重要的ChangeProject函数:
void ChangeProject()
{ //更改信息的函数
cout << "请输入要修改参赛编号:" << endl;
long long FindNumber;
cin >> FindNumber;
for (int i = 6; i < Team.size(); i += 6)
{
if (FindNumber == stoll(Team.at(i))) //找到要修改的编号
{
cout << "你要修改的参赛信息为:" << endl; //输出要修改信息
cout << "1 参赛编号:" << endl;
cout << Team.at(i) << endl;
cout << "2 参赛作品名称:" << endl;
cout << Team.at(i + 1) << endl;
cout << "3 参赛学校:" << endl;
cout << Team.at(i + 2) << endl;
cout << "4 赛事类别:" << endl;
cout << Team.at(i + 3) << endl;
cout << "5 参赛者:" << endl;
cout << Team.at(i + 4) << endl;
cout << "6 指导老师:" << endl;
cout << Team.at(i + 5) << endl;
Exisit = 1;
cout << "你要修改哪一项:(输入要修改目标的编号1-6)" << endl;
int Selection2;
cin >> Selection2;
switch (Selection2)
{
case 1:
{
cout << "请输入修改后的队伍编号:" << endl;
string Modification;
cin >> Modification;
Team.at(i) = Modification;
cout << "修改完成!" << endl;
break;
}
case 2:
{
cout << "请输入修改后的参赛队伍名称:" << endl;
string Modification;
cin >> Modification;
Team.at(i + 1) = Modification;
cout << "修改完成!" << endl;
break;
}
case 3:
{
cout << "请输入修改后的参赛学校:" << endl;
string Modification;
cin >> Modification;
Team.at(i + 2) = Modification;
cout << "修改完成!" << endl;
break;
}
case 4:
{
cout << "请输入修改后的赛事类别:" << endl;
string Modification;
cin >> Modification;
Team.at(i + 3) = Modification;
cout << "修改完成!" << endl;
break;
}
case 5:
{
cout << "请输入修改后的参赛者:" << endl;
string Modification;
cin >> Modification;
Team.at(i + 4) = Modification;
cout << "修改完成!" << endl;
break;
}
case 6:
{
cout << "请输入修改后的指导老师:" << endl;
string Modification;
cin >> Modification;
Team.at(i + 5) = Modification;
cout << "修改完成!" << endl;
break;
}
}
cout << "修改后参赛信息为:" << endl; //输出修改后信息
cout << "参赛编号:" << endl;
cout << Team.at(i) << endl;
cout << "参赛作品名称:" << endl;
cout << Team.at(i + 1) << endl;
cout << "参赛学校:" << endl;
cout << Team.at(i + 2) << endl;
cout << "赛事类别:" << endl;
cout << Team.at(i + 3) << endl;
cout << "参赛者:" << endl;
cout << Team.at(i + 4) << endl;
cout << "指导老师:" << endl;
cout << Team.at(i + 5) << endl;
CreatNewTxt(); //创建新的team1文件储存信息
remove("team.txt"); // 删除原始team文件
break;
}
}
if (Exisit == 0)
{
cout << "输入的编号有误!" << endl;
}
}
具体运行结果:
修改后的team.txt文件(第二行的参赛者):
8 按照参赛学校查找队伍:
首先要定义一个Campus函数,对上述定义的Team容器进行遍历,寻找符合寻找要求的大学名称,之后将其对应的选手编号等信息存入定义的E1结构体数组。代码如下:
void CampusFind()
{
int j = 0; //计数器
string FindCampus;
cout << "请输入要找寻的学校:" << endl;
cin >> FindCampus;
ElemType E1[999]; //包含结构体数组
for (int i = 2; i < Team.size(); i += 6)
{
if (Team.at(i) == FindCampus)
{
//对各种信息赋值
E1[j].Number = stod(Team.at(i - 2));
E1[j].Production = Team.at(i - 1);
E1[j].Campus = Team.at(i);
E1[j].Category = Team.at(i + 1);
E1[j].StudentName = Team.at(i + 2);
E1[j].TeacherName = Team.at(i + 3);
j++;
}
}
//对结构体数字E1按照作品编号进行直接插入排序(升序):
for (int i = 1; i < j; ++i)
{
E1[j] = E1[i];
int k = i - 1;
while (k >= 0 && E1[k].Number > E1[j].Number)
{
E1[k + 1] = E1[k];
--k;
}
E1[k + 1] = E1[j];
}
//进行输出
for (int i = 0; i < j; i++)
{
cout << "参赛队伍编号:" << endl;
cout << E1[i].Number << endl;
cout << "参赛作品名称:" << endl;
cout << E1[i].Production << endl;
cout << "参赛学校:" << endl;
cout << E1[i].Campus << endl;
cout << "赛事类别:" << endl;
cout << E1[i].Category << endl;
cout << "参赛者:" << endl;
cout << E1[i].StudentName << endl;
cout << "指导老师:" << endl;
cout << E1[i].TeacherName << endl;
}
}
其中,对符合要求的参赛队伍,我选择的是按照参赛编号升序排序。我采用的算法是直接插入排序,理由如下:
- 实现简单:直接插入排序算法实现起来相对简单,容易理解和编写。
- 稳定性好:在排序过程中,如果两个元素的值相等,不会改变它们之间的相对位置。因此,直接插入排序是一种稳定的排序算法。
- 对于小规模数据集表现良好:当待排序数组规模较小时,直接插入排序效率比较高。
- 部分有序情况下效率较高:如果待排序数组已经部分有序,则直接插入排序算法的时间复杂度可以降至O(n)。
以下是程序运行结果:
9 决赛叫号系统
首先定义Read函数讲team.txt文件中的信息储存在string类型的容器AllTeam1中,还是需要去除空格的Remove函数,然后根据信息,再存入结构体数组t,并设定随机的答辩时间,最后存入Team类型的容器AllTeam中:
vector<string> AllTeam1;
int Flag = 6; //前六个为无用信息
vector<Team> AllTeam; //所有队伍的容器
typedef struct
{
string Number; //参赛作品编号
string Production; //添加参赛作品名称
string Campus; //参赛学校
string Category; //参赛类别
string StudentName; //参赛学生姓名
string TeacherName; //指导老师姓名
int DefenseTime; //答辩时间
} Team;
void Remove(string &s) //去除字符串中的空格
{
int index = 0;
if (!s.empty())
{
while ((index = s.find('\t', index)) != string::npos) // 需要用'\t' ,不然无法清除
{
s.erase(index, 1);
}
}
}
void Read()
{
ifstream i; //创建文件输入流对象,用于读取文件
i.open("team.txt"); // 读取team.txt文件
string Temp; //按行读取后储存在Temp字符串
while (getline(i, Temp)) //按行读取
{
Remove(Temp); //按行读取,每一行都记录到Temp
for (int j = 0; j < 6; j++) //每行六项数据
{
int Position = Temp.find('#'); //寻找#,记录#出现的位置
string s = Temp.substr(0, Position); //字符串s记录所需要的数据
Temp = Temp.substr(Position + 1);
AllTeam1.push_back(s);
}
}
i.close(); //关闭文件
for (int i = 0; i < 398; i++)
{
t[i].Number = AllTeam1.at(Flag++);
t[i].Production = AllTeam1.at(Flag++);
t[i].Campus = AllTeam1.at(Flag++);
t[i].Category = AllTeam1.at(Flag++);
t[i].StudentName = AllTeam1.at(Flag++);
t[i].TeacherName = AllTeam1.at(Flag++);
int DefenseTime1 = rand() % 5 + 6; //答辩时间6到10分钟
t[i].DefenseTime = DefenseTime1;
AllTeam.push_back(t[i]);
}
}
定义当前时间480分钟,即8:00,定义叫号系统的函数,对每个房间编号和房间容器进行操作,创建打印函数Print,对相关 信息进行输出:
int Current = 480; //当前时间,默认为8:00
vector<Team> Room1; //一到九号决赛室
vector<Team> Room2;
vector<Team> Room3;
vector<Team> Room4;
vector<Team> Room5;
vector<Team> Room6;
vector<Team> Room7;
vector<Team> Room8;
vector<Team> Room9;
void CallSystem(int Number, vector<Team> &Room)
{ //决赛室的编号
cout << Number << "号决赛室:";
if (Room.empty())
{
if (!AllTeam.empty()) //还有需要比赛的队伍
{
Room.push_back(AllTeam.at(0)); //待比赛队伍放第一个放入决赛室然后出容器
cout << "暂无队伍,下一个队伍编号:" << Room.at(0).Number << endl;
AllTeam.erase(AllTeam.begin());
}
else
{
cout << "暂无队伍需要答辩" << endl;
}
}
else //决赛室不可用
{
Room.at(0).DefenseTime--; //答辩时间减少
cout << Room.at(0).Number << endl;
if (Room.at(0).DefenseTime == 0) //答辩时间为0,即答辩完成
{
Room.erase(Room.begin()); //出房间
}
}
}
void Display()
{
while (!AllTeam.empty() || !Room1.empty() || !Room2.empty() || !Room3.empty() || !Room4.empty() || !Room5.empty() || !Room6.empty() || !Room7.empty() || !Room8.empty() || !Room9.empty())
{ //待比赛队伍非空
cout << "当前时间:";
int Hour = Current / 60;
int Minute = Current % 60;
cout << setw(2) << setfill('0') << Hour << ":" << setw(2) << Minute << endl;
CallSystem(1, Room1);
CallSystem(2, Room2);
CallSystem(3, Room3);
CallSystem(4, Room4);
CallSystem(5, Room5);
CallSystem(6, Room6);
CallSystem(7, Room7);
CallSystem(8, Room8);
CallSystem(9, Room9);
Current++; //时间推进
}
if (AllTeam.empty())
{
cout << "当前时间:";
int Hour = Current / 60;
int Minute = Current % 60;
cout << setw(2) << setfill('0') << Hour << ":" << setw(2) << Minute << endl;
cout << "全部项目答辩完成" << endl;
}
}
演示结果(太长,选取部分):
10 校园导游程序
针对此项任务,结合数据结构课程所学到的知识,我首先想到的是利用Dijkstra算法来实现。
地图如下:
Dijkstra算法
算是贪心思想实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离。
为此,首先要先定义图的结构体,包含目标节点,以及二者之间的路径:
struct Edge
{
int v; // 目标节点,即下一个地点
int w; // 权重,即路径长度
};
然后定义Edge容器数组,名称为graph,对应的位置存对应的信息,并用InitializationDiagram函数,来对结构体进行初始化:
vector<Edge> graph[MAXN]; // 图
oid InitializationDiagram()
{
// graph[u].push_back({v, w}); 点u 和点v的距离为w
graph[1].push_back({2, 100});
graph[1].push_back({4, 200});
graph[2].push_back({1, 100});
graph[2].push_back({3, 80});
graph[2].push_back({4, 50});
graph[3].push_back({2, 80});
graph[3].push_back({5, 120});
graph[3].push_back({6, 110});
graph[4].push_back({1, 200});
graph[4].push_back({2, 150});
graph[4].push_back({5, 50});
graph[5].push_back({3, 120});
graph[5].push_back({4, 50});
graph[5].push_back({8, 150});
graph[5].push_back({9, 230});
graph[6].push_back({3, 110});
graph[6].push_back({7, 80});
graph[6].push_back({8, 60});
graph[7].push_back({6, 80});
graph[7].push_back({10, 100});
graph[8].push_back({5, 150});
graph[8].push_back({6, 60});
graph[8].push_back({9, 90});
graph[8].push_back({10, 70});
graph[9].push_back({5, 230});
graph[9].push_back({8, 90});
graph[9].push_back({10, 50});
graph[10].push_back({7, 100});
graph[10].push_back({8, 70});
graph[10].push_back({9, 50});
}
定义一些需要使用的全局变量:path数组用来储存最短路径经过的点,dist数组记录距离,visited数组记录每个点是否被访问。
const int MAXN = 10005;
const int INF = 0x3f3f3f3f;
int n = 10; //点数
int m = 15; //边数
int Star; //起始点
int End; //目标点
int dist[MAXN];
bool visited[MAXN];
int path[MAXN];
然后是Dijkstra算法的主体部分:
void dijkstra()
{
memset(dist, INF, sizeof(dist)); //包含在库cstring中的menset函数,用于初始化
memset(visited, false, sizeof(visited));
memset(path, -1, sizeof(path));
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, Star));
dist[Star] = 0;
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (visited[u])
continue;
visited[u] = true;
for (int i = 0; i < graph[u].size(); i++)
{
int v = graph[u][i].v;
int w = graph[u][i].w;
if (!visited[v] && dist[v] > dist[u] + w)
{
dist[v] = dist[u] + w;
pq.push(make_pair(dist[v], v));
path[v] = u;
}
}
}
}
主函数经过调用后,程序运行结果如下:
分:
void dijkstra()
{
memset(dist, INF, sizeof(dist)); //包含在库cstring中的menset函数,用于初始化
memset(visited, false, sizeof(visited));
memset(path, -1, sizeof(path));
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push(make_pair(0, Star));
dist[Star] = 0;
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (visited[u])
continue;
visited[u] = true;
for (int i = 0; i < graph[u].size(); i++)
{
int v = graph[u][i].v;
int w = graph[u][i].w;
if (!visited[v] && dist[v] > dist[u] + w)
{
dist[v] = dist[u] + w;
pq.push(make_pair(dist[v], v));
path[v] = u;
}
}
}
}
主函数经过调用后,程序运行结果如下:
[外链图片转存中…(img-jJFrIP9k-1685874821115)]