说变了,就是线性表和链表只有上线,下线没法违反监督上线,这一点很不好,我们需要的是上下线相互监督。
这种是无向图,互相之间都是联通的,A - B = 1 B - A = 1表示彼此都是联通的意思。
广度优先实在太傻逼了。就是取得一个节点的所有邻接节点,进去之后打印自己和所有邻接节点,然后将这些节点设置为访问过就行了。
然后将所有节点都送去执行上述操作(执行前先判断一下有没有被访问过,只要没被访问过就送去执行上述操作)
通过邻接矩阵方式实现深度优先广度优先题目写完了
package org.example.sort;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Graph {
private ArrayList<String> vertexList;
private int[][] edges;//记录矩阵
private int numOfedes;//边的个数
private boolean[] visited;//确定当前节点是否被访问过
public static void main(String[] args) {
//测试一把
//先设置节点数量
int n = 8;
String[] Vertesx = {"a","b","c","d","e","f","g","h"};//设置顶点
Graph graph = new Graph(n);
for(String tex : Vertesx){
graph.insert(tex);
}//将顶点添加进图里
//A - B A- c B - C B - D B - E
graph.insertedges(1,3,1);
graph.insertedges(1,4,1);
graph.insertedges(3,7,1);
graph.insertedges(4,7,1);
graph.insertedges(2,5,1);
graph.insertedges(0,1,1);
graph.insertedges(0,2,1);
graph.insertedges(2,6,1);
graph.insertedges(5,6,1);
graph.show();
System.out.println("");
graph.dfs(0);
System.out.println("广度");
graph.bfs();
}
public Graph(int n){
//初始化矩阵
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfedes = 0;
//初始化时候别忘记了这个记录访问节点的大小
visited = new boolean[n];//随时创建这个变量的大小
}
//执行广度优先
public void bfs(){
for (int i = 0;i < getedgesNums();i++){
if(!visited[i]){
//只要没被访问过就去执行广度优先
bfsNode(i);
}
}
}
//广度优先执行步骤
private void bfsNode(int i){
visited[i] = true;//进来就表示自己被访问了
System.out.print(getValueOfIndex(i) + "-> ");//打印一把自己
//广度优先遍历
//先把当前节点所有的邻接表都访问了
//需要一个队列来掌控这一切,队列把当前节点所有被访问过的子节点都一一入队
//当所有子节点都被访问过之后,从队列里将所有子节点拿出来,递归进行访问,将每个子节点的子节点都访问过,每个节点都维持一个队列
//保持掌控自己的子节点
//先打印所有子节点
for(Integer num : getAllNeighbor(i)){
if(!visited[num]){
System.out.print(getValueOfIndex(num) + "->");
visited[num] = true;//设置已经访问过了
}
}
}
//根据索引获取当前节点所有的邻接节点
public ArrayList<Integer> getAllNeighbor(int index){
ArrayList<Integer> result = new ArrayList<>();
for(int i = 0;i < getedgesNums();i++){
if(edges[index][i] != 0){
//说明联通
result.add(i);
}
}
return result;//将所有邻接点都整合到一起
}
//能进到遍历中说明这点;是可靠的
public void dfs(int i){//每次传递进来的都是下标
//深度优先进行遍历
System.out.print(getValueOfIndex(i) + "->");//打印一下当前节点值
visited[i] = true;//表示这个点已经遍历过了
//打印完了看看有没有邻接点
int next = getFirstNeighbor(i);//查找邻节点
//这个点访问完成之后查找邻接点
while (next != -1){
//说明有邻接点
if(!visited[next]){
dfs(next);//邻节点没被访问,就去访问
}
//访问下一个邻接点,回溯回来就去访问下一个邻接点
next = getNextNeighbor(i,next);//再找下一个邻接点,看看是不不是没访问过的
}
//说明有邻节点
//直接遍历邻节
}
//获取第一个邻居下标
//没有邻居会返回-1的
public int getFirstNeighbor(int index){
//获取到当前节点第一个邻居的下标
//深度优先遍历用的
//我将要查询的节点的下标给你,你遍历整个邻接矩阵表,遇到边为1的,就将列给返回,那个列下标,就是第一个我们邻接点
for(int j = 0;j < vertexList.size();j++){
if(edges[index][j] == 1){
//找到了一个邻接点
return j;//将这个邻节点索引返回去
}
}
return -1;//整行遍历了一遍都没返回,说明没有邻接点,这时候返回-1说明没有邻接点
}
//获取一个节点第二个邻节点下标需要,当前节点下标,和上一个邻接点下标。
public int getNextNeighbor(int index,int firstNeighbor){
//index当前节点下标,first表示第一个邻节点下标,本身已经算是被使用过了。
//获取当前节点,第二个邻接点下标
//毕竟一个节点可能有好多个邻接点
for(int j = firstNeighbor + 1;j < vertexList.size();j++){
if(edges[index][j] == 1){
return j;//返回第二邻接点下标
}
}
return -1;//没有第二邻节点返回-1
}
//根据下标返回节点
public String getValueOfIndex(int index){
return vertexList.get(index);
}
public int getedgesNums(){
//返回节点数量
return vertexList.size();//返回节点数量
}
//根据下标返回权值
public int getWeight(int v1,int v2){
return edges[v1][v2];
}
public void show(){
//显示矩阵很简单直接遍历二维数组就行
for(int[] link : edges){
for(int temp : link){
System.out.print(temp + " ");
}
System.out.println();
}
}
public int getNumOfedes(){//返回边的数量
//一条边代表一个联通
return numOfedes;
}
public void insert(String vertex){
vertexList.add(vertex);
}
public void insertedges(int v1,int v2,int weight){
//记录矩阵
//矩阵中有数值的下标用1表示
//v1表示第一个顶点的下标,v2表示第二顶点的下标。
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfedes++;
}
}
邻接矩阵方式对图进行深度优先遍历有一些很有意思的方法
比如随机选择一个点进行切入
,切入后将上下左右所有可以访问的点都放进队列里,同时对这个点进行已经访问过处理(改为1,或者维持一个visited数组)
然后所有点就会进到链表尾巴
等待再次被重新
就是打击了你以后,记录一下你被打击了,然后把你的小弟扔进队列尾巴,一个个来等着被审判。
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1'){
dfs(grid, i, j);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
grid[i][j] = '0';
dfs(grid, i + 1, j);
dfs(grid, i, j + 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
}
当然使用邻接表时候还要注意一下一个问题,就是一定要判断一下这个点越界不越级,越界点不行
有向图这样存储比较好。
按照存储顺序,一个个访问节点,只要节点是按照存储顺序相连的,就进行一个个访问。
当遇到不相连的时候,就再找个节点作为第二起点
啥叫邻节点?就是按顺序走链表,当走到不能走的位置时候重新找一个起点。
广度优先遍历
先把某一个结点的所有结点都给访问了,然后再访问,自己邻节点的所有邻结点。
说白了就是
深度优先,和狗熊掰棒子一样,不求学的扎实,就求学的深,先学的深入,然后再一点点补。就像读历史书一样,先把上下五千年都看了,知道上下五千年大概王朝更替是什么样子,然后,一朝代一朝代补历史。
广度优先就是说白了,先从秦朝开始看,看个几十本,把秦朝看的非常了解了,然后看汉朝,在看个几十本,再往下看。
深度优先就是进攻时候,不管后方敌人,大胆穿插,玩命往里面插,
穿插完了再回过来头扫清后方敌人。
广度优先就是先扫清前后左右一切障碍,然后再推进。