데이터 구조 및 알고리즘(4): 그래프 이론(그래프 이론 개념, 깊이 우선 순회 DFS, 너비 우선 순회 BFS, 최단 경로, Dijkstra 알고리즘)

생각하다

  1. 위챗 우정
  2. QQ는 당신이 알 수도 있는 사람들을 추천합니다
  3. 그래프 데이터베이스 Neo4j
  4. 지식지도 추천 알고리즘, 데이터 마이닝
  5. 내비게이션 소프트웨어 경로 추천, Dijkstra 알고리즘

그래프 - 관계형 네트워크 시스템 해결

그래프에 대한 기본 지식:

  1. 꼭지점:
  2. 옆:
  3. 정점 정도:
  4. 출도, 입도
  5. 유향 그래프
  6. 무방향 그래프

저장소: 배열 + 연결 목록

관계형 네트워크 시스템 해결

인접 행렬

그래프에는 x*x의 행렬인 x개의 점이 있습니다.

7*70과 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

인접 목록: 연결된 목록

  • 배열: 공간 낭비지만 속도 차단. 작은 데이터에는 배열이 선호됩니다.

  • 연결된 목록: 공간을 절약하지만 느림

그래프 순회 검색 알고리즘

사례:

미인 구출: 어느 날 Xiaomei는 당신과 함께 미로를 놀러갔습니다. 하지만 방향 감각이 나쁜 Xiaomei는 곧 길을 잃을 것입니다. 이에 대해 알게 된 후
무기력한 Xiaomei를 구하러 가십시오. 당신은 미로의 지도를 알아냈습니다. 이제
Xiaomei 에 도달할 수 있는지 여부를 알아야 합니다. 현재 위치 아름다운 위치?

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

트리 구조의 계층적 순회와 유사하게 먼저 점을 찾은 다음 해당 점을 대기열에 추가하고 해당 점의 연결된 가장자리를 찾아 대기열에 추가하고 대기열이 빌 때까지 루프를 돌며 모든 도로를 초반에 없어진다

두 가지 핵심 포인트: 대기열, 마크 배열, 추가된 포인트는 추가할 수 없음

휴리스틱 검색, 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);
    }
}

최단 경로 – Dijkstra의 알고리즘

최단 경로의 핵심 아이디어 분석: 탐욕: 정렬, 탐욕 전략. 1-3 우리는 10, 지역을 고려합니다

  1. 시작점에서 각 정점까지의 거리를 나타내기 위해 dis 배열을 엽니다. 처음에는 무한대 값을 할당합니다.
  2. 변수 loc을 추가하면 초기 할당이 시작점입니다.
  3. 점을 추가한 후 경로를 업데이트할 수 있으므로 loc을 통해 dis 배열을 업데이트합니다.贪心策略:在dis数组里面找离初始点最近的那个点
  4. dis 배열에서 초기점과 가장 가까운 점을 찾아 선택한 점을 제외하고 loc에 할당
  5. 모든 점이 추가될 때까지 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);
    }
}

추천

출처blog.csdn.net/menxu_work/article/details/130361924