一、什么是广度优先遍历?
广度优先遍历又称为层次遍历,从上倒下从左到右一层一层进行遍历,直至全部元素被访问.
二、原理
1、使用队列将当前层所有元素入列,当前层遍历完成后,从队列中取出元素,遍历该元素下一层
2、重复步骤1,直至全部元素遍历结束
三、代码实现
代码如下(示例):
/**
* 广度优先遍历
*/
public class Test {
/**
* 端点数组
*/
private static final String[] ENDPOINT;
/**
* 边二维数组
*/
private static final Integer[][] SIDE_ARRAY;
/**
* 判断俩顶点是否存在边
*/
private static final Integer SIDE_FLAG = 1;
/**
* 未被访问的顶点map
*/
private static final Map<Integer, String> NOT_VISITED_ENDPOINT_MAP;
/**
* map table最大数
*/
private static final int MAXIMUM_CAPACITY = 1 << 30;
static {
ENDPOINT = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
NOT_VISITED_ENDPOINT_MAP = new HashMap<>(calculateMapSize(ENDPOINT.length));
for (int i = 0; i < ENDPOINT.length; i++) {
NOT_VISITED_ENDPOINT_MAP.put(i, ENDPOINT[i]);
}
SIDE_ARRAY = new Integer[ENDPOINT.length][ENDPOINT.length];
for (int i = 0; i < ENDPOINT.length; i++) {
for (int j = 0; j < ENDPOINT.length; j++) {
SIDE_ARRAY[i][j] = 0;
}
}
// A-B有边
SIDE_ARRAY[0][1] = 1;
SIDE_ARRAY[1][0] = 1;
// A-D有边
SIDE_ARRAY[0][3] = 1;
SIDE_ARRAY[3][0] = 1;
// A-F有边
SIDE_ARRAY[0][5] = 1;
SIDE_ARRAY[5][0] = 1;
// B-E有边
SIDE_ARRAY[1][4] = 1;
SIDE_ARRAY[4][1] = 1;
// B-C有边
SIDE_ARRAY[1][2] = 1;
SIDE_ARRAY[2][1] = 1;
// C-D有边
SIDE_ARRAY[2][3] = 1;
SIDE_ARRAY[3][2] = 1;
// F-H有边
SIDE_ARRAY[5][7] = 1;
SIDE_ARRAY[7][5] = 1;
// F-G有边
SIDE_ARRAY[5][6] = 1;
SIDE_ARRAY[6][5] = 1;
}
public static void main(String[] args) {
//随机选择起点、终点
Random random = new Random();
int startEndPoint = random.nextInt(ENDPOINT.length - 1);
int endEndPoint = random.nextInt(ENDPOINT.length - 1);
while(startEndPoint == endEndPoint){
endEndPoint = random.nextInt(ENDPOINT.length - 1);
}
String vertex = ENDPOINT[startEndPoint];
String target = ENDPOINT[endEndPoint];
System.out.println("顶点:" + vertex + ",目标顶点:" + target);
System.out.println("开始广度优先遍历搜索目标!");
Queue<Integer> queue = new ArrayBlockingQueue<>(ENDPOINT.length);
NOT_VISITED_ENDPOINT_MAP.remove(startEndPoint);
search(startEndPoint, target, NOT_VISITED_ENDPOINT_MAP, queue);
System.out.println("开始广度优先遍历搜索!");
for (int i = 0; i < ENDPOINT.length; i++) {
NOT_VISITED_ENDPOINT_MAP.put(i, ENDPOINT[i]);
}
queue = new ArrayBlockingQueue<>(ENDPOINT.length);
NOT_VISITED_ENDPOINT_MAP.remove(startEndPoint);
search(startEndPoint, null, NOT_VISITED_ENDPOINT_MAP, queue);
}
private static void search(int vertex, String target, Map<Integer, String> notVisitedEndPointMap, Queue<Integer> queue) {
int i = vertex;
while (!notVisitedEndPointMap.isEmpty()) {
Iterator<Integer> it = notVisitedEndPointMap.keySet().iterator();
// 遍历 i下一层元素
while (it.hasNext()) {
int j = it.next();
int endPointSide = SIDE_ARRAY[i][j];
if (endPointSide == SIDE_FLAG) {
if (ENDPOINT[j].equals(target)) {
System.out.println("找到目标端点:" + ENDPOINT[j]);
return;
}
System.out.println("端点:" + ENDPOINT[j]);
it.remove();
queue.add(j);
}
}
if (queue.isEmpty()) {
continue;
}
// 取出队列元素
int temp = queue.poll();
i = temp;
if (!notVisitedEndPointMap.isEmpty()) {
System.out.println("开始遍历端点:" + ENDPOINT[i] + "下一层元素!");
}
}
}
/**
* 计算map最大不用扩容的siz大小
*
* @param cap
* @return
*/
private static int calculateMapSize(int cap) {
int maxTableSize = tableSizeFor(cap);
float size = (float) maxTableSize * 0.75f;
if (size < cap) {
maxTableSize = maxTableSize << 1;
}
if (maxTableSize > MAXIMUM_CAPACITY) {
maxTableSize = MAXIMUM_CAPACITY;
}
System.out.println("map容量为:" + maxTableSize);
return maxTableSize;
}
/**
* 获取大于等于cap的最小2次方数
*
* @param cap
* @return
*/
private static int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
}
总结
本文简单介绍了一下,广度优先遍历原理及代码实现,如有误请告知,谢谢!