考え
- WeChatでの友情
- QQ はあなたが知っているかもしれない人を推薦します
- グラフデータベース Neo4j
- ナレッジマップ推奨アルゴリズム、データマイニング
- ナビゲーション ソフトウェアのルート推奨、ダイクストラ アルゴリズム
グラフ – リレーショナル ネットワーク システムの解決
グラフの基本的な知識:
- バーテックス:
- 側:
- 頂点次数:
- 出度、入度
- 有向グラフ
- 無向グラフ
ストレージ: 配列 + リンクされたリスト
リレーショナル ネットワーク システムの解決
隣接行列
グラフには x 個の点があり、これは x*x の行列です。
7*7
0と1の行列
A[7][7]
: 配列の添え字を巧みに適用するA[1][1]
状況を1対1で示しますA[1][2]
1対2の状況を意味し、サイドマークありA[1][2]=1
、サイドマークなしA[1][3]=0
スパース行列: 3*3 行列
0 0 0
1 1 1
0 1 0
隣接リスト: リンクされたリスト
-
配列: スペースの無駄ですが、速度の妨げになります。小さなデータには配列が推奨されます
-
リンクされたリスト: スペースは節約できますが、速度が遅い
グラフ横断検索アルゴリズム
場合:
美女を救出せよ: ある日、シャオメイはあなたと一緒に迷路を遊びに行きました。しかし、方向音痴のシャオメイはすぐに道に迷ってしまいます。それを知ったら、
無力なシャオメイを助けに行きましょう。迷路の地図を理解しました。次に、そこから
シャオメイに到達できるかどうかを知る必要があります。あなたの現在地。美しい場所ですか?
1: マップ上の障害物を意味し、0 は進むべき道があることを意味します
隣接行列:
0(あなた) | 0 | 1 | 0 |
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0(シャオメイ) | 0 |
0 | 0 | 0 | 1 |
深さ優先トラバーサル (DFS)
迷路をプレイすることを想像してみてください。最後まで進む方向を選択しても、行けなくなるまで戻って別の方向を試します。そう、これは実際には深さ優先の横断です。一方の方法は最後まで進み、再帰、後戻りが行われます。移動した地点にもマークを付けます
重要な最適化: 枝刈り
面接では検索アルゴリズムに直面するのは簡単です。コンピューターテスト
面接で直接質問するのが木に尋ねるのが最も簡単です
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
//深度遍历 最短路线
class DFS {
int line; //地图行
int column; //地图列
int dx; //目标x
int dy; //目标y
int data[][]; //邻街矩阵
boolean mark[][]; //标记数据
int minStep = Integer.MAX_VALUE;
int next[][] = {
{
0,1}, {
1,0}, {
0,-1}, {
-1,0}}; // ACM 想到的
Stack<Point> stack = new Stack<>(); //保存当前路径
//保存所有的路径,key是步数
Map<Integer, List<Stack<Point>>> result = new HashMap<>();
public DFS(int line, int column, int dx, int dy, int[][] data, boolean[][] mark) {
this.line = line;
this.column = column;
this.dx = dx;
this.dy = dy;
this.data = data;
this.mark = mark;
}
public void dfs(int sx, int sy, int step) {
if (sx == dx && sy == dy) {
if (!result.containsKey(step)) {
result.put(step, new ArrayList<>());
}
result.get(step).add((Stack<Point>) stack.clone());
if (step < minStep ) minStep = step;
return;
}
for (int i = 0; i < 4; i++) {
int nextX = sx + next[i][0];
int nextY = sy + next[i][1];
if (nextX < 0 || nextX > line || nextY < 0 || nextY > column) continue;
if (data[nextX][nextY] == 0 && !mark[nextX][nextY]) {
mark[nextX][nextY] = true;
stack.add(new Point(nextX, nextY));
dfs(nextX, nextY, step+1);
mark[nextX][nextY] = false; //回溯
stack.pop();
}
}
}
public static void main(String[] args) {
int data[][] = {
{
0,0,1,0},
{
0,0,0,0},
{
0,0,1,0},
{
0,1,0,0},
{
0,0,0,1}
};
int dx = 3;
int dy = 2;
int sx = 0;
int sy = 0;
int line = 4;
int column = 3;
boolean mark[][] = new boolean[line+1][column+1];
DFS dfs = new DFS(line, column, dx, dy, data, mark);
dfs.dfs(sx, sy, 0);
System.out.println(dfs.minStep);
List<Stack<Point>> stacks = dfs.result.get(dfs.minStep);
for (Stack<Point> stack : stacks) {
for (Point point : stack) {
System.out.printf("(" + point.x + ", " + point.y + ")");;
}
System.out.println();
}
}
}
幅優先トラバーサル (BFS) ---- ArrayBlockingQueue
ツリー構造の階層トラバースと同様に、最初にポイントを見つけてから、そのポイントをキューに追加し、ポイントの関連するエッジを見つけてキューに追加し、キューが空になり、すべての道路が空になるまでループします。最初から消えてる
重要な 2 つのポイント: キュー、マーク配列、追加ポイントは追加できません
ヒューリスティック検索、A*
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
//广度遍历 能不能到达
class BFS {
int line; //地图行
int column; //地图列
int dx; //目标x
int dy; //目标y
int data[][]; //邻街矩阵
boolean mark[][]; //标记数据
int next[][] = {
{
0,1}, {
1,0}, {
0,-1}, {
-1,0}}; // ACM 想到的
public BFS(int line, int column, int dx, int dy, int[][] data, boolean[][] mark) {
this.line = line;
this.column = column;
this.dx = dx;
this.dy = dy;
this.data = data;
this.mark = mark;
}
public boolean bfs(int sx, int sy) {
//当前位置 x,y当前位置 求(x,y)->(dx,dy)
if (sx < 0 || sx > line || sy < 0 || sy > column) return false;
if (sx == dx && sy == dy) {
System.out.println("当前位置就是目标位置: sx = " + sx + ", sy = " + sy);
return true;
}
mark[sx][sy] = true;
Queue<Point> queue = new ArrayBlockingQueue<>(line * column);
queue.add(new Point(sx,sy));
while (!queue.isEmpty()) {
Point point = queue.poll(); //队列第一个点
for (int i = 0; i < 4; i++) {
int nextX = point.x + next[i][0];
int nextY = point.y + next[i][1];
if (nextX < 0 || nextX > line || nextY < 0 || nextY > column) continue;
if (data[nextX][nextY] == 0 && !mark[nextX][nextY]) {
if (nextX == dx && nextY == dy) {
System.out.println("找到了: dx = " + dx + ", dy = " + dy);
return true;
}
mark[nextX][nextY] = true;
queue.add(new Point(nextX, nextY));
}
}
}
return false;
}
public static void main(String[] args) {
int data[][] = {
{
0,0,1,0},
{
0,0,0,0},
{
0,0,1,0},
{
0,1,0,0},
{
0,0,0,1}
};
int dx = 3;
int dy = 2;
int sx = 0;
int sy = 0;
int line = 4;
int column = 3;
boolean mark[][] = new boolean[line+1][column+1];
BFS bfs = new BFS(line, column, dx, dy, data, mark);
bfs.bfs(sx,sy);
}
}
最短経路 – ダイクストラのアルゴリズム
最短経路の核となるアイデアの分析: 貪欲: 並べ替え、貪欲な戦略。1-3 10、ローカルを検討します
- 始点から各頂点までの距離を表す dis 配列を開き、最初に無限大の値を割り当てます。
- 変数 loc を追加します。初期代入が開始点となります。
- ポイントを追加した後にパスを更新できるため、loc を通じて dis 配列を更新します。
贪心策略:在dis数组里面找离初始点最近的那个点
- dis 配列内の初期点に最も近い点を検索し、選択した点を除外して、それを loc に割り当てます。
- すべての点が追加されるまで 3 4 の操作を繰り返します
//地图--最短路径 迪杰斯特拉算法(Dijkstra)
/**
6 个点
8 个变
1 是起点
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
1 到 1 的最短距离是 0 === 最短路径是 1
1 到 2 的最短距离是 2147483647 === 无法到达
1 到 3 的最短距离是 10 === 最短路径是 1 -> 3
1 到 4 的最短距离是 50 === 最短路径是 1 -> 5 -> 4
1 到 5 的最短距离是 30 === 最短路径是 1 -> 5
1 到 6 的最短距离是 60 === 最短路径是 1 -> 5 -> 4 -> 6
*/
class DJSTL {
static Map<Integer, String> routes = new HashMap<>();
public static void search(int start, int dis[], int value[][], int point) {
boolean mark[] = new boolean[point+1];
mark[start] = true;
dis[start] = 0;
int count = 1;
while (count <= point) {
//O(n^2)
//求最小值点开始
int loc = 0; //新加的点
int min = Integer.MAX_VALUE;
for (int i = 1; i <= point; i++) {
//求dis里面最小的值 可以优化成 堆 logn
if (!mark[i] && dis[i] < min) {
min = dis[i];
loc = i;
}
}
if (loc == 0) break; //表示没有可以加入的点
mark[loc] = true;
if (routes.get(loc) == null) {
routes.put(loc, start + " -> " + loc);
}
//加入的点到各点距离计算
//优化只需要关注加入的点
for (int i = 1; i <= point; i++) {
//min(dis[3] + data[3][4], dis[4])
if ( value[loc][i] != -1 && (dis[loc] + value[loc][i] < dis[i]) ) {
dis[i] = dis[loc] + value[loc][i];
routes.put(i, routes.get(loc) + " -> " + i);
}
}
count++;
}
for (int i = 1; i <= point; i++) {
System.out.print(start + " 到 " + i + " 的最短距离是 " + dis[i] + " === ");
if (dis[i] == 0 && routes.get(i) == null) {
System.out.println("最短路径是 " + i);
} else if (dis[i] == Integer.MAX_VALUE) {
System.out.println("无法到达");
} else {
System.out.println( "最短路径是 " + routes.get(i));
}
}
}
public static void main(String[] args) {
int point, line, start; //n 点数, m 边数, x 起点
Scanner scanner = new Scanner(System.in);
point = scanner.nextInt();
line = scanner.nextInt();
start = scanner.nextInt();
int value[][] = new int[point+1][line+1]; //点到点矩阵
int dis[] = new int[point+1]; //存储最短路径
for (int i = 1; i <= point; i++) {
dis[i] = Integer.MAX_VALUE;
for (int j = 1; j <= point; j++) {
//初始化地图
if (i == j) {
value[i][j] = 0;
} else {
value[i][j] = -1;
}
}
}
for (int i = 0; i < line; i++) {
int xx = scanner.nextInt();
int yy = scanner.nextInt();
int v = scanner.nextInt(); //xx 到 yy 的距离
value[xx][yy] = v;
if (xx == start) {
dis[yy] = v;
}
}
search(start, dis, value, point);
}
}