目录
图的实现
文件名 | 功能 |
---|---|
ALGraphAlgo.h | 定义了图数据结构相关的函数,包括无向图的创建、获取顶点数据、邻接边及遍历操作。 |
ALGraphDef.h | 定义了图的邻接列表数据结构,包括顶点、边的结构体和图的数据结构,以及队列结构。 |
pubuse.h | 包含基本的标准库导入,定义了布尔常量、枚举和类型别名,用于项目中的通用操作。 |
ALGraphUse.cpp | 实现了一个交互式应用,允许用户创建、探索并遍历图,使用了上述头文件中定义的数据结构和函数。 |
整个程序的功能是:提供一个基于命令行的图形数据结构交互式工具,用户可以创建无向图,查询顶点信息和邻接边,并进行深度优先和广度优先遍历。
这些文件整体上构成了一个C++实现的图数据结构库,包含图的定义、算法实现以及一个示例应用,让用户能够创建、操作和遍历无向图。
项目获取
所有代码已经上传到CSDN,通过资源绑定功能,已经绑定本篇博客,有需要请自取,完整的VS2022项目,运行“数据结构-二叉树.sln”即可在vs2022中打开(一般来说,版本无限制)
在我上传时,设置了0积分,可以免费获取,但不保证后续积分要求会不会变化(但放心,不会变成付费或会员专享资源),不过,还请尽快保存!
具体实现解析
pubuse.h
C++头文件
pubuse.h
是一个C++头文件,包含了一系列标准库和自定义常量及类型的定义。这个文件的主要目的是提供常用的函数和类型以便在项目中使用:
- 引入多种标准库,如
<string>
,<iostream>
,<math.h>
等,支持字符串操作,输入输出,数学计算等功能。 - 定义了一些布尔常量
TRUE
和FALSE
,以及状态枚举OK
,ERROR
,INFEASIBLE
,原本可能用于表示函数调用的结果。 - 使用
typedef
定义了Status
和Boolean
类型,简化了代码中对整型常量作为返回值或参数的使用。 - 注意到注释中提到的
OVERFLOW
原本被定义,但因为math.h
已经定义了相同的值,所以取消了定义。
这个文件可能在更大的数据结构或算法实现项目中用作通用的头文件,为其他源代码文件提供共用的类型和常量。
#include<string>
#include<ctype.h>
#include<malloc.h> /* malloc()等*/
#include<limits.h> /* INT_MAX 等*/
#include<stdio.h> /* EOF(=^Z 或F6),NULL */
#include<iostream>
#include<stdlib.h> /* atoi() */
#include<io.h> /* eof() */
#include<math.h>/* floor(),ceil(),abs() */
#include<process.h> /* exit() */
#include"conio.h"
#include <sstream>
using namespace std;
/* 函数结果状态代码*/
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
//#define OVERFLOW -2 因为在math. h 中已定义OVERFLOW 的值为3,故去掉此行
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如OK 等*/
typedef int Boolean; /* Boolean 是布尔类型,其值是TRUE 或FALSE */
ALGraphDef.h
C++头文件
ALGraphDef.h
是一个C++头文件,它定义了一个图的数据结构和相关操作。以下是文件内容的概述:
#include "pubuse.h"
:包含另一个名为"pubuse.h"的头文件。MVNum 100
:定义了一个常量MVNum,值为100,可能用于限制图中顶点的最大数量。OtherInfo
结构体:存储图中的边的额外信息(例如权重),包含一个double类型的'l'成员。ArcNode
结构体:表示图中的有向边,包含:adjvex
:边连接的顶点索引。nextarc
:指向下一个相邻边的指针(链表结构)。info
:存储与边相关的OtherInfo
对象。
VerTexType
结构体:表示图中的顶点,包含一个字符串s
作为顶点数据。VNode
结构体:表示图的顶点节点,包含:data
:顶点数据,类型为VerTexType
。firstarc
:指向顶点的第一个邻接边的指针。
ALGraph
结构体:定义了一个邻接列表表示的图,包括:vertices
:AdjList
类型的数组,存储所有顶点。vexnum
:图中顶点的数量。arcnum
:图中边的数量。
QNode
结构体:表示队列中的节点,包含一个整型变量v
和一个指向下一个节点的指针next
。QueuePtr
类型定义:指向QNode
结构体的指针。LinkQueue
结构体:表示链式队列,包含front
和rear
指针,分别指向队列的头部和尾部。
这个头文件提供了图、顶点、边和链式队列的基本数据结构定义,可用于实现图的各种算法,如遍历、搜索等。
#include "pubuse.h"
#define MVNum 100
typedef struct {
double l; //边的长度
}OtherInfo;
typedef struct ArcNode // 边结点
{
int adjvex; // 边指向顶点的位置
struct ArcNode* nextarc = nullptr; // 边下一个结点位置
OtherInfo info; // 边相关信息
}ArcNode; // 边类型
typedef struct
{
string s; // 顶点信息
}VerTexType; // 顶点类型
typedef struct VNode // 顶点结点
{
VerTexType data; // 顶点信息
struct ArcNode* firstarc; // 顶连接的边
}VNode, AdjList[MVNum]; // 顶点数组
typedef struct
{
AdjList vertices; // 顶点数组
int vexnum, arcnum; // 顶点数和边数
}ALGraph;
// 队列
typedef struct QNode {
int v; // 顶点位置
struct QNode* next; // 下一个结点
}QNode, * QueuePtr; // 队列指针
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
}LinkQueue; // 队列
ALGraphAlgo.h
C++头文件
ALGraphAlgo.h
是一个C++头文件,它定义了与图数据结构相关的函数。这个文件主要实现了无向图(Undirected Graph,UDG)的创建、获取顶点数据、获取顶点邻接边、遍历(深度优先搜索DFS和广度优先搜索BFS)等功能。
LinkVex
函数用于在图中添加两个顶点之间的边,并保持图的无向性。CreateUDG
函数从用户输入创建一个无向图,包括读取顶点数、边数以及边的权重信息。GetVexData
函数获取指定顶点的数据。GetVexArc
函数显示给定顶点的所有邻接边及其权重。GetAllVexArc
函数显示图中所有顶点的邻接边及其权重。DFS
和useDFS
函数实现了深度优先遍历图。BFS
和useBFS
函数实现了广度优先遍历图。- 文件还包含了一些辅助的队列操作函数,如初始化队列、入队、出队和判断队列是否为空。
这些函数使用了简单的邻接表(Adjacency List)来存储图的结构,每个顶点都有一个指向其邻接顶点的链表。
#include "ALGraphDef.h"
// 无向图连接2点
void LinkVex(ALGraph& G, int v1, int v2, double l) {
// v1顶点连接v2顶点
if (G.vertices[v1].firstarc == nullptr) {
G.vertices[v1].firstarc = new ArcNode;
G.vertices[v1].firstarc->adjvex = v2;
G.vertices[v1].firstarc->info.l = l;
}
else {
ArcNode* p1 = G.vertices[v1].firstarc;
if (p1->adjvex == v2) {
cout << "两顶点已连接" << endl;
return;
}
while (p1->nextarc) {
if (p1->nextarc->adjvex == v2) {
cout << "两顶点已连接" << endl;
return;
}
p1 = p1->nextarc;
}
ArcNode* pp1 = new ArcNode;
pp1->adjvex = v2;
pp1->info.l = l;
p1->nextarc = pp1;
}
// v2顶点连接v1顶点
if (G.vertices[v2].firstarc == nullptr) {
G.vertices[v2].firstarc = new ArcNode;
G.vertices[v2].firstarc->adjvex = v1;
G.vertices[v2].firstarc->info.l = l;
}
else {
ArcNode* p2 = G.vertices[v2].firstarc;
if (p2->adjvex == v1) {
cout << "两顶点已连接" << endl;
return;
}
while (p2->nextarc) {
if (p2->nextarc->adjvex == v1) {
cout << "两顶点已连接" << endl;
return;
}
p2 = p2->nextarc;
}
ArcNode* pp2 = new ArcNode;
pp2->adjvex = v1;
pp2->info.l = l;
p2->nextarc = pp2;
}
}
// 采用邻接表表示法创建无向图
Status CreateUDG(ALGraph& G) {
cout << "输入总顶点数和总边数,用空格隔开:";
cin >> G.vexnum >> G.arcnum;
cin.clear();
cin.ignore();
if (G.vexnum > MVNum || G.vexnum < 0) return ERROR;
for (int i = 0; i < G.vexnum; i++) {
cout << "输入序号为" << i + 1 << "的顶点值:";
getline(cin, G.vertices[i].data.s); //输人顶点值
G.vertices[i].firstarc = nullptr;
}
cout << "----------------------" << endl;
cout << "边的信息包括:边连接2个顶点的序号,和边的长度。用空格隔开" << endl;
cout << "比如:1 3 2.3 表示,该边连接序号为1和3的顶点,长度为2.3" << endl;
for (int k = 0; k < G.arcnum; k++) {
cout << "输入第" << k + 1 << "条边的信息:";
int v1, v2;
double l;
cin >> v1 >> v2 >> l;
v1 -= 1;
v2 -= 1;
if (l < 0 || v1 < 0 || v2 < 0 || v1 > G.vexnum - 1 || v2 > G.vexnum - 1 || cin.fail()) {
cin.clear();
cin.ignore();
return ERROR;
}
LinkVex(G, v1, v2, l);
}
return OK;
}
// 获取顶点的值
Status GetVexData(ALGraph G) {
cout << "输入顶点的序号,获取顶点的值:";
int choice;
cin >> choice;
choice -= 1;
if (choice > G.vexnum - 1 || choice < 0 || cin.fail()) return ERROR;
cout << "序号为" << choice + 1 << "的顶点的值为:" << G.vertices[choice].data.s << endl;
return OK;
}
// 获取顶点的邻接点
Status GetVexArc(ALGraph G) {
cout << "输出:值(序号)----边的长度---->" << endl;
cout << "获取顶点的邻接点,输入顶点的序号:";
int choice;
cin >> choice;
choice -= 1;
if (choice > G.vexnum - 1 || choice < 0 || cin.fail()) return ERROR;
ArcNode* p = G.vertices[choice].firstarc;
cout << G.vertices[choice].data.s << "(" << choice + 1 << ")";
while (p)
{
cout << "----" << p->info.l << "---->";
cout << G.vertices[p->adjvex].data.s << "(" << p->adjvex + 1 << ")";
p = p->nextarc;
}
cout << endl;
return OK;
}
// 整体输出邻接表
Status GetAllVexArc(ALGraph G) {
cout << "输出:值(序号)----边的长度---->" << endl;
for (int i = 0; i < G.vexnum; i++) {
ArcNode* p = G.vertices[i].firstarc;
cout << G.vertices[i].data.s << "(" << i + 1 << ")";
while (p)
{
cout << "----" << p->info.l << "---->";
cout << G.vertices[p->adjvex].data.s << "(" << p->adjvex + 1 << ")";
p = p->nextarc;
}
cout << endl;
}
return OK;
}
bool visited[MVNum];
// 递归深度优先遍历算法
void DFS(ALGraph G, int v) {
if (v < 0 || v >= G.vexnum) {
cout << "无此顶点" << endl;
return;
}
cout << G.vertices[v].data.s << "(" << v + 1 << ") ";
visited[v] = true;
ArcNode* p = G.vertices[v].firstarc;
while (p)
{
if (!visited[p->adjvex]) {
DFS(G, p->adjvex);
}
p = p->nextarc;
}
}
// 使用递归深度优先遍历算法
Status useDFS(ALGraph G) {
for (int i = 0; i < MVNum; i++) visited[i] = false;
cout << "输出:值(序号)……" << endl;
cout << "对图进行深度优先递归遍历,输入开始顶点的序号:";
int choice;
cin >> choice;
choice -= 1;
if (choice > G.vexnum - 1 || choice < 0 || cin.fail()) return ERROR;
DFS(G, choice);
cout << endl;
return OK;
}
……具体看看绑定的资源
C++代码文件ALGraphUse.cpp
这个C++代码文件(ALGraphUse.cpp)实现了一个基于命令行的图形数据结构交互式应用。它包括以下功能:
- 创建无向图(UDG)
- 获取图中顶点的数据
- 获取图中顶点的邻接边
- 深度优先遍历图
- 广度优先遍历图
- 显示所有顶点及其邻接边
用户通过菜单选择操作,程序使用ALGraphAlgo.h
头文件中定义的数据结构和算法。程序在每个操作后暂停,等待用户确认(使用system("pause")
),并在完成或出错时清除屏幕重绘菜单。
#include "ALGraphAlgo.h"
void ShowMenu() {
cout << "========= 图的实现及应用 =========" << endl;
cout << "1. 采用邻接表表示法创建无向图G" << endl;
cout << "2. 获取顶点的值" << endl;
cout << "3. 获取顶点的邻接点" << endl;
cout << "4. 自选顶点,对图进行深度优先递归遍历" << endl;
cout << "5. 自选顶点,对图进行广度优先非递归遍历" << endl;
cout << "6. 整体输出邻接表" << endl;
cout << "0. 退出" << endl;
cout << "请输入你的选择:";
}
void ExitEnter() {
cout << "-------------------------------" << endl;
system("pause");
system("cls");
}
int main() {
ALGraph G;
int numF = 6; //菜单选项数量
int choice;
do {
ShowMenu();
cin >> choice;
while (choice < 0 || choice>numF || cin.fail())
{
system("cls");
cin.clear();
cin.ignore();
ShowMenu();
cin >> choice;
}
switch (choice) {
case 1: {
// 采用邻接表表示法创建无向图G
system("cls");
if (CreateUDG(G)) cout << "\n无向图创建成功!" << endl;
else cout << "\n无向图创建失败,请重新尝试" << endl;
ExitEnter();
break;
}
case 2: {
// 获取顶点的值
system("cls");
if (GetVexData(G)) cout << "\n获取顶点的值成功!" << endl;
else cout << "\n失败,请重新尝试" << endl;
ExitEnter();
break;
}
case 3: {
// 获取顶点的邻接点
system("cls");
if (GetVexArc(G)) cout << "\n获取顶点的邻接点成功!" << endl;
else cout << "\n失败,请重新尝试" << endl;
ExitEnter();
break;
}
case 4: {
// 自选顶点,对图进行深度优先递归遍历
system("cls");
if (useDFS(G)) cout << "\n对图进行深度优先递归遍历成功!" << endl;
else cout << "\n失败,请重新尝试" << endl;
ExitEnter();
break;
}
case 5: {
// 自选顶点,对图进行广度优先非递归遍历
system("cls");
if (useBFS(G)) cout << "\n对图进行广度优先非递归遍历成功!" << endl;
else cout << "\n失败,请重新尝试" << endl;
ExitEnter();
break;
}
case 6: {
// 整体输出邻接表
system("cls");
GetAllVexArc(G);
ExitEnter();
break;
}
case 0: {
cout << "-------------------------------" << endl;
cout << "感谢使用,再见!" << endl;
break;
}
default:
system("cls");
cout << "输入无效,请重新选择!" << endl;
break;
}
} while (choice != 0);
return 0;
}
结语
希望你能通过本篇博客,更好理解数据结构——图。
最后,使用愉快!