双方向検索?
双方向検索 は双方向で実行される検索手法です。これは、同時に実行される2人の検索で機能します。最初の1つはソースからの目標であり、もう1つは目標からソースへの逆方向です。最適な状態では、両方の検索がデータ構造の真ん中で出会うでしょう。
双方向検索アルゴリズムは、有向グラフで機能し、ソース(初期ノード)からゴールノードまでの最短経路を見つけます。 2つの検索はそれぞれの場所から開始され、2つの検索がノードで出会うとアルゴリズムは停止します。
双方向アプローチの重要性 −これはより高速な手法であり、グラフのトラバースに必要な時間を改善します。
このアプローチは、開始ノードと目標ノードが一意で定義されている場合に効率的です。分岐係数は両方向で同じです。
パフォーマンス測定
-
完全性 −両方の検索でBFSが使用されている場合、双方向検索は完了です。
-
最適性 −検索にBFSを使用し、パスのコストが均一である場合に最適です。
-
時間と空間の複雑さ −時間と空間の複雑さは O(b ^ {d / 2})
例
#include <bits/stdc++.h>
using namespace std;
class Graph {
int V;
list<int> *adj;
public:
Graph(int V);
int isIntersecting(bool *s_visited, bool *t_visited);
void addEdge(int u, int v);
void printPath(int *s_parent, int *t_parent, int s,
int t, int intersectNode);
void BFS(list<int> *queue, bool *visited, int *parent);
int biDirSearch(int s, int t);
};
Graph::Graph(int V) {
this->V = V;
adj = new list<int>[V];
};
void Graph::addEdge(int u, int v) {
this->adj[u].push_back(v);
this->adj[v].push_back(u);
};
void Graph::BFS(list<int> *queue, bool *visited,
int *parent) {
int current = queue->front();
queue->pop_front();
list<int>::iterator i;
for (i=adj[current].begin();i != adj[current].end();i++) {
if (!visited[*i]) {
parent[*i] = current;
visited[*i] = true;
queue->push_back(*i);
}
}
};
int Graph::isIntersecting(bool *s_visited, bool *t_visited) {
int intersectNode = -1;
for(int i=0;i<V;i++) {
if(s_visited[i] && t_visited[i])
return i;
}
return -1;
};
void Graph::printPath(int *s_parent, int *t_parent,
int s, int t, int intersectNode) {
vector<int> path;
path.push_back(intersectNode);
int i = intersectNode;
while (i != s) {
path.push_back(s_parent[i]);
i = s_parent[i];
}
reverse(path.begin(), path.end());
i = intersectNode;
while(i != t) {
path.push_back(t_parent[i]);
i = t_parent[i];
}
vector<int>::iterator it;
cout<<"Path Traversed by the algorithm\n";
for(it = path.begin();it != path.end();it++)
cout<<*it<<" ";
cout<<"\n";
};
int Graph::biDirSearch(int s, int t) {
bool s_visited[V], t_visited[V];
int s_parent[V], t_parent[V];
list<int> s_queue, t_queue;
int intersectNode = -1;
for(int i=0; i<V; i++) {
s_visited[i] = false;
t_visited[i] = false;
}
s_queue.push_back(s);
s_visited[s] = true;
s_parent[s]=-1;
t_queue.push_back(t);
t_visited[t] = true;
t_parent[t] = -1;
while (!s_queue.empty() && !t_queue.empty()) {
BFS(&s_queue, s_visited, s_parent);
BFS(&t_queue, t_visited, t_parent);
intersectNode = isIntersecting(s_visited, t_visited);
if(intersectNode != -1) {
cout << "Path exist between " << s << " and "
<< t << "\n";
cout << "Intersection at: " << intersectNode << "\n";
printPath(s_parent, t_parent, s, t, intersectNode);
exit(0);
}
}
return -1;
}
int main() {
int n=15;
int s=0;
int t=14;
Graph g(n);
g.addEdge(0, 4);
g.addEdge(1, 4);
g.addEdge(2, 5);
g.addEdge(3, 5);
g.addEdge(4, 6);
g.addEdge(5, 6);
g.addEdge(6, 7);
g.addEdge(7, 8);
g.addEdge(8, 9);
g.addEdge(8, 10);
g.addEdge(9, 11);
g.addEdge(9, 12);
g.addEdge(10, 13);
g.addEdge(10, 14);
if (g.biDirSearch(s, t) == -1)
cout << "Path don't exist between "
<< s << " and " << t << "\n";
return 0;
} 出力
Path Traversed by the algorithm 0 4 6 7 8 10 14
-
データ構造における最適な二分木
整数のセットはソートされた順序で与えられ、別の配列は頻度カウントに頻繁に与えられます。私たちのタスクは、これらのデータを使用してバイナリ検索ツリーを作成し、すべての検索の最小コストを見つけることです。 サブ問題の解を解いて保存するために、補助配列cost [n、n]が作成されます。コストマトリックスは、ボトムアップ方式で問題を解決するためのデータを保持します。 入力 −ノードおよび頻度としてのキー値。 Keys = {10, 12, 20} Frequency = {34, 8, 50} 出力 −最小コストは142です。 これらは、指定された値から可能なBSTです。 ケース1の
-
C#での二分探索
バイナリ検索はソートされた配列で機能します。値は配列の中央の要素と比較されます。同等性が見つからない場合は、値が存在しない半分の部分が削除されます。同様に、残りの半分の部分が検索されます。 これが配列のmid要素です。 62を見つける必要があるとしましょう。そうすると、左側の部分が削除され、右側の部分が検索されます- これらは二分探索の複雑さです- 最悪の場合のパフォーマンス O(log n) ベストケースのパフォーマンス O(1) 平均パフォーマンス O(log n) 最悪の場合のスペースの複雑さ O(1) 例 二分