图的操作
实验目的
- 掌握图的基本概念,描述方法;遍历方法。
- 掌握图的最短路径算法。
实验内容:
1.图的存储结构使用邻接矩阵。
2.创建图操作类,支持BFS遍历、DFS遍历、求单源最短路径、判断是否存在回路等四个功能,这些功能封装成图操作类的成员函数。
3. 输入图的节点数n(不超过10个)、边数m,节点分别用0到n-1表示。
4. 采用“起始节点,终止节点,权值”输入图的m条边,创建图。
5. 输出从节点0开始的BFS遍历、DFS遍历节点遍历顺序。
6. 输出从节点0到其余节点最短路径的长度,如果没有路经,输出0。
基本思路:
1.使用了链式队列,图的实现代码
2.在graph类中设置了BFS,DFS,Dijkstra,hascircle,4个基础操作函数,并利用helpBFS,helpDFS,minVertex,helpfindcircle,4个辅助操作函数
3.在BFS和DFS中循环调用相应help函数对未遍历的节点遍历
4.在hascircle函数中循环调用helpfindcircle对未遍历的节点dfs遍历,在逐个的遍历过程中,若发现除父节点外已经遍历过的结点,则判断有环
#include <iostream>
using namespace std;
template <typename E>
class Link {
private:
static Link<E>* freelist; // Reference to freelist head
public: E element; // Value for this node
Link *next;
Link(const E& elemval, Link* nextval =NULL) {
element = elemval; next = nextval; }
Link(Link* nextval =NULL) { next = nextval; }
void* operator new(size_t) {
if (freelist == NULL)
return ::new Link;
Link<E>* temp = freelist;
freelist = freelist->next;
return temp;
}
void operator delete(void* ptr) {
((Link<E>*)ptr)->next = freelist;
freelist = (Link<E>*)ptr; }
};
template <typename E>
Link<E>* Link<E>::freelist = NULL;
template <typename E>
class Queue {
private: Link<E>* front; // Pointer to front queue node
Link<E>* rear; // Pointer to rear queue node
int size; // Number of elements in queue
public:
Queue(int sz =10)
{ front = rear = new Link<E>();
size = 0; }
~Queue() { clear();
delete front; }
void clear() {
while(front->next != NULL) {
rear = front;
delete rear; }
rear = front;
size = 0; }
void enqueue(const E& it) {
rear->next = new Link<E>(it, NULL);
rear = rear->next;
size++; }
E dequeue() {
//Assert(size != 0, "Queue is empty");
E it = front->next->element;
Link<E>* ltemp = front->next;
front->next = ltemp->next;
if (rear == ltemp)
rear = front; // Dequeue last element
delete ltemp; // Delete link
size --;
return it; // Return element value
}
const E& frontValue() const { // Get front element
//Assert(size != 0, "Queue is empty");
return front->next->element; }
virtual int length() const {
return size; }
};
class Graph{
private:
int numVertex, numEdge; // Store number of vertices, edges
int **matrix;
int *mark;
void helpDFS(int v) {
PreVisit(v);
setMark(v, 1);
for (int w=first(v); w<numVertex; w = next(v,w))
if (getMark(w) == 0)
helpDFS(w);
}
void helpBFS(int start, Queue<int>* Q) {
int v, w;
Q->enqueue(start);
setMark(start, 1);
while (Q->length() != 0) {
v = Q->dequeue();
PreVisit(v);
for (w=first(v); w<numVertex; w = next(v,w))
if (getMark(w) == 0) {
setMark(w, 1);
Q->enqueue(w); }
}
}
int helpfindcircle(int v,int baba)
{ setMark(v,1);
for (int w=first(v); w<n(); w = next(v,w))
{ if(getMark(w)==1&&w!=baba)
return 1;
else if(getMark(w)==0)
if(helpfindcircle(w,v))
return 1;
}
return 0;
}
public:
Graph(int numVert){
Init(numVert); }
~Graph() {
delete [] mark;
for (int i=0; i<numVertex; i++)
delete [] matrix[i];
delete [] matrix; }
void Init(int n) {
int i;
numVertex = n;
numEdge = 0;
mark = new int[n]; // Initialize mark array
for (i=0; i<numVertex; i++)
mark[i] = 0;
matrix = (int**) new int*[numVertex]; // Make matrix
for (i=0; i<numVertex; i++)
matrix[i] = new int[numVertex];
for (i=0; i< numVertex; i++) // Initialize to 0 weights
for (int j=0; j<numVertex; j++)
matrix[i][j] = 0;
}
int n() {
return numVertex; }
int e() {
return numEdge; }
int first(int v) {
for (int i=0; i<numVertex; i++)
if (matrix[v][i] != 0)
return i;
return numVertex; // Return n if none
}
// Return v’s next neighbor after w
int next(int v, int w) {
for(int i=w+1; i<numVertex; i++)
if (matrix[v][i] != 0) return i;
return numVertex; // Return n if none
}
void setEdge(int v1, int v2, int wt) {
// Assert(wt>0, "Illegal weight value");
if (matrix[v1][v2] == 0)
numEdge++;
matrix[v1][v2] = wt; }
void delEdge(int v1, int v2) {
if (matrix[v1][v2] != 0)
numEdge--;
matrix[v1][v2] = 0; }
bool isEdge(int i, int j) // Is (i, j) an edge?
{ return matrix[i][j] != 0; }
int weight(int v1, int v2) {
return matrix[v1][v2]; }
int getMark(int v) {
return mark[v]; }
void setMark(int v, int val) {
mark[v] = val; }
void PreVisit(int v){
cout<<v<<' ';
}
void DFS(){
int i;
for(i=0;i<numVertex;i++)
setMark(i,0);
for(int i=0;i<numVertex;i++)
if(getMark(i)==0)
helpDFS(i);
cout<<endl;
}
void BFS(){
Queue<int> q;
int i;
for(i=0;i<numVertex;i++)
setMark(i,0);
for(i=0;i<numVertex;i++)
if(getMark(i)==0)
helpBFS(i,&q);
cout<<endl;
}
int minVertex(int* D) {
int i, v =-1;
for (i=0; i<numVertex; i++)
if (getMark(i) == 0) {
v = i;
break; }
for (i++; i<numVertex; i++)
if ((getMark(i) == 0) && (D[i] < D[v]))
v = i;
return v;
}
void Dijkstra(int* D, int s) {
int i, v, w;
D[s]=0;
for(i=0;i<n();i++)
setMark(i,0);
for (i=0; i<numVertex; i++) {
v = minVertex(D);
if (D[v] == 100)
return; // Unreachable vertices
setMark(v, 1);
for (w=first(v);w<n(); w = next(v,w))
if (D[w] > (D[v] + weight(v, w)))
D[w] = D[v] + weight(v, w);
}
}
bool hascircle(int v)
{
int i;
for(i=0;i<numVertex;i++)
setMark(i,0);
for(i=0;i<n();i++)
if(getMark(i)==0)
{ if(helpfindcircle(i,-1)==1)
return true;
}
return false;
}
};
int main()
{
int m,n,i,v1,v2,w;
cin>>n>>m;
Graph G(n);
int D[n];
for(i=0;i<n;i++)
D[i]=100;
for(i=0;i<m;i++)
{cin>>v1>>v2>>w;
G.setEdge(v1,v2,w);
G.setEdge(v2,v1,w);
}
//BFS遍历
G.BFS();
//DFS遍历
G.DFS();
//找最短路径
G.Dijkstra(D,0);
for(i=1;i<G.n();i++)
if(D[i]==100)
cout<<0<<' '<<i<<' '<<"0"<<endl;
else
cout<<0<<' '<<i<<' '<<D[i]<<endl;
//有无环
if(G.hascircle(0)==true)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}