一篇整理的笔记,较为全面。用邻接表表示图,实现图的深度遍历、广度优先遍历。
图-邻接表的优缺点:
- 邻接表适用于简单图(稀疏图)。
- 邻接表保存的都是必要的关系信息。
- 链表的结构,导致不适宜频繁查询遍历。
//
// main.cpp
// 图-邻接表
//
// Created by scnulpc on 2018/10/23.
// Copyright © 2018年 scnulpc. All rights reserved.
//
#include <iostream>
#include <queue>
#define Defaultvertices 30
using namespace std;
template <class T,class E>
struct Edge //边结点的定义
{
int dest; //边的另一顶点位置
E weight; //边上权值
Edge<T,E>* link;
Edge(int num,E cost):dest(num),weight(cost),link(NULL){}
bool operator !=(Edge<T,E> &R)const //判断边不等
{
return (dest!=R.dest)?true:false;
}
};
template <class T,class E>
struct Vertex //顶点的定义
{
T data; //顶点的名字
Edge<T,E> * adjacent;//边链表的头指针
Vertex(T name):data(name),adjacent(NULL){}
};
template <class T,class E>
class Graph
{
private:
int numVertices;
int numEdge;
int maxVertices;
Vertex<T, E> *NodeTable;
public:
int getVertexPosition(T vertex) //给出顶点vertex在图中的位置
{
for (int i=0; i<numVertices; i++)
{
if (NodeTable[i].data==vertex) return i;
}
return -1;
}
public:
Graph(int sz=Defaultvertices); //构造函数
~Graph(); //析构函数
T getValue(int i); //获取第i个顶点中的值
E getWeight(int v1,int v2); //获取边(v1,v2)的权值
int numberOfVetices(){return numVertices;} //获取顶点数量
Vertex<T, E>* getVertex(int i); //获取顶点
bool insertVertex(const T & vertex); //插入顶点
bool removeVertex(int v); //删除顶点
bool insertEdge(int v1,int v2,E weight); //插入边(v1,v2)
bool removeEdge(int v1,int v2); //删除边(v1,v2)
int getFirstNeighbor(int v); //获取v的第一个邻接点
int getNextNeighbor(int v,int w); //获取顶点v在w下的下一个邻接点
};
template <class T,class E>
Graph<T, E>::Graph(int sz)
{
maxVertices=sz;
numVertices=0;
numEdge=0;
NodeTable = new Vertex<T, E>[sz];
}
template <class T,class E>
Graph<T, E>::~Graph()
{
for (int i=0; i<numVertices; i++) //删除各边链表中的结点
{
Edge<T, E> *p = NodeTable[i].adjacent;
while (p!=NULL) { //不断删除第一个边结点
NodeTable[i].adjacent = p->link;
delete p;
p=NodeTable[i].adjacent;
}
}
delete [] NodeTable;
}
template <class T,class E>
T Graph<T,E>::getValue(int i)
{
return (i>-1&&i<numVertices)?NodeTable[i].data:0;
}
template <class T,class E>
E Graph<T,E>::getWeight(int v1, int v2)
{
if (v1>-1&&v1<numVertices&&v2>-1&&v2<numVertices)
{
Edge<T, E>* p = NodeTable[v1].adjacent;
while (p!=NULL) {
if (p->dest==v2) return p->weight;
}
}
return 0;
}
template <class T,class E>
Vertex<T, E>* Graph<T,E>::getVertex(int i)
{
if (i>-1&&i<numVertices)return NodeTable[i];
else return NULL;
}
template <class T,class E>
bool Graph<T,E>::insertVertex(const T &vertex)
{
if (numVertices==maxVertices) return false; //满
if (getVertexPosition(vertex)!=-1) return false;//已存在
NodeTable[numVertices++]=new Vertex<T, E>(vertex);
return true;
}
template <class T,class E>
bool Graph<T,E>::removeVertex(int v)
{
if (v<0||v>=numVertices||numVertices==1) return false;//表空或顶点号超出范围
Edge<T, E> *p,*s,*t;
int k;
while (NodeTable[v].adjacent!=NULL) //删除第v个边链表中的所有结点
{
p=NodeTable[v].adjacent;
k=p->dest; //找到邻接结点k
t=NULL;
s=NodeTable[k].adjacent;
while (s!=NULL) { //找对称存放的边结点
if (s->dest==v) break;
t=s;
s=s->link;
}
if (t==NULL) { //删除对称存放的边结点
NodeTable[k].adjacent = s->link;
//numEdge--;
delete s;
}
else
{
t->link = s->link;
//numEdge--;
delete s;
}
NodeTable[v].adjacent = p->link;
delete p;
numEdge--;
}
numVertices--;
NodeTable[v]=NodeTable[numVertices]; //替换
p=NodeTable[numVertices].adjacent;
while (p!=NULL) {
t = NodeTable[p->dest].adjacent;
while (t!=NULL)
if (t->dest==numVertices) {t->dest=v;break;}
else t=t->link;
p=p->link;
}
return true;
}
template <class T,class E>
bool Graph<T,E>::insertEdge(int v1, int v2, E weight)
{
if (v1>=0&&v1<numVertices&&v2>=0&&v2<numVertices) {
Edge<T, E>* p;
p=NodeTable[v1].adjacent;
while (p!=NULL) {
if (p->dest==v2) return false; //边已存在,不插
p=p->link;
}
p=NodeTable[v1].adjacent;
Edge<T, E> *target1 = new Edge<T, E>(v2,weight);
target1->link=p; //插入边(v1,v2,weight)
NodeTable[v1].adjacent=target1;
p=NodeTable[v2].adjacent;
Edge<T, E> *target2 = new Edge<T, E>(v1,weight);
target2->link=p; //插入边(v2,v1,weight)
NodeTable[v2].adjacent=target2;
numEdge++;
return true;
}
return false;
}
template <class T,class E>
bool Graph<T,E>::removeEdge(int v1, int v2)
{
if (v1>=0&&v1<numVertices&&v2>=0&&v2<numVertices)
{
Edge<T, E> *pre=NULL,*p=NULL;
p=NodeTable[v1].adjacent;
while (p!=NULL) { //删除边(v1,v2)
if (p->dest==v2) {
if (pre==NULL) {
NodeTable[v1].adjacent=p->link;
delete p;
}
else
{
pre->link=p->link;
delete p;
}
break;
}
else {pre = p; p=p->link;}
}
p=NodeTable[v2].adjacent;
while (p!=NULL) { //删除边(v2,v1)
if (p->dest==v1) {
if (pre==NULL) {
NodeTable[v2].adjacent=p->link;
delete p;
}
else
{
pre->link=p->link;
delete p;
}
break;
}
else { pre = p; p=p->link;}
}
numEdge--; //边数减一
return true;
}
else return false;
}
template <class T,class E>
int Graph<T,E>::getFirstNeighbor(int v)
{
if (v>-1&&v<numVertices) {
Edge<T, E> *p = NodeTable[v].adjacent;
if (p!=NULL) return p->dest;
else return -1;
}
return -1;
}
template <class T,class E>
int Graph<T,E>::getNextNeighbor(int v, int w)
{
if (v>-1&&v<numVertices&&w>-1&&w<numVertices) {
Edge<T, E>* p = NodeTable[v].adjacent;
while (p!=NULL) {
if (p->dest==w)break;
p=p->link;
}
if (p!=NULL&&p->dest==w)return p->dest;
else return -1;
}
else return -1;
}
//图的深度遍历
template <class T,class E>
void DFS(Graph<T,E> *G,T vertex)
{
int n = G->numberOfVetices();
bool * visited = new bool[n];
for (int i=0; i<n; i++)visited[i]=false;
int index = G->getVertexPosition(vertex);
DFS(G, index, visited);
delete []visited;
}
template <class T,class E>
void DFS(Graph<T,E> *G,int i,bool visted[]) //深度遍历,核心操作
{
cout<<G->getValue(i)<<" ";
visted[i]=true;
Edge<T, E>* p = G->getVertex(i).adjacent;
while (p!=NULL) {
DFS(G, p->dest, visted);
p=p->link;
}
}
//图的广度遍历
template <class T,class E>
void BFS(Graph<T,E> *G,const T vertex)
{
int index = G->getVertexPosition(vertex);
int n = G->numberOfVetices();
if (index<0||index>=n) return;
bool * visited = new bool(n);
for (int i=0; i<n; i++) visited[i]=false;
queue<int> q;
q.push(index);
while (!q.empty()) {
int v = q.front();q.pop();
cout<<G->getValue(v)<<" ";
visited[v]=true;
int w = G->getFirstNeighbor(v);
while (w!=-1) {
if (visited[w]==false) {q.push(w);visited[w]=true;}
w = G->getNextNeighbor(v, w);
}
}
}