图的邻接表表示可以减少存储空间,但是同时增加了访问时间。下面是邻接矩阵和邻接表的适用情况:
邻接矩阵:1)经常检测边的存在;
2)经常做边的插入/删除操作;
3)图规模相对固定
4)稠密图
邻接表:1)经常计算顶点度数;
2)顶点数目不确定;
3)经常做遍历;
4)稀疏图;
对于邻接表的存储,我没有想到什么比较好的办法,就是用vector<list<Node>> V来做的存储,由于存储的不是地址,因此每次查找一个Node都需要在V中进行遍历。在网上找的代码中,有的是用int来表示节点,那样就能用V[i]来直接寻找节点了,但是如果几点表征的不是int而是字符串等就需要改动很大的代码,或者用map来得到原来的数字,但是插入和删除又会有新的问题。因此没有考虑这种算法。
我就只是用了简单的算法:将每个节点放入V中的首个元素位置,然后将与当前节点由连接的节点放入其后面,如过用边插入,则Node中是有两个节点和一条边的。代码如下:
//GraphList.h
#ifndef __GraphList__
#define __GraphList__
#include<vector>
#include<list>
using namespace std;
struct Node
{
char begin;
char end;
int weight;
bool isVisited;
Node(char b,char e,int w=0)
{begin=b;end=e;weight=w;isVisited=false;}
};
class GraphList
{
vector<list<Node>> V;
void BFS(Node &r);
void DFS(Node &r);
public:
GraphList(){}
void insertVertex(Node &r);
void insertEdge(Node &r);
void removeVertex(Node &r);
void removeEdge(Node &r);
void bfs(Node &r);
void dfs(Node &r);
};
#endif
#include"GraphList.h"
#include<iostream>
#include<queue>
using namespace std;
void GraphList::BFS(Node &r)
{
queue<char> q;
q.push(r.begin);
while(!q.empty())
{
int k=-1;
char curr=q.front();
for(int i=0;i<V.size();i++)
{
if(V[i].front().begin==curr)
{
k=i;
break;
}
}
auto iter=V[k].begin();
if(iter->isVisited==false)
{
cout<<iter->begin<<endl;
iter->isVisited=true;
}
for(;iter!=V[k].end();++iter)
{
for(int i=0;i<V.size();i++)//每次都需要遍历,这里可以用map来实现
//网上有用int来表示节点的,那样就能够直接用V[iter->end]来索引,但是删除不方便
if(V[i].front().begin==iter->end && V[i].front().isVisited==false)
q.push(iter->end);
}
q.pop();
}
}
void GraphList::DFS(Node &r)
{
int k=-1;
for(int i=0;i<V.size();i++)
if(V[i].front().begin==r.begin)
{
if(V[i].front().isVisited==true)
return;
k=i;
}
V[k].front().isVisited=true;
cout<<V[k].front().begin<<endl;
for(auto iter=V[k].begin();iter!=V[k].end();++iter)
{
for(int i=0;i<V.size();i++)
if(V[i].front().begin==iter->end)
{
DFS(Node(iter->end,iter->end));
}
}
}
void GraphList::insertVertex(Node &r)
{
V.push_back(list<Node>(1,r));
}
void GraphList::insertEdge(Node &r)
{
int first=-1,second=-1;
for(int i=0;i<V.size();i++)
{
if(V[i].front().begin==r.begin)
first=i;
if(V[i].front().begin==r.end)
second=i;
}
if(first==-1)
V.push_back(list<Node>(1,r));
else
V[first].push_back(r);
if(second==-1)
V.push_back(list<Node>(1,Node(r.end,r.begin,r.weight)));
else
V[second].push_back(Node(r.end,r.begin,r.weight));
}
void GraphList::removeVertex(Node &r)
{
for(int i=0;i<V.size();i++)
{
if(V[i].front().begin==r.begin)
V.erase(V.begin()+i--);
else
{
auto iter=V[i].begin();
for(;iter!=V[i].end();)
if(iter->end==r.begin)
{
V[i].erase(iter);
if(V[i].empty())
{
V.erase(V.begin()+i);
i--;
}
break;
}
else
++iter;
}
}
}
void GraphList::removeEdge(Node &r)
{
for(int i=0;i<V.size();i++)
{
if(V[i].front().begin==r.begin)
{
auto iter=V[i].begin();
for(;iter!=V[i].end();)
if(iter->end==r.end)
{
iter=V[i].erase(iter);
break;
}
else
++iter;
}
if(V[i].front().begin==r.end)
{
auto iter=V[i].begin();
for(;iter!=V[i].end();)
if(iter->end==r.begin)
{
V[i].erase(iter);
break;
}
else
++iter;
}
}
}
void GraphList::bfs(Node &r)
{
for(int i=0;i<V.size();i++)
V[i].front().isVisited=false;
BFS(r);
for(int i=0;i<V.size();i++)
if(V[i].front().isVisited==false)
BFS(V[i].front());
}
void GraphList::dfs(Node &r)
{
for(int i=0;i<V.size();i++)
V[i].front().isVisited=false;
DFS(r);
for(int i=0;i<V.size();i++)
if(V[i].front().isVisited==false)
DFS(V[i].front());
}
这个是main的测试函数:
#include<iostream>
#include<vector>
#include<queue>
#include<list>
#include"GraphList.h"
using namespace std;
#define DEBUG
int main()
{
#ifdef DEBUG
freopen("input.txt","r",stdin);
#endif
GraphList gl;
char vertex,from,to;
int e;
//测试边和顶点的插入
cout<<"输入边"<<endl;
while(cin>>from>>to>>e)
{
cout<<"输入边"<<endl;
gl.insertEdge(Node(from,to,e));
}
//测试深度优先搜索
gl.dfs(Node('B','B'));
//测试广度优先搜索
gl.bfs(Node('B','B'));
//测试边和顶点的删除
gl.removeEdge(Node('A','B'));
gl.removeVertex(Node('C','C'));
system("pause");
return 0;
}