提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
该代码为笔者算法课堂作业,要求实现BFS算法,并在UI界面上显示出来,笔者基于JAVA语言完成该任务,初始界面截图:
选择好两个地点后点击查询按钮截图:
实现思路及代码
1.绘制地图
先绘制一个简略版地图,笔者使用的是powerpoint,上面有一些好用的绘制工具,能满足简单的地图绘制要求
2.BFS算法部分
BFS全称为广度优先算法,CSDN上许多文章都有讲,这里不作赘述,首先在控制台能实现该算法,因为地点数目不大这里笔者使用的是邻接矩阵,如果地点数目庞大需要使用邻接链表
代码如下:
import java.util.*;
public class BFS {
public static int[] edgeTo = new int[13];
public static boolean[] marked = new boolean[13];
public static int s;
public static void bfsMethod(int[][] adjMatrix, int sourceNode){
//利用队列
Queue<Integer> queue = new LinkedList<Integer>();
int numOfNodes = adjMatrix[sourceNode].length;
int[] isVisited = new int[numOfNodes];//没访问过的初始化为0
s = sourceNode;
isVisited[sourceNode] = 1;
queue.add(sourceNode);
int i = 0;
int element = 0;
marked[i] = true;
while(!queue.isEmpty()){
element = queue.remove();
System.out.print(element+" ");
i = 0;
while(i < numOfNodes){
if(adjMatrix[element][i] == 1 && isVisited[i] == 0){
queue.add(i);//按照最先遍历到的1进入队列为原则, 如果有好几个1在一行,也就是一个顶点与多个顶点相连
isVisited[i] = 1;
edgeTo[i] = element; //如果想要到i节点可以走element节点
marked[i] = true;
}
i++;
}
}
}
public static boolean hasPath(int v){
return marked[v];
}
public static Iterable<Integer> pathTo(int v){
if(!hasPath(v))
return null;
Stack<Integer> path = new Stack<Integer>();
for(int x=v; x!=s; x=edgeTo[x]) //不停地往上一个节点找
path.push(x);
path.push(s);
return path;
}
/*
public static void main(String[] args){
//0 1 2 3 4 5 6 7 8 9 10 11 12
int[][] adjMatrix = {{0,1,0,1,0,0,0,0,0,0,0,0,0}, //0
{1,0,0,0,1,1,0,0,0,0,0,0,0}, //1
{0,0,0,1,0,0,1,1,0,0,0,0,0}, //2
{1,0,1,0,0,0,0,1,0,0,0,0,0}, //3
{0,1,0,0,0,1,0,0,0,0,0,0,0}, //4
{0,1,0,0,1,0,1,0,1,0,0,0,0}, //5
{0,0,1,0,0,1,0,0,1,0,0,0,0}, //6
{0,0,1,1,0,0,0,0,0,1,1,0,0}, //7
{0,0,0,0,0,1,1,0,0,1,0,1,0}, //8
{0,0,0,0,0,0,0,1,1,0,0,1,1}, //9
{0,0,0,0,0,0,0,1,0,0,0,0,1}, //10
{0,0,0,0,0,0,0,0,1,1,0,0,1}, //11
{0,0,0,0,0,0,0,0,0,1,1,1,0}}; //12
System.out.println("图的广度优先遍历(BFS)结果为(从0开始编号):");
bfsMethod(adjMatrix, 0);
System.out.println();
Iterable<Integer> temp = pathTo(4);
Iterator<Integer> iterator = temp.iterator();
LinkedList<Integer> test = new LinkedList<>();
while (iterator.hasNext()) {
int x = iterator.next();
test.add(x);
}
System.out.println(pathTo(4));
}
*/
}
Tools类的作用是提供一个“路径”链表存放信息以便于UI界面的绘制,并在该类中调用BFS搜索算法
代码如下:
import java.util.Iterator;
import java.util.LinkedList;
public class Tools {
//0 1 2 3 4 5 6 7 8 9 10 11 12
public static int[][] adjMatrix = {{0,1,0,1,0,0,0,0,0,0,0,0,0}, //0
{1,0,0,0,1,1,0,0,0,0,0,0,0}, //1
{0,0,0,1,0,0,1,1,0,0,0,0,0}, //2
{1,0,1,0,0,0,0,1,0,0,0,0,0}, //3
{0,1,0,0,0,1,0,0,0,0,0,0,0}, //4
{0,1,0,0,1,0,1,0,1,0,0,0,0}, //5
{0,0,1,0,0,1,0,0,1,0,0,0,0}, //6
{0,0,1,1,0,0,0,0,0,1,1,0,0}, //7
{0,0,0,0,0,1,1,0,0,1,0,1,0}, //8
{0,0,0,0,0,0,0,1,1,0,0,1,1}, //9
{0,0,0,0,0,0,0,1,0,0,0,0,1}, //10
{0,0,0,0,0,0,0,0,1,1,0,0,1}, //11
{0,0,0,0,0,0,0,0,0,1,1,1,0}}; //12
//全局链表用于存放路径信息
public static LinkedList<Integer> list = new LinkedList<>();
public static void search(int source, int target){
BFS.bfsMethod(adjMatrix, source);
Iterable<Integer> temp = BFS.pathTo(target);
Iterator<Integer> iterator = temp.iterator();
while (iterator.hasNext()) {
int x = iterator.next();
list.add(x);
}
System.out.println(BFS.pathTo(target));
}
}
3.UI界面
笔者使用的是Eclipse中的windowbuilder插件,为控件加上需要的监听器,其中refresh类是为了刷新路径的显示,图片中地点的坐标需要调试
代码如下:
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GUI {
public JFrame jf;
public static JPanel drawJP;
public JPanel toolJP;
public JLabel jlpic = new JLabel();
JPanel jPanel = new JPanel();
JFrame jframe = new JFrame();
static JComboBox comboBoxFrom = new JComboBox();
static JComboBox comboBoxTo = new JComboBox();
public void showUI() {
// new一个JFrame窗体
jf = new JFrame("路线查询");
// 设置窗体大小
jf.setSize(600,600);
// 设置窗体的布局为边界布局,分为东南西北中五个方位,可以将组件添加到指定的地方
jf.setLayout(new BorderLayout());
// 设置窗体居中显示
jf.setLocationRelativeTo(null);
// 给窗体设置退出按钮 关掉即退出程序
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// new一个区域JPanel
drawJP = new JPanel();
ImageIcon icon = new ImageIcon(getClass().getResource("MAP.jpg"));
jlpic.setIcon(icon);
drawJP.add(jlpic);
jf.add(drawJP);
jf.pack();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 定制操作模块
toolJP = new JPanel();
toolJP.setBackground(Color.WHITE);
// 除了窗体使用setSize(),其他组件的大小设置都需要使用setPreferredSize()方法
toolJP.setPreferredSize(new Dimension(0,70));
jf.add(toolJP, BorderLayout.SOUTH);
comboBoxTo.setModel(new DefaultComboBoxModel(new String[] {"西门","校医院","食堂",
"西苑","美术楼","体育馆","图书馆","教学楼","运动场","实验楼","南门","东苑","音乐楼"}));
comboBoxTo.setPreferredSize(new Dimension(80,30));
toolJP.add(comboBoxTo);
comboBoxFrom.setModel(new DefaultComboBoxModel(new String[] {"西门","校医院","食堂",
"西苑","美术楼","体育馆","图书馆","教学楼","运动场","实验楼","南门","东苑","音乐楼"}));
comboBoxFrom.setPreferredSize(new Dimension(80,30));
toolJP.add(comboBoxFrom);
//查询按钮
JButton jbt = new JButton("查询");
jbt.setPreferredSize(new Dimension(80,30));
toolJP.add(jbt);
//按钮监听事件
btnListener check = new btnListener();
jbt.addActionListener(check);
//清除按钮
JButton jbtClear = new JButton("清除");
jbtClear.setPreferredSize(new Dimension(80,30));
toolJP.add(jbtClear);
//按钮监听事件
btnListenerClear clear = new btnListenerClear();
jbtClear.addActionListener(clear);
// 设置窗体为可见,不然看不见窗体以及窗体中的内容
jf.setVisible(true);
}
}
//查询事件
class btnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("查询事件");
refresh.draw();
}
}
//清除事件
class btnListenerClear implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("清除事件");
refresh.clear();
}
}
//刷新界面
class refresh extends GUI{
private static int[][] location = {{0,130,220},
{1,400,100},
{2,380,250},
{3,240,400},
{4,630,50},
{5,630,150},
{6,630,275},
{7,450,385},
{8,890,205},
{9,870,385},
{10,625,525},
{11,1135,350},
{12,870,470}};
public static void draw(){
Tools.search(comboBoxTo.getSelectedIndex(),comboBoxFrom.getSelectedIndex());
drawRoad();
}
public static void clear(){
drawJP.repaint();
Tools.list.clear();
}
public static void drawRoad(){
Graphics g = drawJP.getGraphics();
g.setColor(Color.red);
int head = Tools.list.poll();
int len = Tools.list.size();
for(int i=0; i<len; i++){
int tail = Tools.list.peek();
g.drawLine(location[head][1],location[head][2], location[tail][1],location[tail][2]);
head = Tools.list.poll();
}
}
}
4.main函数
代码如下:
/*
* 广度优先搜索算法BFS
*/
public class App {
public static void main(String[] args) throws Exception {
GUI ui = new GUI();
ui.showUI();
}
}