深度和广度优先搜索:如何找出社交网络中的三度好友关系

深度和广度优先搜索:如何找出社交网络中的三度好友关系

什么是“搜索”算法?

深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构的,图这种数据结构表达能力很强,大部分设计搜索的场景都可以抽象成“图”

在图中找出从一个顶点出发,到另一个顶点的路径。方法有很多,比如深度优先、广度优先,还有A* , IDA*等启发式搜索算法,用邻接表来存储图

public class Graph{   //无向图
	private int v;    //顶点的个数
	private LinkedList<Integer> adj[];  //邻接表
	
	public Graph(int v){
		this.v = v;
		adj = new LinkedList[v];
		for(int i = 0 ; i < v ; ++i){
			adj[i] = new LinkedList<>();
		}
	}
	
	public void addEdge(int s ,int t){   //无向图一条边存两次
		adj[s] .add(t);
		adj[t].add(s);
	}
}

广度优先搜索 BFS

先查找离起始顶点最近的,然后是次近的,依次向外搜索

s表示起始顶点,t是终止顶点,搜索一条从s到t的路径,即就是从s到t的最短路径

visited是用来记录已经被访问的顶点,用来避免顶点被重复访问,如果顶点q被访问,相应的visited[q]被设置为true

quene是一个队列,用来存储已经被访问、但是相连的顶点还没有被访问的顶点。因为广度优先搜索是逐层访问的,只有把第k层的顶点都访问完成之后,才能访问第k+1层的顶点,当我们访问到第K层的顶点的时候,需要先把第K层的顶点记录下来,才能通过第K层的顶点来找第K+1层的顶点

prev记录搜索路径,当我们从顶点s开始,广度优先搜索到顶点t,prev数组中存储的是路径,不过这个路径是反向存储的,prev[w]存储的是顶点w是从哪个前驱顶点遍历过来的,比如,我们通过顶点2的邻接表访问到顶点3,那个prev[3] = 2

public void bfs(int s ,int  t){
	if(s == t ) return;
	boolean[] visited = new boolean[v];
	visited[s] = true;
	Quene<Integer> quene = new LinkedList<>();
	quene.add(s);
	int[] prev = new int[v];
	for(int i = 0 ;i < v ;++i){
		prev[i] = -1;
	}
	while(quene.size() != 0){
		int w = quene.poll();
		for(int i = 0 ;i < adj[w].size();++i){
			int q = adj[w].get(i);
			if(!visited[q]){
				prev[q] = w;
				if(q==t){
					print(prev,s,t);
					return;
				}
				visited[q] =true;
				quene.add(q);
			}
		}
	}
}

private void print(int[] prev ,int s ,int  t ){        //递归打印s->t 的路径
	if(prev[t] != -1  && t!= s){
		print(prev,s,prev[t]);
	}
	System.out.print(t+" ");
}

时间复杂度是O(V)

深度优先搜索 DFS

深度优先搜索找出来的路径并不是最短路径,实际上,用的是回溯思想,用递归实现

found这个特殊的变量,作用是当我们已经找到终止顶点t之后,我们就不再递归继续查找了

boolean found = false;  //全局变量或者类成员变量

public void dfs(int s ,int  t){
	found = false;
	boolean[] visited = new boolean[v];
	int[] prev = new int[v];
	for(int i =0;i < v;++i){
		prev[i] = -1;
	}
	recurDfs(s,t,visited,prev);
	print(prev,s,t);
}

private void recurDfs(int w,int t ,boolean[] visited,int[] prev){
	if(found == true) return;
	visited[w] = true;
	if(w == t){
		found = true;
		return;
	}
	for(int i = 0 ;i < adj[w].size();++i){
		int q = adj[w].get(i);
		if(!visited[q]){
			prev[q] = w ;
			recurDfs(q,t,visited,prev);
		}
	}
}

每条边最多被反问两次,一次是遍历,一次是回复,所以时间复杂度是O(E),E是边的个数

如何找出社交网络上某个用户的三度好友关系?

用广度优先搜索算法,首先,遍历与起始顶点最近的一层顶点,也就是一度好友,然后再遍历与用户距离的边数为2的顶点,二度好友关系,以及边数为3的顶点,就是三度好友关系

发布了76 篇原创文章 · 获赞 9 · 访问量 9189

猜你喜欢

转载自blog.csdn.net/ywangjiyl/article/details/104448392