刚拿到图这一块时,也是无从下手,因为它涉及到邻接点,和弧,还有种类,点数,边数,等等情况,但是如果你把前面的数据关系理清楚之后,问题就一切迎刃而解了:
1. 首先图中因为有点是否遍历到了,是否还未遍历到,而且其中每个点还有数据,并且每个点必须指出邻接关系,对于点的数据类型我定义为:
struct SVertexNode //节点信息
{
bool bIsVisited;
string data;
vector<int> vecLoc; //弧的令一个节点的存储
SVertexNode():bIsVisited(false)
{}
};
其中vector容器用来存储邻接点信息的。
2. 对于弧,需要知道弧的两个端点,这样一个弧就得知了。并且对于一个图,其实就是存储一些点的信息,点之间是否相连等信息。
typedef struct SEdge //边界信息
{
int iInitialNode;
int iTerminalNode;
}Edge;
int iVertexNum; //顶点数目
int iEdgeNum; //边数目
vector<SVertexNode> vecVertex; //存储顶点的容器
3.有了这些其他的一些函数方法什么的,都很容易写出来了。
深度优先搜索我自己写的时候学习体会: 深度优先遍历是纵向进行的,
例如对图
从0开始遍历的时候,如果先遍历的是3,则会沿着3一直向它的深层进行遍历。然后再会是另一个邻接的情况。所以遍历顺序为顺序为 0 -> 3 -> 1 -> 2 (v1->v4->v2->v3)
在遍历时,1)从节点数的开始(即0)来进行(可以自己写为想要的那个点开始)
2) 遍历开始后因为前面的节点结构体中我们已经将bIsVisited 设为false, 所以在这里我们没有重新写(应该写上的)
3)对于遍历的点我们检测其邻接点,并对邻接点进行递归遍历,判断依据看看是否已经遍历过了,通过bIsVisited来进行判定
实现:
/*
* brief depth first search
*/
void depthFirstSearch()
{
cout << "depthFirstSearch: " << endl;
for(int i = 0; i < iVertexNum; i++)
{
if(!vecVertex.at(i).bIsVisited)
{
depthFirstSearch(i);
}
}
}
void depthFirstSearch(int v)
{
int iAdjacent = 0;
SVertexNode node = vecVertex.at(v);
vecVertex.at(v).bIsVisited = true;
cout << node.data << endl;
//thus we can search the node
for(int i = 0; i < node.vecLoc.size(); i++)
{
iAdjacent = node.vecLoc.at(i);
if(!(vecVertex.at(iAdjacent).bIsVisited))
depthFirstSearch(iAdjacent);
}
}
4. 广度优先遍历:即横向进行遍历的。
同样对于上图:
这时如果同样从0开始然后到3,因为是横向进行的,即先遍历同一级上的点,深度的属于下一级,这时的遍历顺序为0->3->2->1(v1->v4->v3->v2)
遍历过程参考《数据结构》严蔚敏
1)最重要解决好横向遍历的问题,如果递归时,总会是向下进行的,一直是第一个遍历了。
2)利用一个队列,先入后出,首先将所有的标志写为false, 从头进行遍历,之后对第一个进行(即0);
3)将这个进行检测的是否遍历过,若没有,则输出其数据,并将这个节点列数队列中(很经典啊)
4) 这个队列这是不为空,然后将它取出来,查找这个开始头节点的邻接点,对每一个邻接点进行遍历,输出其数据,并同时将这些邻接点列入队列中,这样队列中的头此时就是第一个访问的邻接点,再次读取队列头,这样循环读取队列头,就得到的是每一层一层的。
实现:
/*
* brief bread first search with the unjoin sort, use a queue make the search simple
*/
//问题:横向循环问题。
void breadFirstSearch()
{
int count = 0;
queue<int> bfs_queue;
cout << "breadFirstSearch: " << endl;
for(int i = 0; i < iVertexNum; i++)
{
vecVertex.at(i).bIsVisited = false;
}
for(int i = 0; i < iVertexNum; i++)
{
if(!(vecVertex.at(i).bIsVisited))
{
vecVertex.at(i).bIsVisited = true;
cout << vecVertex.at(i).data << endl;
}
bfs_queue.push(i);
while(!bfs_queue.empty()) //利用了一个队列很巧妙的实现了。
{
SVertexNode node = vecVertex.at(bfs_queue.front());
bfs_queue.pop();
for(int i = 0; i < node.vecLoc.size(); i++)
if(!(vecVertex.at(node.vecLoc.at(i)).bIsVisited))
{
vecVertex.at(node.vecLoc.at(i)).bIsVisited = true;
cout << vecVertex.at(node.vecLoc.at(i)).data << endl;
bfs_queue.push(node.vecLoc.at(i));
} // end if
} // end while
} // end for
} // end breadFirstSearch
整体结构的代码:
#include "iostream"
#include "vector"
#include "queue"
#include "string"
using namespace std;
#define Max 26
class Graph
{
private:
struct SVertexNode //节点信息
{
bool bIsVisited;
string data;
vector<int> vecLoc; //弧的令一个节点的存储
SVertexNode():bIsVisited(false)
{}
};
typedef struct SEdge //边界信息
{
int iInitialNode;
int iTerminalNode;
}Edge;
int iVertexNum; //顶点数目
int iEdgeNum; //边数目
vector<SVertexNode> vecVertex; //存储顶点的容器
public:
/*
* brief Initalize the graph.
*
* v: vertex number of the graph.
*/
Graph(int v):iVertexNum(v), iEdgeNum(0) //初始化
{
char szData[6];
SVertexNode node;
for(int i = 0; i < v; i++)
{
sprintf(szData, "v%d", i+1);
node.data = szData; //有几个节点的话先进性分配
vecVertex.push_back(node);
}
}
/*
* brief Make an edge by initial node and terminal node.
*/
Edge MakeEdge(int v, int w)
{
Edge edge;
edge.iInitialNode = v;
edge.iTerminalNode = w;
iEdgeNum++;
return edge;
}
/*
* brief Insert an edge to the graph
*/
void InsetEdge(const Edge &e)
{
vecVertex.at(e.iInitialNode).vecLoc.push_back(e.iTerminalNode);
//if the graph is Undigraph, need do something here...
//vecVertex.at(e.iTerminalNode).vecLoc.push_back(e.iInitialNode);
iEdgeNum++;
}
/*
* brief Show the graph.
*/
void ShowGraph()
{
cout << "Show the graph" << endl;
for(int i = 0; i < iVertexNum; i++)
{
cout << "Node " << i << "(" << vecVertex.at(i).data << ")";
for(int j = 0; j < vecVertex.at(i).vecLoc.size(); j++)
{
cout << "->" << vecVertex.at(i).vecLoc.at(j);
}
cout << endl;
}
}
/*
* brief depth first search
*/
void depthFirstSearch()
{
cout << "depthFirstSearch: " << endl;
for(int i = 0; i < iVertexNum; i++)
{
if(!vecVertex.at(i).bIsVisited)
{
depthFirstSearch(i);
}
}
}
void depthFirstSearch(int v)
{
int iAdjacent = 0;
SVertexNode node = vecVertex.at(v);
vecVertex.at(v).bIsVisited = true;
cout << node.data << endl;
//thus we can search the node
for(int i = 0; i < node.vecLoc.size(); i++)
{
iAdjacent = node.vecLoc.at(i);
if(!(vecVertex.at(iAdjacent).bIsVisited))
depthFirstSearch(iAdjacent);
}
}
/*
* brief bread first search with the unjoin sort, use a queue make the search simple
*/
//问题:横向循环问题。
void breadFirstSearch()
{
int count = 0;
queue<int> bfs_queue;
cout << "breadFirstSearch: " << endl;
for(int i = 0; i < iVertexNum; i++)
{
vecVertex.at(i).bIsVisited = false;
}
for(int i = 0; i < iVertexNum; i++)
{
if(!(vecVertex.at(i).bIsVisited))
{
vecVertex.at(i).bIsVisited = true;
cout << vecVertex.at(i).data << endl;
}
bfs_queue.push(i);
while(!bfs_queue.empty()) //利用了一个队列很巧妙的实现了。
{
SVertexNode node = vecVertex.at(bfs_queue.front());
bfs_queue.pop();
for(int i = 0; i < node.vecLoc.size(); i++)
if(!(vecVertex.at(node.vecLoc.at(i)).bIsVisited))
{
vecVertex.at(node.vecLoc.at(i)).bIsVisited = true;
cout << vecVertex.at(node.vecLoc.at(i)).data << endl;
bfs_queue.push(node.vecLoc.at(i));
} // end if
} // end while
} // end for
} // end breadFirstSearch
}; //class Graph
/*
* brief main for test the class of Graph and use the depthFirstSearch to search
*/
int main()
{
Graph graph(4);
graph.InsetEdge(graph.MakeEdge(0, 3));
graph.InsetEdge(graph.MakeEdge(0, 2));
graph.InsetEdge(graph.MakeEdge(1, 0));
graph.InsetEdge(graph.MakeEdge(3, 1));
graph.InsetEdge(graph.MakeEdge(3, 0));
graph.ShowGraph();
graph.depthFirstSearch();
graph.breadFirstSearch();
cin.get();
cin.get();
return 0;
}
![](https://img-my.csdn.net/uploads/201210/07/1349585207_5828.jpg)
体会: 1)对于每个结构体中的数据,其初值化的位置,以及在后续调用中的设置问题;
2)代码要将思想写好,多练习,多写,可以参考,但不能一直参考;
3)代码中的细节要把握好,比如每一个方法的简短说明,方法的命名等问题。