目录
1.广度优先搜索
1.1.广度优先搜索的概念
广度优先搜索(Breadth-First-Search, BFS),类似二叉树层次遍历。以v为起点,依次访问和v有路径相同且路径长度为1,2,……的顶点
#define MaxVertexNum 100
bool visited[MaxVertexNum]; //标记是否访问过
void BTS(Graph G, int v){ //从顶点v出发
Queue Q;
initQueue(Q);
visit(v); //访问v
visited[v] = true; //visited数组中下标v的元素改为true
EnQueue(Q, v); //v入队
while(!IsEmpty(Q)){
DeQueue(Q, v); //取出队头元素
int w;
for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
//检测所有v的邻接点
if (!visit[w]){ //w当前未访问过
visit(w); //访问w
visit[w] = true; //visited数组中下标w的元素改为true
EnQueue(Q, w); //将w入队
}//if
}//for
}//while
}
非连通图或非强连通图,在执行完BTS后,可能还会有剩余的顶点没有访问到,因此,要重新调用BTS函数继续进行遍历
bool visited[MaxVertexNum];
void BTS(Graph G, int v){
visit(v);
visited[v] = true;
Queue Q;
InitQueue(Q);
EnQueue(Q, v);
while(!IsEmpty(Q)){
DeQueue(Q, v);
int w;
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
if (!visited[w]){
visit(w);
visited[w] = true;
EnQueue(Q, W);
}//if
}//for
}//while
}
void BTS_G(Graph G){
for (int i = 0; i < G.verNum; i++) visited[i] = false; //初始化visited数组
//当前visited数组下标i的元素为false,调用BTS函数
for (int i = 0; i < G.verNum; i++) if (!visited[i]) BTS(G, i);
}
1.2.广度优先搜索的可变性
邻接矩阵唯一→广度优先遍历序列唯一
邻接表不唯一→广度优先遍历序列不唯一
1.3.广度优先搜索性能
空间复杂度:图中每个顶点都需要入队一次,最坏情况下是O(|V|)
时间复杂度:分为访问各顶点的时间和探索各条边的时间
- 邻接矩阵,访问V个结点,需要O(|V|),查找需遍历V行(顶点数),每行V个顶点,需要O(|
|),故时间复杂度为O(|
|)
- 邻接表,访问V个结点,需要O(|V|),查找E个边,需要O(|E|),故时间复杂度为O(|V|+|E|)
2.深度优先搜索
2.1.深度优先搜索的概念
首先访问起点v,然后访问与之邻接且未被访问的顶点w,再访问与w邻接且未被访问的顶点u,直到不能再继续向下访问时,依次退回到最近被访问的顶点,如果还有邻接且未被访问的顶点,则访问那个顶点,循环这个过程,直至图中所有顶点都被访问过
bool visited[MaxVertexNum];
void DFS(Graph G, int v){
visit(v);
visited[v] = true;
int w;
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) DFS(G, w);
}
void DFS_G(Graph G){
for (int i = 0; i < G.verNum; i++) visit[i] = false;
for (int i = 0; i < G.verNum; i++) if (!visit[i]) DFS(G, i);
}
2.2.深度优先搜索的性能
空间复杂度:最好O(1):中间一点连着其他顶点,栈仅需一个空间;最坏O(|V|):一条线,需要全部依次压入栈中
时间复杂度:
- 邻接矩阵 O(|
|)
- 邻接表O(|V|+|E|)
3.图的遍历和图的连通性
无向图:DFS/BFS函数调用次数 = 连通分量数
有向图:起始顶点到其他顶点都有路径,则仅需一次;强连通图从任意一个顶点出发,都仅需一次
4.王道课后题
无向图是树→连通图且没有回路 || 有 n - 1 条边的连通图
//广度搜索,对应连通图且没有回路
bool visited[MaxVertexNum];
bool IsTree(ALGraph G) {
//初始化visited数组
for (int i = 0; i < MaxVertexNum; i++) visited[i] = false;
Queue Q;
InitQueue(Q);
//寻找图中的第一个数据
int p;
for (p = 0; p < MaxVertexNum; p++) if (G.vertices[p].data) break;
int temp = p;
int count = 0; //标记访问了多少个顶点
//将p入队
EnQueue(Q, p);
while (!IsEmpty(Q)) {
//出队队头元素
DeQueue(Q, p);
//当前顶点p未扫描过,则进入标记扫描,并且找到所有与它邻接的顶点,并依次入队
if (!visited[p]) {
visited[p] = true;
count++;
for (int q = FirstNeighbor(G, p); q >= 0; q = NextNeighbor(G, p, q)){
EnQueue(Q, q);
}
}
//扫描过p,存在回路
else return false;
}
//访问顶点个数不等于顶点总数,非连通图
if (count != G.verNum) return false;
else return true;
}
//DFS,对应有 n - 1 条边的连通图
bool visited[MaxVertexNum];
bool IsTree(ALGraph G) {
//初始化visited数组为false
for (int i = 0; i < G.verNum; i++) visited[i] = false;
//vCount记录遍历顶点数,eCount记录遍历边数
int vCount = 0, eCount = 0;
//遍历G中的每个顶点
for (int i = 0; i < G.verNum; i++) {
if (!visited[i]) DFS(G, vCount, eCount, i);
}
//满足条件顶点数=已遍历顶点数,并且边数为n - 1
//无向图的存储中每条边存储两次
if (vCount == G.verNum && 2 * eCount + 2 == G.arcNum) return true;
else return false;
}
void DFS(ALGraph G, int& vCount, int& eCount, int v) {
if (!visited[v]) {
visited[v] = true;
//访问顶点数+1
vCount++;
}
for (int w = FistNeighbor; w >= ; w = NextNeighbor) {
//访问边数+1
eCount++;
DFS(G, vCount, eCount, w);
}
}
#define MaxVertexNum 100
typedef struct ArcNode{
struct ArcNode *next;
int adjVertex;
}ArcNode;
typedef struct VNode{
ArcNode *next;
elemtype data;
}VNode, adjList[MaxVertexNum];
typedef struct{
adjList vertices;
int verNum, arcNum;
}ALGraph;
typedef struct Stack{
int top;
elemtype data[MaxVertexNum];
}Stack;
bool visited[MaxVertexNum];
void DFS(ALGraph G, int v){
//初始化visited数组
for (int i = 0; i < MaxVertexNum; i++) visited[i] = false;
Stack S;
InitStack(S);
int i, j;
//访问v,并将v压入栈中
visited[v] = true;
push(S, v);
//循环直到栈空
while(!IsEmpty(S)){
//弹出栈顶元素
pop(S, i);
//访问i所有的邻接结点
for (j = FirstNeighbor(G, i); j >= 0; j = NextNeighbor(G, i, j)){
//将j压入栈中
if (!visited[j]) {
visited[j] = true;
push(S, j);
}
}//for
}//while
}
//广度搜索
#define MaxVertexNum 100
typedef struct ArcNode{
struct ArcNode *next;
int adjVertex;
}ArcNode;
typedef struct VNode{
ArcNode *first;
elemtype data;
}VNode, AdjList[MaxVertexNum];
typedef struct ALGraph{
AdjList vertices;
int verNum, arcNum;
}ALGraph;
typedef struct Queue{
elemtype data[MaxVertexNum];
int rear, front;
}Queue;
bool visited[MaxVertexNum];
bool BFS_iToj(Graph G, int i, int j){
for (int i = 0; i < G.verNum; i++) visited[i] = false;
Queue Q;
InitQueue;
EnQueue(Q, i);
int w, v;
while (!IsEmpty(Q)){
DeQueue(Q, v);
if (!visited[v]) {
//v == j, ij存在路径,返回true
if (j == v) return true;
visited[v] = true;
for (w = FistNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
if (!visited[w]) EnQueue(Q, w);
}
}//if
}//while
//ij没有路径,返回false
return false;
}
//深度搜索
#define MaxVertexNum 100
typedef struct ArcNode{
struct ArcNode *next;
int adjVertex;
}ArcNode;
typedef struct VNode{
ArcNode *first;
elemtype data;
}VNode, AdjList[MaxVertexNum];
typedef struct ALGraph{
int verNum, arcNum;
AdjList vertices;
}ALGraph;
typedef struct Stack{
elmetpye data[MaxVertexNum];
int top;
}Stack;
bool visited[MaxVertexNum];
bool DFS_iToj(ALGraph G, int i, int j){
Stack S;
InitStack(S);
for (int temp = 0; temp < G.verNum; temp++) visited[temp] = false;
push(S, i);
visited[i] = 0;
int v, w;
while (!IsEmpty(S)){
pop(S, v);
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){
//w == j, ij存在路径,返回true
if (w == j) return true;
if (!visited[w]) {
visited[w] = true;
push(S, w);
}
}//for
}//while
return false;
}