隣接リンクリストと行列がグラフを表す場合の幅優先検索と深さ優先検索

1.グラフの基本的な表現:
G(V、E)はグラフを表し、Vはベクトルノード、Eはエッジです。
隣接リストは、スパースグラフを表すためによく使用され、隣接マトリックスは、密なグラフを表すことがよくあります。、隣接行列は、グラフスケールが小さいときによく使用されます。これは、行列が単純だからです。
ここに画像の説明を挿入
隣接するリンクされたリストの長さの和2|E|無向グラフであり、有向グラフの隣接するリンクされたリストの長さの合計です|E|
ここに画像の説明を挿入
2.幅優先検索BFS:
BFSは、ウェイトグラフなしで最短経路を解くための最も基本的なアルゴリズムです
これに基づく単一ソースの最短経路問題、加重グラフの最短経路解決問題であり、解決策はダイクストラアルゴリズム(BFS改善に基づく)です。

アルゴリズムは、ソースノードsからの距離がkであるすべてのノードを見つけた後、ソースノードsからの距離がk + 1である他のノードを見つけます。
ここに画像の説明を挿入
注:幅優先検索は階層検索このプロセスでは、深さ優先検索とは異なり、前進するすべてのステップが頂点のバッチを訪問する可能性があります。バックトラックは行われないため、再帰的なアルゴリズムではありません。レイヤーごとのアクセスを実現するために、アルゴリズムは、補助キューを使用して、アクセスされている頂点の次のレイヤーを記録する必要があります
同時に、ノードアクセスの状態を保存する必要があります(繰り返しアクセスを避けるため)。、隣接行列の形式の場合は、配列を使用してノードのアクセス状態を保存します。隣接リンクリストの形式の場合は、リンクリストのノード属性を増やしますnode.accessed = true
2.1。隣接行列で表される幅優先検索C ++コード:
配列を使用してノードのアクセス状態を保存する

const int MaxNum = 10; // 图的大小10X10
int G[MaxNum ][MaxNum ]; // 表示图 ,顶点为数字0-9,此部分要随题变化
int visited[MaxNum ] = {
    
    0}; // 保存访问状态
int route[MaxNum ] ={
    
    -1}; //记录路径
queue<int> q; // 记录待访问节点
void BFS(int* G,int start) // 输入图与搜索起点,起点类型随题目而变
{
    
    
	visited[start] = 1;
	route[start] = -1; //源头,-1表示已经没有路了
	q.push(start);
	while(!q.empty()){
    
    
		int tmpnode = q.front();
		q.pop();
		for(int i = 0;i<MaxNum;i++){
    
    
			if(G[tmpnode][i] = 1 && visited[i] == 0){
    
     //1代表连接(有路) 
			//当两节点间连接且没访问过则进行处理:加入待放问列表
				route[i] = tmpnode; //路的来源
				q.push(i); 
				visited[i] = 1;
			}
		}
	}
}

//输出起点start到任一点的路径:
void route(int start, int end)
{
    
    
	vector<int> route_start_end;
	while( end !=-1){
    
    
		route_start_end.push_back(end);
		end = route[end];
	}
	for(int i = route_start_end.size()-1;i>=0;i--){
    
    
		std::cout<<route_start_end[i];
	}
}

2.2。隣接リンクリストで表される幅優先検索C ++コード:
訪問済み配列の代わりに訪問済み属性をノードに追加することもできます

struct ListNode {
    
    
	int val;
	struct ListNode *next;
	ListNode(int x) : val(x), next(NULL) {
    
    }
}
const int MaxNum = 10; // 图的大小10X10
ListNode* G[MaxNum]; // 图,假设已经构造好了
void BFS(ListNode* G,int start) // 输入图与搜索起点,起点类型随题目而变
{
    
    
	int visited[MaxNum ] = {
    
    0}; // 保存访问状态
	int route[MaxNum ] ={
    
    -1}; //记录路径
	queue<ListNode*> q; // 记录待访问节点
	q.push(G[start]); //起点入队
	visited[start] = 1; //标识起点已经访问
	while(!q.empty()){
    
    
		ListNode* tmp = q.front();
		q.pop();
		while(tmp->next != null){
    
    
			if(visited[tmp->next->val]!=1){
    
    
				q.push(tmp->next);
				visited[tmp->next->val] = 1;
				route[tmp->next->val] =tmp->val; //记录路径
			}
			tmp = tmp->next;
		}
	}
}

2.3。非ユニコムマップの幅優先検索:

void BFSall(ListNode* G)
{
    
    
	for(int i = 0;i<MaxNum;i++){
    
    
		if(visited[i]!=1){
    
    
			BFS(G,i); // 若这个节点未访问过说明与其他节点不连通,从此节点开始再调用BFS 
		}
	}
}

参考資料:
良:グラフの幅優先検索(BFS)および深さ優先検索(DFS)アルゴリズム分析
幅優先検索(BFS)C ++実装

3.深さ優先検索:
深さ優先検索は、ツリーの事前順序トラバーサルに似ています。訪問されたノードを記録する配列が必要であり、すべてのノードが訪問されたときに、再帰を使用して先行ノードに戻る
3.1。隣接行列で表される深さ優先検索C ++コード:

int visited[MaxNum] = {
    
    0}; // 保存访问状态
void DFS(int* G,int start)
{
    
    
	visit(start); // 可以是输出、记录父节点等任何操作
	visited[start] = 1;
	for(int i = 0;i<MaxNum;i++){
    
    
		if(G[start][i]!=0 && visited[i]!=1){
    
    
			DFS(G,i);
		}
	}
} 

3.2。隣接リンクリストで表される深さ優先検索C ++コード:

int visited[MaxNum] = {
    
    0}; // 保存访问状态
void DFS(ListNode* G,int start) //start为访问起点
{
    
    
	visit(start); // 可以是输出、记录前驱节点等任何操作
	visited[start] = 1;
	ListNode* head = G[start];
	while(head){
    
    
		ListNode* tmp = head->next;
		if(tmp && visited[tmp->val]!=1){
    
     //若节点存在且未访问,则递归进入
			DFS(G,tmp->val); 
		}
		head = tmp; //否则就退回源节点,转到链表其余节点
	}
} 

参考資料:グラフの幅優先探索(BFS)および深さ優先探索(DFS)アルゴリズムの分析

総括する:

1.幅優先検索はシーケンストラバーサルに似ています。訪問するノードを格納するにはキューが必要です。ノードのアクセスステータスを識別するには属性が必要です。ノードパスを保存するには、パス配列も必要です。
2.深さ優先検索は、再帰によって実装される事前注文トラバーサルに似ています。
3. BFSとDFSの検索の開始点は不明確であるため、問題を解決するときは通常、最初に開始点を見つける必要があります。
4.幅優先検索アルゴリズムを使用できます最短経路を見つけます。

おすすめ

転載: blog.csdn.net/qq_33726635/article/details/105968253