邻接表是图的另一种存储结构(使用链表的思想)。
该方式的基本思路:顶点表后指向邻接表,邻接表中依次为当前顶点的邻接点
与邻接矩阵类似,在构造邻接表之前,需要存储各个顶点的信息,在这里使用结构体存储。因此,在构造邻接表之前,需要先定义两个结构体:邻接表结构体、顶点结构体。【其中,都需要用到指向邻接表的指针!】
struct EdgeNode{ //邻接表
int ad; //记录邻接点的位置
EdgeNode *next; //指向邻接表的指针
};
struct VertxNode{ //顶点表
char vertx;
EdgeNode *firstEdge;//指向邻接表的指针
};
与邻接矩阵类似,在这里,继续使用C++面向对象的方法完成构建。
class AlGraph{
public:
AlGraph(char a[],int n,int e); //通过顶点数据、点数、边数建邻接表
~AlGraph(); //使用链表存储,非静态存储,需析构!
void dfs(int v);
void bfs(int v);
private:
VertxNode adjlist[MaxSize]; //结构数组存放各顶点
int vertxNum,edgeNum; //点数、边数
};
构造函数与单链表的头插法类似,但又不完全相同。如图,单链表中的first结点为一个结构体变量,其中包含next指针。
在实现单链表的头插法时,首先将插入元素的next指针与first指针指向同一位置,之后将头指针的next指针指向新插入的元素。而在邻接表构建中,顶点结构体就相当于单链表头插构造中的整个first结点,顶点结构体中的firstEdge指针就相当于单链表first结点的next指针!(如图所示)
邻接表的构造过程用以下代码实现:
AlGraph::AlGraph(char a[],int n,int e){
vertxNum=n,edgeNum=e;
int i,j,k;
//顶点结构初始化(抄入顶点数据并将头指全部置空)
for(i=0;i>i>>j; //输入顶点,i已存入顶点结构,j存入邻接点域。
s=new EdgeNode;s->ad=j;
//将j挂链到i上 (头插)
s->next=adjlist[i].firstEdge;
adjlist[i].firstEdge=s;
}
}
由于邻接表使用链表存储数据,为动态存储,不同于邻接矩阵的数组存储结构。因此,需要手动写析构函数!
析构过程的思路及代码如下:
AlGraph::~AlGraph(){
//使用链表存储邻接点,存储结构非静态,需循环删除指针
EdgeNode *p,*q; //工作指针p ,临时指针q(暂存被删除元素)
p=NULL,q=NULL;
for(int i=0;inext;
delete q; //删除临时指针指向的数据
q=p; //更新临时指针指向
}
}
}
与邻接矩阵相同,有两种方式对图进行遍历:DFS、BFS。其思路与邻接矩阵时实现的思路完全一样,所不同的仅仅是对链表的遍历过程。
void AlGraph::dfs(int v){
cout<ad;
if(!vis[i]) dfs(i);
p=p->next;
}
}
void AlGraph::bfs(int v){
//思路:用队列,将元素访问、标记、入队
int front,rear;
front=rear=-1;
int Q[MaxSize],j,t; //t存储出队元素,j存储邻接点位置
cout<ad;
if(!vis[j]){
cout<next;
}
}
}
如图,测试边为:(0 1)(0 3)(0 4)(1 2)(2 4)(3 2)(3 4)
#include
using namespace std;
const int MaxSize=10;
int vis[MaxSize]={0};
struct EdgeNode{ //邻接表
int ad; //记录邻接点位置
EdgeNode *next;
};
struct VertxNode{ //顶点表
char vertx;
EdgeNode *firstEdge;//顶点表指向邻接表,指针为邻接表类型
};
//思路:顶点表后指向邻接表,邻接表中依次为当前顶点的邻接点
class AlGraph{
public:
AlGraph(char a[],int n,int e); //通过顶点数据、点数、边数建邻接表
~AlGraph(); //使用链表存储,非静态存储,需析构!
void dfs(int v);
void bfs(int v);
private:
VertxNode adjlist[MaxSize]; //结构数组存放各顶点
int vertxNum,edgeNum; //点数、边数
};
AlGraph::AlGraph(char a[],int n,int e){
vertxNum=n,edgeNum=e;
int i,j,k;
//顶点结构初始化(抄入顶点数据并将头指全部置空)
for(i=0;i>i>>j; //输入顶点,i已存入顶点结构,j存入邻接点域。
s=new EdgeNode;s->ad=j;
//将j挂链到i上 (头插)
s->next=adjlist[i].firstEdge;
adjlist[i].firstEdge=s;
}
}
void AlGraph::dfs(int v){
cout<ad;
if(!vis[i]) dfs(i);
p=p->next;
}
}
void AlGraph::bfs(int v){
//思路:用队列,将元素访问、标记、入队
int front,rear;
front=rear=-1;
int Q[MaxSize],j,t; //t存储出队元素,j存储邻接点位置
cout<ad;
if(!vis[j]){
cout<next;
}
}
}
AlGraph::~AlGraph(){
//使用链表存储邻接点,存储结构非静态,需循环删除指针
EdgeNode *p,*q; //工作指针p ,临时指针q(暂存被删除元素)
p=NULL,q=NULL;
for(int i=0;inext;
delete q; //删除临时指针指向的数据
q=p; //更新临时指针指向
}
}
}
int main( )
{
char ch[ ] = {'A','B','C','D','E'};
int i;
AlGraph ALG(ch, 5, 7); //建立具有5个顶点6条边的有向图
for (i = 0; i < MaxSize; i++)
vis[i] = 0;
cout << "深度优先遍历序列是:";
ALG.dfs(0); //从顶点0出发进行深度优先遍历
cout<