本文是笔者2020年秋哈工大数据结构作业4自己的代码,由于本人能力有限,可能存在一些错误,欢迎指出。
本次作业是有向图和无向图二选一,笔者选的是有向图。
完整源代码链接:https://download.youkuaiyun.com/download/qq_45853731/20213288?spm=1001.2014.3001.5503
本文仅供参考,严禁抄袭!
文章目录
作业题目:图的存储结构的建立与搜索
图的搜索(遍历)算法是图型结构相关算法的基础,本作业要求编写程序演示有向图典型存储结构的建立和搜索(遍历)过程。
存储结构
typedef struct {
vector<char>vertex;
int Matrix[Maxlength][Maxlength];
int n, e;
}MTGraph;
typedef struct node{
int adjvex;
int cost;
struct node* next;
}EdgeNode;
typedef struct {
char vertex;
EdgeNode* firstedge;
}VertexNode;
typedef struct {
VertexNode verlist[Maxlength];
int n, e;
}AdjGraph;
typedef struct {
char vertex;
char parent;
}GeneTree;
//下列vector存储搜索树
vector<GeneTree>DFSLinkTree;
vector<GeneTree>DFSLinkRecTree;
vector<GeneTree>DFSMatrixRecTree;
vector<GeneTree>DFSMatrixTree;
vector<GeneTree>BFSLinkTree;
vector<GeneTree>BFSMatrixTree;
bool visit[Maxlength];
int dfsorder[Maxlength];
int countdfs = 1;
分别实现有向图的邻接矩阵和邻接表存储结构的建立算法,分析和比较各建立算法的时间复杂度以及存储结构的空间占用情况
void ReadinMatrix(MTGraph &graph)//将图读入邻接矩阵
{
ifstream in("map.txt");
string read1,read2;//读入的第一行,存储的是顶点信息;第二行,存储的是边信息
int i = 0,j = 0, weight, k;
getline(in, read1);
while (i < read1.length())
{
graph.vertex.push_back(read1[i]);
graph.n++;
i += 2;
}
getline(in, read2);
in.close();
while (j < read2.length())
{
weight = 0;
k = j + 4;
while (read2[k] <= '9' && read2[k] >= '0')
{
weight += int(read2[k] - '0');
weight *= 10;
k++;
}
weight /= 10;
graph.Matrix[read2[j] - 'A'][read2[j + 2] - 'A'] = weight;
graph.e++;
j = k - 1;
j += 2;
}
}
void ReadinLink(AdjGraph& adjgraph)//读入邻接表
{
ifstream in("map.txt");
string read1, read2;//读入的第一行,存储的是顶点信息;第二行,存储的是边信息
int i = 0, j = 0, weight, k;
getline(in, read1);
while (i < read1.length())
{
adjgraph.verlist[read1[i]-'A'].vertex=read1[i];
adjgraph.verlist[read1[i] - 'A'].firstedge = NULL;
adjgraph.n++;
i += 2;
}
getline(in, read2);
in.close();
while (j < read2.length())
{
weight = 0;
k = j + 4;
while (read2[k] <= '9' && read2[k] >= '0')
{
weight += int(read2[k] - '0');
weight *= 10;
k++;
}
weight /= 10;
EdgeNode* p = new EdgeNode, * q = adjgraph.verlist[read2[j] - 'A'].firstedge;
if (q == NULL)
{
p->adjvex = int(read2[j + 2] - 'A');
p->cost = weight;
p->next = NULL;
adjgraph.verlist[read2[j] - 'A'].firstedge = p;
}
else
{
while (q->next != NULL)
q = q->next;
p->adjvex = int(read2[j + 2] - 'A');
p->cost = weight;
p->next = NULL;
q->next = p;
}
adjgraph.e++;
j = k - 1;
j += 2;
}
}
实现有向图的邻接矩阵和邻接表两种存储结构的相互转换算法
void MatrixToLink(MTGraph matrix,AdjGraph &link)//邻接矩阵转邻接表
{
for (int i = 0; i < matrix.n; i++)
{
link.verlist[i].vertex = matrix.vertex[i];
link.verlist[i].firstedge = NULL;
link.n++;
for (int j = 0; j < matrix.n; j++)
{
if (matrix.Matrix[i][j] != 0)
{
EdgeNode* p = new EdgeNode, * q = link.verlist[i].firstedge;
if (q == NULL)
{
p->adjvex = j;
p->cost = matrix.Matrix[i][j];
p->next = NULL;
link.verlist[i].firstedge = p;
}
else
{
while (q->next != NULL)
q = q->next;
p->adjvex = j;
p->cost = matrix.Matrix[i][j];
p->next = NULL;
q->next = p;
}
link.e++;
}
}
}
}
void LinkToMatrix(MTGraph& matrix, AdjGraph link)//邻接表转邻接矩阵
{
EdgeNode* p = NULL;
for (int i = 0; i < link.n; i++)
{
matrix.vertex.push_back(link.verlist[i].vertex);
matrix.n++;
p = link.verlist[i].firstedge;
while (p != NULL)
{
matrix.Matrix[i][p->adjvex] = p->cost;
matrix.e++;
p = p->next;
}
}
}
在上述两种存储结构上,分别实现有向图的深度优先搜索(递归和非递归) 和广度优先搜索算法。并以适当的方式存储和显示相应的搜索结果(深度优先或广度优先生成森林(或生成树)、深度优先或广度优先序列和编号)
void DFSMainLinkRec(AdjGraph link, int i)//递归对邻接表进行深度优先搜索
{
EdgeNode* p = NULL;
GeneTree node;
DFSLinkRecTree.back().vertex = link.verlist[i].vertex;
cout << countdfs<<":"<<link.verlist[i].vertex<<" ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
p = link.verlist[i].firstedge;
while (p)
{
if (!visit[p->adjvex])
{
node.parent = link.verlist[i].vertex;
DFSLinkRecTree.push_back(node);
DFSMainLinkRec(link, p->adjvex);
}
p = p->next;
}
}
void DFSLinkRec(AdjGraph link)//递归深度优先搜索邻接表主程序
{
GeneTree node;
for (int i = 0; i < link.n; i++)
{
visit[i] = false;
}
for (int i= 0; i < link.n; i++)
{
if (!visit[i])
{
node.parent = '#';
if(!DFSLinkRecTree.empty())
DFSLinkRecTree.pop_back();
DFSLinkRecTree.push_back(node);
DFSMainLinkRec(link, i);
}
}
cout << endl;
cout << "深搜树或森林为:"<<endl;
for (auto x : DFSLinkRecTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
void DFSMainLink(AdjGraph link, int i)//非递归深度优先搜索邻接表
{
EdgeNode* p = link.verlist[i].firstedge;
char ch;
stack<VertexNode>STACK;
GeneTree node;
DFSLinkTree.back().vertex = link.verlist[i].vertex;
ch = link.verlist[i].vertex;
cout << countdfs << ":" << link.verlist[i].vertex<<" ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
STACK.push(link.verlist[i]);
while (countdfs<=link.n)
{
while (p)
{
if (!visit[p->adjvex])
{
node.parent = ch;
node.vertex = link.verlist[p->adjvex].vertex;
DFSLinkTree.push_back(node);
cout << countdfs << ":" << link.verlist[p->adjvex].vertex<<" ";
visit[p->adjvex] = true;
dfsorder[p->adjvex] = countdfs;
countdfs++;
STACK.push(link.verlist[p->adjvex]);
}
else
{
p = p->next;
continue;
}
ch = link.verlist[p->adjvex].vertex;
p = link.verlist[p->adjvex].firstedge;
}
STACK.pop();
if (STACK.empty())
break;
else
{
p = STACK.top().firstedge;
ch = STACK.top().vertex;
}
}
}
void DFSLink(AdjGraph link)//非递归深度优先搜索邻接表主程序
{
GeneTree node;
for (int i = 0; i < link.n; i++)
{
visit[i] = false;
}
countdfs = 1;
for (int i = 0; i < link.n; i++)
{
if (!visit[i])
{
node.parent = '#';
if (!DFSLinkTree.empty())
DFSLinkTree.pop_back();
DFSLinkTree.push_back(node);
DFSMainLink(link, i);
}
}
cout << endl;
cout << "深搜树或森林为:" << endl;
for (auto x : DFSLinkTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
void DFSMainMatrix(MTGraph matrix, int i)//非递归深度优先搜索邻接矩阵
{
stack<char>STACK;
int j = 0, k=0;
char ch;
GeneTree node;
DFSMatrixTree.back().vertex = matrix.vertex[i];
cout << countdfs << ":" << matrix.vertex[i]<<" ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
STACK.push(matrix.vertex[i]);
j = i;
while (countdfs <= matrix.n)
{
while(k<matrix.n)
{
if (matrix.Matrix[j][k]!=0&&!visit[k])
{
node.parent = matrix.vertex[j];
node.vertex = matrix.vertex[k];
DFSMatrixTree.push_back(node);
cout << countdfs << ":" << matrix.vertex[k] << " ";
visit[k] = true;
dfsorder[k] = countdfs;
countdfs++;
STACK.push(matrix.vertex[k]);
j = k;
k = 0;
continue;
}
k++;
}
STACK.pop();
if (STACK.empty())
break;
else
{
ch = STACK.top();
j = int(ch - 'A');
k = 0;
}
}
}
void DFSMatrix(MTGraph matrix)//非递归深度优先搜索邻接矩阵主程序
{
GeneTree node;
for (int i = 0; i < matrix.n; i++)
{
visit[i] = false;
}
countdfs = 1;
for (int i = 0; i < matrix.n; i++)
{
if (!visit[i])
{
node.parent = '#';
if (!DFSMatrixTree.empty())
DFSMatrixTree.pop_back();
DFSMatrixTree.push_back(node);
DFSMainMatrix(matrix, i);
}
}
cout << endl;
cout << "深搜树或森林为:" << endl;
for (auto x : DFSMatrixTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
void DFSMainRec(MTGraph matrix, int i)//递归深度优先搜索邻接矩阵
{
GeneTree node;
DFSMatrixRecTree.back().vertex = matrix.vertex[i];
cout << countdfs << ":" << matrix.vertex[i] << " ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
for (int j = 0; j < matrix.n; j++)
{
if (matrix.Matrix[i][j] != 0 && visit[j] == false)
{
node.parent = matrix.vertex[i];
DFSMatrixRecTree.push_back(node);
DFSMainRec(matrix, j);
}
}
}
void DFSMatrixRec(MTGraph matrix)//递归深度优先搜索邻接矩阵主程序
{
countdfs = 1;
GeneTree node;
for (int i = 0; i < matrix.n; i++)
{
visit[i] = false;
}
countdfs = 1;
for (int i = 0; i < matrix.n; i++)
{
if (!visit[i])
{
node.parent = '#';
if (!DFSMatrixRecTree.empty())
DFSMatrixRecTree.pop_back();
DFSMatrixRecTree.push_back(node);
DFSMainRec(matrix, i);
}
}
cout << endl;
cout << "深搜树或森林为:" << endl;
for (auto x : DFSMatrixRecTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
void BFSMainLink(AdjGraph link, int i)//广度优先搜索邻接表
{
GeneTree node;
EdgeNode* p = link.verlist[i].firstedge;
VertexNode v;
queue<VertexNode>QUEUE;
cout << countdfs << ":" << link.verlist[i].vertex<<" ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
QUEUE.push(link.verlist[i]);
while (!QUEUE.empty())
{
v = QUEUE.front();
node.parent = v.vertex;
p = v.firstedge;
QUEUE.pop();
while (p)
{
if (!visit[p->adjvex])
{
cout << countdfs << ":" << link.verlist[p->adjvex].vertex<<" ";
visit[p->adjvex] = true;
dfsorder[p->adjvex] = countdfs;
countdfs++;
node.vertex = link.verlist[p->adjvex].vertex;
BFSLinkTree.push_back(node);
QUEUE.push(link.verlist[p->adjvex]);
}
p = p->next;
}
}
}
void BFSLink(AdjGraph link)//广度优先搜索邻接表主程序
{
GeneTree node;
for (int i = 0; i < link.n; i++)
{
visit[i] = false;
}
countdfs = 1;
for (int i = 0; i < link.n; i++)
{
if (!visit[i])
{
node.parent = '#';
node.vertex = link.verlist[i].vertex;
BFSLinkTree.push_back(node);
BFSMainLink(link, i);
}
}
cout << endl;
cout << "广搜树或森林为:" << endl;
for (auto x : BFSLinkTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
void BFSMainMatrix(MTGraph matrix, int i)//广度优先搜索邻接矩阵
{
queue<char>QUEUE;
GeneTree node;
char ch;
int j=0;
cout << countdfs << ":" << matrix.vertex[i]<<" ";
visit[i] = true;
dfsorder[i] = countdfs;
countdfs++;
QUEUE.push(matrix.vertex[i]);
while (!QUEUE.empty())
{
ch = QUEUE.front();
node.parent = ch;
j = 0;
while (j < matrix.n && matrix.Matrix[ch - 'A'][j] == 0)
j++;
QUEUE.pop();
while (j<matrix.n)
{
if (matrix.Matrix[ch-'A'][j]!=0&&!visit[j])
{
cout << countdfs << ":" << matrix.vertex[j]<<" ";
visit[j] = true;
dfsorder[j] = countdfs;
countdfs++;
node.vertex = matrix.vertex[j];
BFSMatrixTree.push_back(node);
QUEUE.push(matrix.vertex[j]);
}
j++;
}
}
}
void BFSMatrix(MTGraph matrix)//广度优先搜索邻接矩阵主程序
{
GeneTree node;
for (int i = 0; i < matrix.n; i++)
{
visit[i] = false;
}
countdfs = 1;
for (int i = 0; i < matrix.n; i++)
{
if (!visit[i])
{
node.parent = '#';
node.vertex = matrix.vertex[i];
BFSMatrixTree.push_back(node);
BFSMainMatrix(matrix, i);
}
}
cout << endl;
cout << "广搜树或森林为:" << endl;
for (auto x : BFSMatrixTree)
cout << "节点为" << x.vertex << "," << "它的父节点为:" << x.parent << endl;
cout << endl;
}
复杂度分析
一、对邻接表进行深度优先搜索和广度优先搜索的复杂度分析:
对邻接表进行深度优先搜索(广度优先搜索)的时间复杂度为O(n+e),n为顶点数,e为边数,这是因为,算法对每个顶点都访问一次,这部分的开销为O(n),而图的遍历过程是对每个顶点通过边查找邻接顶点的过程,这一过程开销为O(e),故总的时间复杂度为O(n+e);
而空间复杂度为O(n),这是因为最坏的情况下需要将所有的顶点进入栈(队列).
二、对邻接矩阵进行深度优先搜索和广度优先搜索的复杂度分析:
对邻接矩阵进行深度优先搜索(广度优先搜索)的时间复杂度为O(n^ 2),这是因为,在搜索过程中需要对邻接矩阵中的所有点进行判断,而邻接矩阵中一共有n^2个点;
而空间复杂度为O(n),这是因为最坏的情况下需要将所有的顶点进入栈(队列).