最短路径问题 java实现 源代码

最短路径问题  java实现 源代码下载地址:http://download.csdn.net/source/246269

用到的资源文件  文件名 shortPath.properties

begin=/u59CB/u53D1/u5730/uFF1A
clear=/u6E05   /u9664
clearString=/u6E05/u695A/u7ED8/u56FE/u533A/u548C/u6240/u6709/u7684/u6587/u672C
drawLine=/u7ED8/u5236/u8DEF/u5F84
end=/u76EE/u7684/u5730/uFF1A
mouseLocation=/u9F20/u6807/u4F4D/u7F6E/uFF1A
nodeLine=/u7ED3/u70B9/u8FDE/u7EBF
nodeLineString=/u7ED8/u5236/u7ED3/u70B9/u5230/u7ED3/u70B9/u7684/u8DEF/u5F84/uFF08/u8FDE/u7EBF/uFF09
nodeName=/u7ED3/u70B9/u540D/u79F0
nodeNameString=/u7528/u4E8E/u8F93/u5165/u65B0/u7ED3/u70B9/u7684/u540D/u79F0
nodeNew=/u65B0/u7ED3/u70B9
nodeSpace=/u7ED3/u70B9/u8DDD/u79BB
nodeSpaceString=/u7528/u4E8E/u8F93/u5165/u7ED3/u70B9/u5230/u7ED3/u70B9/u7684/u8DEF/u5F84
nodeString=/u7ED8/u5236/u65B0/u7684/u5706/u5F62/u7ED3/u70B9
ok=/u786E   /u5B9A
okText=/u5355/u51FB /u201C/u786E/u5B9A/u201D /u6309/u94AE/u5C06/u663E/u793A/u51FA/u53D1/u5730/u5230/u76EE/u7684/u5730/u7684/u6700/u77ED/u8DEF/u5F84/uFF01
shortPath=/u6700/u77ED/u8DEF/u5F84
 

import javax.swing.UIManager;
/**
 * 类介绍:主类
 * 
 * @author 作者:liujunguang
 * @version 创建时间:2010-5-25 下午01:45:23
 */
public class ShortPath {
	public static void main(String[] args) {
		try {// 将界面设置为当前windows界面风格
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
		}
		new ShortPathFrame();
	}
}
 

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.util.Properties;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
/**
 * 类说明:ShortPath 界面类
 * 
 * @author 作者: LiuJunGuang
 * @version 创建时间:2010-5-29 下午02:15:05
 */
public class ShortPathFrame extends JFrame implements ActionListener {
	private static final long serialVersionUID = -1877582687108858783L;
	private Properties prop = null;
	private String begin = "Begin: ";// 始发地
	private String end = "End: ";// 目的地
	private String ok = "OK";// 确定键
	private String shortPath = "ShortPath";// 标题
	private String mouseLocation = "MouseLocation:";// 鼠标的位置
	private String okText = "Show Path when OK is click.";
	private JPanel nothJP = null, shouthJP = null, centerJP = null;
	private JLabel beginJLabel = null, endJLabel = null;
	private JLabel AtoBPathJLabel = null, mouseJLabel = null;
	private JComboBox beginJComboBox = null, endJComboBox = null;// 两个下拉选择框
	private JButton jButton = null;
	private JToolBar jToolBar = null;// 定义工具条
	private JButton newNodeJButton = null, nodeLineJButton = null,
			nodeNameJButton = null, nodeSpaceJButton = null,
			clearJButton = null;// 定义工具条按钮
	private DrawJPanel drawJPanel = null;// 定义中央绘制区对象
	public ShortPathFrame() {
		// TODO Auto-generated constructor stub
		properties();
		if (prop != null) {
			begin = prop.getProperty("begin");
			end = prop.getProperty("end");
			ok = prop.getProperty("ok");
			shortPath = prop.getProperty("shortPath");
			mouseLocation = prop.getProperty("mouseLocation");
			okText = prop.getProperty("okText");
		}
		this.setTitle(shortPath);
		// 始发地
		nothJP = new JPanel();
		beginJLabel = new JLabel(begin);
		nothJP.add(beginJLabel);
		beginJComboBox = new JComboBox();
		beginJComboBox.setPreferredSize(new Dimension(150, 25));
		beginJComboBox.addActionListener(this);
		nothJP.add(beginJComboBox);
		nothJP.add(new JLabel("     "));// 添加空标签使得beginJComboBox与endJLabel之间有一定的间隙
		// 目的地
		endJLabel = new JLabel(end);
		nothJP.add(endJLabel);
		endJComboBox = new JComboBox();
		endJComboBox.setPreferredSize(new Dimension(150, 25));
		endJComboBox.addActionListener(this);
		nothJP.add(endJComboBox);
		jButton = new JButton(ok);
		jButton.setToolTipText(okText);// 确定 按钮添加提示文本
		jButton.addActionListener(this);
		nothJP.add(jButton);
		// 中间绘图区
		centerJP = new JPanel();
		toolBar();
		centerJP.setLayout(new BorderLayout());
		centerJP.add(jToolBar, BorderLayout.NORTH);
		drawJPanel = new DrawJPanel(this);
		centerJP.add(drawJPanel, BorderLayout.CENTER);
		// 状态栏
		shouthJP = new JPanel();
		shouthJP.setBackground(Color.LIGHT_GRAY);
		AtoBPathJLabel = new JLabel();
		mouseJLabel = new JLabel(mouseLocation);
		shouthJP.add(mouseJLabel);
		shouthJP.add(new JLabel("      "));
		shouthJP.add(AtoBPathJLabel);
		this.add(nothJP, BorderLayout.NORTH);
		this.add(shouthJP, BorderLayout.SOUTH);
		this.add(centerJP, BorderLayout.CENTER);
		// 设置流布局的流向
		FlowLayout flowLayout = new FlowLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);
		flowLayout.setHgap(5);
		shouthJP.setLayout(flowLayout);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
		Toolkit toolkit = getToolkit();
		Dimension dim = toolkit.getScreenSize();
		this.setLocation((dim.width - 500) / 2, (dim.height - 500) / 2);
		pack();
	}
	private void setDrawType(int drawType) {// 设置要绘制的内容
		drawJPanel.setCurrentChoice(drawType);// 设置绘制内容
		drawJPanel.createNewitem();// 新建要绘制的图形
		drawJPanel.repaint();// 重新绘制绘图区
	}
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if (e.getSource() == newNodeJButton) {// 新建结点
			setAtoBPathJLabel("你选择了新建圆结点!");
			int c = drawJPanel.getCircleCount();
			drawJPanel.setCircleCount(--c);
			setDrawType(1);
		} else if (e.getSource() == nodeNameJButton) {// 结点名称
			setAtoBPathJLabel("你选择了输入圆结点的名称!");
			JOptionPane.showMessageDialog(null, "请单击结点(圆圈)以确定要输入名字的结点!", "提示",
					JOptionPane.INFORMATION_MESSAGE);
			setDrawType(2);
		} else if (e.getSource() == nodeLineJButton) {// 结点连线
			setAtoBPathJLabel("你选择了新建圆结点之间的连线!");
			int l = drawJPanel.getLineCount();
			drawJPanel.setLineCount(--l);
			setDrawType(3);
		} else if (e.getSource() == nodeSpaceJButton) {// 结点距离
			setAtoBPathJLabel("你选择了输入结点之间的距离!");
			JOptionPane.showMessageDialog(null, "请单击线段上方以确定要输入距离的线段!", "提示",
					JOptionPane.INFORMATION_MESSAGE);
			setDrawType(4);
		} else if (e.getSource() == clearJButton) {// 清除
			setDrawType(5);
		} else if (e.getSource() == jButton) {// 确定
			ShortPathALG shortPathALG = new ShortPathALG(drawJPanel);
			int x = 1, y = 2;
			try {
				x = drawJPanel.getCircleId(beginJComboBox.getSelectedItem()
						.toString());
				y = drawJPanel.getCircleId(endJComboBox.getSelectedItem()
						.toString());
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(this, "请输入结点的名称。", "警告",
						JOptionPane.WARNING_MESSAGE);
			}
			setAtoBPathJLabel(shortPathALG.disPath(x, y));// 输出最短路径
			shortPathALG.showMGraph();// 输出最短路径
		} else if (e.getSource() == beginJComboBox) {
			String string = "";
			try {
				string = beginJComboBox.getSelectedItem().toString();
			} catch (Exception e1) {
				string = "";
			}
			setAtoBPathJLabel("你选择的始发地是:" + beginJComboBox.getSelectedItem()
					+ " ,该结点下标是:" + drawJPanel.getCircleId(string));
		} else if (e.getSource() == endJComboBox) {
			String s2 = "";
			try {
				s2 = endJComboBox.getSelectedItem().toString();
			} catch (Exception e1) {
				s2 = "";
			}
			setAtoBPathJLabel("你选择的目的地是:" + endJComboBox.getSelectedItem()
					+ " ,该结点下标是:" + drawJPanel.getCircleId(s2));
		}
	}
	// 读取资源文件
	private void properties() {
		InputStream fis = null;
		try {
			fis = ShortPathFrame.class.getClassLoader().getResourceAsStream(
					"shortPath.properties");
			prop = new Properties();// 属性集合对象
			prop.load(fis);// 将属性文件流装载到Properties对象中
			fis.close();// 关闭流
		} catch (Exception e) {
			prop = null;
			JOptionPane.showMessageDialog(this, " 资源文件打开错误!", "警告",
					JOptionPane.WARNING_MESSAGE);
		}// 属性文件输入流
	}
	// 工具条的初始化
	private void toolBar() {
		jToolBar = new JToolBar(JToolBar.HORIZONTAL);
		Icon newNodeIcon = null;
		Icon nodeNameIcon = null;
		Icon nodeLineIcon = null;
		Icon nodeSpaceIcon = null;
		Icon clearIcon = null;
		try {
			newNodeIcon = new ImageIcon(getClass().getResource(
					"images/newNode.jpg"));
			nodeNameIcon = new ImageIcon(getClass().getResource(
					"images/nodeName.jpg"));
			nodeLineIcon = new ImageIcon(getClass().getResource(
					"images/nodeLine.jpg"));
			nodeSpaceIcon = new ImageIcon(getClass().getResource(
					"images/nodeSpace.jpg"));
			clearIcon = new ImageIcon(getClass()
					.getResource("images/clear.jpg"));
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, " 图片读取失败!", "警告",
					JOptionPane.WARNING_MESSAGE);
		}
		// 按钮提示文本
		String nodeString = "New a node.";
		String nodeLineString = "New a line between node and node.";
		String nodeNameString = "Put into a node name.";
		String nodeSpaceString = "Put into space between node and node.";
		String clearString = "Clear all picture and data.";
		String nodeNew = "New";
		String nodeLine = "Node Line";
		String nodeName = "Node Name";
		String nodeSpace = "Node Space";
		String clear = "Clear";
		if (prop != null) {
			nodeString = prop.getProperty("nodeString");
			nodeLineString = prop.getProperty("nodeLineString");
			nodeNameString = prop.getProperty("nodeNameString");
			nodeSpaceString = prop.getProperty("nodeSpaceString");
			clearString = prop.getProperty("clearString");
			nodeNew = prop.getProperty("nodeNew");
			nodeLine = prop.getProperty("nodeLine");
			nodeName = prop.getProperty("nodeName");
			nodeSpace = prop.getProperty("nodeSpace");
			clear = prop.getProperty("clear");
		}
		newNodeJButton = creatJButton(nodeNew, nodeString, newNodeJButton,
				newNodeIcon);
		nodeNameJButton = creatJButton(nodeName, nodeNameString,
				nodeNameJButton, nodeNameIcon);
		nodeLineJButton = creatJButton(nodeLine, nodeLineString,
				nodeLineJButton, nodeLineIcon);
		nodeSpaceJButton = creatJButton(nodeSpace, nodeSpaceString,
				nodeSpaceJButton, nodeSpaceIcon);
		clearJButton = creatJButton(clear, clearString, clearJButton, clearIcon);
	}
	// 创建工具条按钮 ,buttonName按钮要显示的文本, buttonText按钮的提示文本,
	// button按钮名称,buttonIcon 按钮图标
	public JButton creatJButton(String buttonName, String buttonText,
			JButton button, Icon buttonIcon) {
		button = new JButton(buttonName, buttonIcon);// 初始化按钮
		button.setToolTipText(buttonText);// 设置按钮提示文本
		button.setBackground(Color.orange);// 设置按钮背景颜色
		button.addActionListener(this);
		jToolBar.add(button);
		return button;
	}
	public Properties getProp() {
		return prop;
	}
	public void addItem(String s) {// 在下拉项中添加项
		this.beginJComboBox.addItem(s);
		this.endJComboBox.addItem(s);
	}
	public void removeAllItems() {// 移除下拉项中的所有项
		this.beginJComboBox.removeAllItems();
		this.endJComboBox.removeAllItems();
	}
	public void setStratBar(String s) {// 设置状态栏鼠标操作的接口
		mouseJLabel.setText(s);
	}
	public void setAtoBPathJLabel(String s) {// 设置状态栏操作的接口
		AtoBPathJLabel.setText(s);
	}
}
 

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
 * 类说明:中间界面绘图区类 (各种图形的绘制和鼠标事件)
 * 
 * @author 作者: LiuJunGuang
 * @version 创建时间:2010-5-29 下午05:29:36
 */
public class DrawJPanel extends JPanel {
	private static final long serialVersionUID = 3136876175510584357L;
	private Drawing[] itemList = new Drawing[500];// 绘制图形类
	private Drawing[] circleList = new Drawing[100];// 用于存放结点
	private Drawing[] lineList = new Drawing[100];// 用于存放线段
	private int index = 0;// 当前已经绘制的图形数目
	private Color color = Color.black;// 当前画笔的颜色
	private int f1, f2;// 用来存放当前字体的风格
	private String stytle;// 存放当前字体
	private float stroke = 2.0f;// 设置画笔的粗细 ,默认的是 1.0
	private int currentChoice = 1;// 设置默认基本图形状态为新节点
	private int circleCount = 0;// 结点计数器
	private int lineCount = 1;// 线条计数器
	ShortPathFrame shortPJF = null;
	public DrawJPanel(ShortPathFrame shortPathFrame) {
		// TODO Auto-generated constructor stub
		shortPJF = shortPathFrame;
		// 把鼠标设置成十字形
		setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		// setCursor 设置鼠标的形状 ,getPredefinedCursor()返回一个具有指定类型的光标的对象
		setBackground(Color.white);// 设置绘制区的背景是白色
		addMouseListener(new MouseA());// 添加鼠标事件
		addMouseMotionListener(new MouseB());
		createNewitem();
		this.setPreferredSize(new Dimension(400, 400));
	}
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;// 定义随笔画
		int j = 0;
		while (j <= index) {
			draw(g2d, itemList[j]);
			j++;
		}
	}
	void draw(Graphics2D g2d, Drawing i) {
		i.draw(g2d);// 将画笔传到个各类的子类中,用来完成各自的绘图
	}
	// 新建一个图形的基本单元对象的程序段
	void createNewitem() {
		if (currentChoice == 2 || currentChoice == 4)// 字体的输入光标相应的设置为文本输入格式
			setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
		else
			setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		switch (currentChoice) {
		case 3:
			itemList[index] = new Line();
			lineList[++lineCount] = itemList[index];// 线段加一
			break;
		case 1:
			itemList[index] = new Circle();// 绘制圆
			circleList[++circleCount] = itemList[index];// 结点加一
														// 并将结点的值复制到新的itemList[]对象数组中
			break;
		case 5:// 请空绘图区
			clearDrawJPanel();
			break;
		case 6:
			itemList[index] = new fillCircle();
			break;
		case 2:
		case 4:
			itemList[index] = new Word();
			break;
		}
		itemList[index].type = currentChoice;
		itemList[index].stroke = stroke;
		itemList[index].setColor(color);
	}
	private void clearDrawJPanel() {// 绘图区清空
		for (int i = 0; i <= index; i++) {
			itemList[i] = null;
		}
		shortPJF.setAtoBPathJLabel("已经清空绘图区!");
		index = 0;
		shortPJF.removeAllItems();// 移除下拉项中的所有项
		setCircleCount(1);// 设置结点个数为零
		setLineCount(1);// 设置线条个数为零
		currentChoice = 1;
		createNewitem();// 创建新的图形的基本单元对象
		repaint();
	}
	public void setColor(Color color)// 设置颜色的值
	{
		this.color = color;
	}
	public void setStroke(float f)// 设置画笔粗细的接口
	{
		stroke = f;
	}
	public void setCurrentChoice(int i)// 设置要绘制的类型
	{
		currentChoice = i;
	}
	public int getCircleCount() {// 得到结点个数
		return circleCount;
	}
	public void setCircleCount(int circleCount) {// 设置结点个数
		this.circleCount = circleCount;
	}
	public int getLineCount() {// 得到线段个数
		return lineCount;
	}
	public void setLineCount(int lineCount) {// 设置线段个数
		this.lineCount = lineCount;
	}
	public Drawing[] getCircleList() {// 得到圆结点对象数组
		return circleList;
	}
	public Drawing[] getLineList() {// 得到线段结点对象数组
		return lineList;
	}
	public int getCircleId(String circleName) {
		int id = 0;
		for (int i = 1; i < getCircleCount(); i++) {
			if (circleList[i].name.equals(circleName)) {
				id = i;
				break;
			}
		}
		return id;
	}
	// TODO 鼠标事件MouseA类继承了MouseAdapter
	// 用来完成鼠标的响应事件的操作(鼠标的按下、释放、单击、移动、拖动、何时进入一个组件、何时退出、何时滚动鼠标滚轮 )
	class MouseA extends MouseAdapter {
		int circleWhere1 = -1;// 鼠标按下的地方
		@Override
		public void mouseEntered(MouseEvent me) {
			// TODO 鼠标进入
			shortPJF
					.setStratBar("鼠标进入在:[" + me.getX() + " ," + me.getY() + "]");
		}
		@Override
		public void mouseExited(MouseEvent me) {
			// TODO 鼠标退出
			shortPJF
					.setStratBar("鼠标退出在:[" + me.getX() + " ," + me.getY() + "]");
		}
		@Override
		public void mousePressed(MouseEvent me) {
			// TODO 鼠标按下
			shortPJF
					.setStratBar("鼠标按下在:[" + me.getX() + " ," + me.getY() + "]");// 设置状态栏提示
			itemList[index].x1 = itemList[index].x2 = me.getX();
			itemList[index].y1 = itemList[index].y2 = me.getY();
			// 如果选择图形的文字输入,则进行下面的操作
			if (currentChoice == 2) {
				circleWhere1 = clickLocation(me.getX(), me.getY());
				if (circleWhere1 == -1)// 判断点击的点是否在园内
				{
					JOptionPane.showMessageDialog(shortPJF, " 请在圆内点击!", "提示",
							JOptionPane.WARNING_MESSAGE);
					return;
				}
				itemList[index].x1 = me.getX();
				itemList[index].y1 = me.getY();
				String input;
				input = JOptionPane.showInputDialog("请输入你该结点的名称!");
				circleList[circleWhere1].setName(input);
				shortPJF.setAtoBPathJLabel("你在第" + circleWhere1
						+ "圆内点击了,输入的名字是:"
						+ circleList[circleWhere1].getName());
				shortPJF.addItem(circleList[circleWhere1].getName());
				itemList[index].s1 = input;
				itemList[index].x2 = f1;
				itemList[index].y2 = f2;
				itemList[index].s2 = stytle;
				itemList[index].setColor(Color.magenta);
				index++;
				currentChoice = 2;
				createNewitem();// 创建新的图形的基本单元对象
				repaint();
			}
			if (currentChoice == 3) {
				circleWhere1 = clickLocation(me.getX(), me.getY());
				if (circleWhere1 == -1)// 判断点击的点是否在园内
				{
					JOptionPane.showMessageDialog(shortPJF,
							" 请在圆内点击,以确定线与哪个圆关联!", "提示",
							JOptionPane.WARNING_MESSAGE);
					return;
				}
				itemList[index].x1 = me.getX();
				itemList[index].y1 = me.getY();
				itemList[index].xLocation = circleWhere1;
				shortPJF.setAtoBPathJLabel("线段 " + lineCount + "的起始点在圆 "
						+ circleWhere1
						+ "内。");
			}
			if (currentChoice == 4) {
				int lineWhere = -1;
				lineWhere = lineLocation(me.getX(), me.getY());
				if (lineWhere == -1) {
					JOptionPane.showMessageDialog(shortPJF, " 请在不在园内的线段上方点击!",
							"提示", JOptionPane.WARNING_MESSAGE);
					return;
				}
				itemList[index].x1 = me.getX();
				itemList[index].y1 = me.getY();
				String input;
				input = JOptionPane.showInputDialog("请输入该线段连接的两结点的距离!");
				lineList[lineWhere].setName(input);
				shortPJF.setAtoBPathJLabel("你在第" + lineWhere
						+ "条线段上方点击了,输入的距离是:"
						+ lineList[lineWhere].getName());
				itemList[index].s1 = input;
				itemList[index].x2 = f1;
				itemList[index].y2 = f2;
				itemList[index].s2 = stytle;
				itemList[index].setColor(Color.cyan);
				index++;
				currentChoice = 4;
				createNewitem();// 创建新的图形的基本单元对象
				repaint();
			}
		}
		// 判断在那条线段中点击了
		private int lineLocation(int x0, int y0) {
			int lineWhere = -1;
			for (int i = 1; i <= lineCount; i++) {
				double d = pointToLine(lineList[i].x1, lineList[i].y1,
						lineList[i].x2, lineList[i].y2, x0, y0);// 点到线段的距离
				if (clickLocation(x0, y0) == -1 && d <= 5) {
					lineWhere = i;
					break;
				}
			}
			return lineWhere;
		}
		// 点到直线的最短距离的判断 点(x0,y0) 到由两点组成的线段(x1,y1) ,( x2,y2 )
		private double pointToLine(int x1, int y1, int x2, int y2, int x0,
				int y0) {
			double space = 0;
			double a, b, c;
			a = lineSpace(x1, y1, x2, y2);// 线段的长度
			b = lineSpace(x1, y1, x0, y0);// (x1,y1)到点的距离
			c = lineSpace(x2, y2, x0, y0);// (x2,y2)到点的距离
			if (c <= 0.000001 || b <= 0.000001) {
				space = 0;
				return space;
			}
			if (a <= 0.000001) {
				space = b;
				return space;
			}
			if (c * c >= a * a + b * b) {
				space = b;
				return space;
			}
			if (b * b >= a * a + c * c) {
				space = c;
				return space;
			}
			double p = (a + b + c) / 2;// 半周长
			double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
			space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
			return space;
		}
		// 计算两点之间的距离
		private double lineSpace(int x1, int y1, int x2, int y2) {
			double lineLength = 0;
			lineLength = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2)
					* (y1 - y2));
			return lineLength;
		}
		// 判断点击的点是否在园内
		private int clickLocation(int x, int y) {
			int where = -1;// 确定在那个园内点击了 并返回圆的下标
			int a = 0;// 圆心的横坐标
			int b = 0;// 圆心的中坐标
			int r = 0;// 圆心的半径
			for (int i = 1; i <= circleCount; i++) {
				// 确定单击的点在圆内
				a = circleList[i].xLocation + circleList[i].width / 2;// 圆心的横坐标
				b = circleList[i].yLocation + circleList[i].heigh / 2;// 圆心的中坐标
				r = circleList[i].width / 2;// 圆的半径
				if (((x - a) * (x - a) + (y - b) * (y - b)) <= r * r) {// 如果点击是在园内
					where = i;// 返回在那个园内
					break;
				}
			}
			return where;
		}
		@Override
		public void mouseReleased(MouseEvent me) {
			// TODO 鼠标松开
			shortPJF
					.setStratBar("鼠标松开在:[" + me.getX() + " ," + me.getY() + "]");
			if (currentChoice == 3) {// 绘制直线的颜色设定
				itemList[index].setColor(Color.blue);
				int circleWhere2 = clickLocation(me.getX(), me.getY());// 鼠标松开的地方
				if (circleWhere2 == -1 || circleWhere2 == circleWhere1)// 判断点击的点是否在园内
				{
					JOptionPane.showMessageDialog(shortPJF,
							" 请在圆内松开鼠标,以确定线与哪个圆关联!", "提示",
							JOptionPane.WARNING_MESSAGE);
					itemList[index].x2 = itemList[index].x1;
					itemList[index].y2 = itemList[index].y1;
					repaint();
					return;
				}
				itemList[index].yLocation = circleWhere2;
				shortPJF.setAtoBPathJLabel("线段 " + lineCount + "的终止点在圆 "
						+ circleWhere2
						+ "内。");
			}
			itemList[index].x2 = me.getX();
			itemList[index].y2 = me.getY();
			repaint();
			index++;
			createNewitem();// 创建新的图形的基本单元对象
		}
	}
	// 鼠标事件MouseB继承了MouseMotionAdapter
	// 用来处理鼠标的滚动与拖动
	class MouseB extends MouseMotionAdapter {
		public void mouseDragged(MouseEvent me)// 鼠标的拖动
		{
			shortPJF
					.setStratBar("鼠标拖动在:[" + me.getX() + " ," + me.getY() + "]");
			itemList[index].x2 = me.getX();
			itemList[index].y2 = me.getY();
			repaint();
		}
		public void mouseMoved(MouseEvent me)// 鼠标的移动
		{
			shortPJF
					.setStratBar("鼠标移动在:[" + me.getX() + " ," + me.getY() + "]");
		}
	}
}
 

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.io.Serializable;
/*类通过实现 java.io.Serializable 接口以启用其序列化功能。
 未实现此接口的类将无法使其任何状态序列化或反序列化。
 可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,
 仅用于标识可序列化的语义。*/
public class Drawing implements Serializable {
	private static final long serialVersionUID = 4945502450819201865L;
	int x1, x2, y1, y2; // 定义坐标属性
	Color color = null;// 设置颜色属性
	float stroke; // 定义线条粗细的属性
	int type; // 定义字体属性
	String s1; // 输入的字符串
	String s2; // 定义字体的风格
	int xLocation = -1;// 左上角x的坐标
	int yLocation = -1;// 左上角y的坐标
	int width = 0;// 圆的宽度
	int heigh = 0;// 圆的高度
	String name = "";// 用于存放结点的名称
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setColor(Color color) {
		this.color = color;
	}
	void draw(Graphics2D g2d) {
	}// 定义绘图函数
}
class Line extends Drawing// 直线类
{
	private static final long serialVersionUID = 4945502450819201865L;
	String lineSpace = "";// 用于存放结点与结点间的距离
	void draw(Graphics2D g2d) {
		g2d.setPaint(color);// 为 Graphics2D 上下文设置 Paint 属性。
		// 使用为 null 的 Paint 对象调用此方法对此 Graphics2D 的当前 Paint 属性没有任何影响。
		g2d.setStroke(new BasicStroke(stroke, BasicStroke.CAP_ROUND,
				BasicStroke.JOIN_BEVEL));
		// setStroke(Stroke s)为 Graphics2D 上下文设置 Stroke
		// BasicStroke 类定义针对图形图元轮廓呈现属性的一个基本集合
		// BasicStroke.CAP_ROUND使用半径等于画笔宽度一半的圆形装饰结束未封闭的子路径和虚线线段
		// BasicStroke.JOIN_BEVEL通过直线连接宽体轮廓的外角,将路径线段连接在一起。
		g2d.drawLine(x1, y1, x2, y2);// 画直线
	}
}
class Circle extends Drawing {// 圆类
	private static final long serialVersionUID = 4945502450819201865L;
	void draw(Graphics2D g2d) {
		xLocation = Math.min(x1, x2);
		yLocation = Math.min(y1, y2);
		width = Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
		heigh = Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
		g2d.setPaint(color);
		g2d.setStroke(new BasicStroke(stroke));
		g2d.drawOval(xLocation, yLocation, width, heigh);
	}
}
class fillCircle extends Drawing {// 实心圆类
	private static final long serialVersionUID = 4945502450819201865L;
	void draw(Graphics2D g2d) {
		g2d.setPaint(color);
		g2d.setStroke(new BasicStroke(stroke));
		g2d.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.max(Math.abs(x1
				- x2), Math.abs(y1 - y2)), Math.max(Math.abs(x1 - x2), Math
				.abs(y1 - y2)));
	}
}
class fillRect extends Drawing {// 实心矩形类 刷新绘图区
	private static final long serialVersionUID = 4945502450819201865L;
	void draw(Graphics2D g2d) {
		g2d.setPaint(Color.white);
		g2d.fillRect(x1, y1, x2, y2);
	}
}
class Word extends Drawing {// 输入文字类
	private static final long serialVersionUID = 4945502450819201865L;
	void draw(Graphics2D g2d) {
		g2d.setPaint(color);
		g2d.setFont(new Font(s2, x2 + y2, ((int) stroke) * 10));// 设置字体
		if (s1 != null)
			g2d.drawString(s1, x1, y1);
	}
}
 

import java.awt.Color;
import java.util.StringTokenizer;
import javax.swing.JOptionPane;
/**
 * 类说明:最短路径的算法
 * 
 * @author 作者: LiuJunGuang
 * @version 创建时间:2010-6-1 下午10:24:57
 */
public class ShortPathALG {
	private Drawing[] circleList = null;// 用于存放结点
	private Drawing[] lineList = null;// 用于存放线段
	private int mGraph[][] = null;// 用于存储图的邻接矩阵
	private int mGraphCopy[][] = null;
	private String dis = "";// 最短路径结果
	private String drawLineRed = "";// 要绘制的红线路径
	private int circleNum = 0;// 结点的个数
	private int lineNum = 0;// 线段的个数
	private DrawJPanel drawJPanel = null;
	public ShortPathALG(DrawJPanel draw) {
		drawJPanel = draw;
		// TODO 最短路径的算法 初始化 结点 和线
		circleList = drawJPanel.getCircleList();// 获得结点对象数组
		lineList = drawJPanel.getLineList();// 获得线段对象数组
		circleNum = drawJPanel.getCircleCount();// 获得结点的个数
		lineNum = drawJPanel.getLineCount();
		mGraph = new int[circleNum][circleNum];// 为邻接矩阵分配空间 0行 、0列 不用
		for (int i = 0; i < circleNum; i++) {// 初始化邻接矩阵 全赋值为 -1 (距离不可能是负数)
			for (int j = 0; j < circleNum; j++) {
				if (i == j)
					mGraph[i][j] = 0;
				else {
					mGraph[i][j] = 32767;
				}
			}
		}
		changeLineColor();// 初始化线条的颜色
		mGraphInitialize();// 初始化邻接矩阵
		path_FLOYD(getmGraphCopy());
	}
	// 初始化线条的颜色
	private void changeLineColor() {
		for (int i = 1; i < lineNum; i++) {
			lineList[i].setColor(Color.blue);
			}
		drawJPanel.repaint();
	}
	// 初始化邻接矩阵
	public void mGraphInitialize() {
		for (int i = 1; i < lineNum; i++) {// 循环遍历线条的起点与终点
			int m = 32767;
			try{
				m= Integer.parseInt(lineList[i].name);//如果输入的距离不能转换成整形 默认距离是1 
			}catch(Exception e) {
				m = 1;
			}
			// 构建无向图
			if (lineList[i].name.equals(""))
				m = 1;
			mGraph[lineList[i].xLocation][lineList[i].yLocation] = m;
			mGraph[lineList[i].yLocation][lineList[i].xLocation] = m;
		}
	}
	// 输出邻接矩阵
	public void showMGraph() {
		String s = "最短路径的邻接矩阵是(无向图):/n";
		for (int i = 1; i < circleNum; i++) {
			if (!circleList[i].name.equals("")) {
				s = s + circleList[i].name + "   ";
			} else {
				s = s + i + "   ";
			}
		}
		s = s + "/n";
		for (int i = 1; i < circleNum; i++) {
			for (int j = 1; j < circleNum; j++) {
				s = s + mGraph[i][j] + "   ";
			}
			s = s + "/n";
		}
		s = dis;
		lineColor();// 修改路径的颜色
		JOptionPane.showMessageDialog(drawJPanel, s, "最短路径",
				JOptionPane.PLAIN_MESSAGE);
	}
	// 修改路径的颜色
	private void lineColor() {// 修改路径的颜色
		int gv[];// 存放线段顶点
		int i = 1;
		StringTokenizer tokenizer = new StringTokenizer(drawLineRed, "-->");
		gv = new int[tokenizer.countTokens() + 1];// 动态的决定数组的长度
		while (tokenizer.hasMoreTokens()) {
			String d = tokenizer.nextToken();
			gv[i] = Integer.valueOf(d);// 将字符串转换为整型
			i++;
		}
		for (int j = 1; j < gv.length - 1; j++) {
			for (i = 1; i < lineNum; i++) {
				boolean x = lineList[i].xLocation == gv[j]
						&& lineList[i].yLocation == gv[j + 1];
				boolean y = lineList[i].yLocation == gv[j]
						&& lineList[i].xLocation == gv[j + 1];
				if (x || y) {
					lineList[i].setColor(Color.red);
				}
			}
		}
		drawJPanel.repaint();
	}
	// 最短路径算法FLOYD 算法
	int D[][] = null;// D存放每对顶点之间的最短路径值
	int path[][] = null;// p存放每对顶点之间的最短路径
	int length = 0;
	public void path_FLOYD(int data[][]) {
		int i, j, k;
		length = data.length;
		D = new int[length][length];// D存放每对顶点之间的最短路径值
		path = new int[length][length];// p存放每对顶点之间的最短路径
		for (i = 1; i < length; i++) {// 各节点之间的初始已知路径及距离
			for (j = 1; j < length; j++) {
				D[i][j] = data[i][j];//
				path[i][j]= -1;
			}
		}// for
		for (k = 1; k < length; k++) {
			for (i = 1; i < length; i++) {
				for (j = 1; j < length; j++) {
					if (i == j)// 对角线上的元素(即顶点自身之间)不予考虑
						continue;
					if (D[i][k] + D[k][j] < D[i][j]) {// 从i经k到j的一条路径更短
						D[i][j] = D[i][k] + D[k][j];
						path[i][j]=k;
					}
				}
			}
		}
	}
	// 最短路径输出
	public String disPath(int i, int j) {
		// TODO Auto-generated method stub
		boolean c1Name = !circleList[i].name.equals("");
		boolean c2Name = !circleList[j].name.equals("");
		if (D[i][j] == 32767) {
			if (i != j) {
				if (c1Name) {
					dis = "从" + circleList[i].name + "到";
				} else {
					dis = "从" + i + "到";
				}
				if (c2Name) {
					dis += circleList[j].name + "没有路径/n";
				} else {
					dis += j + "没有路径/n";
				}
			}
		} else {
			if (c1Name) {
				dis = "从" + circleList[i].name + "到";
			} else
				dis = "从" + i + "到";
			if (c2Name) {
				dis += circleList[j].name + "路径为: ";
			} else
				dis += j + "路径为: ";
			if (c1Name) {
				dis += circleList[i].name + "-->";
			} else
				dis += i + "-->";
			if (c2Name) {
				dis += ppath(i, j) + circleList[j].name + "     /n路径长度为: "
						+ D[i][j]
						+ "/n";
			} else {
				dis += ppath(i, j) + j + "       /n路径长度为:" + D[i][j] + "/n";
			}
			drawLineRed = i + "-->" + lineString + j;
		}
		return dis;
	}
	String s = "";// 存放路径
	String lineString = "";// 划红线的路径
	private String ppath(int i, int j) {
		int k;
		k = path[i][j];
		if (k == -1)
			return s;
		ppath(i, k);
		if (!circleList[k].name.equals("")) {
			s = s + circleList[k].name + "-->";
		} else {
			s = s + k + "-->";
		}
		lineString += k + "-->";
		ppath(k, j);
		return s;
	}
	// 得到邻接矩阵对象的副本
	public int[][] getmGraphCopy() {
		mGraphCopy = new int[mGraph.length][mGraph.length];
		for (int i = 0; i < mGraph.length; i++)
			for (int j = 0; j < mGraph.length; j++)
				mGraphCopy[i][j] = mGraph[i][j];
		return mGraphCopy;
	}
}
 

要用到的图片 请将图片放在images文件夹下

clear.jpgnewNode.jpgnodeLine.jpgnodeName.jpgnodeSpace.jpg

转载于:https://my.oschina.net/java2010/blog/356491

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用分支界限法解决单源最路径问题Java代码示例: ```java import java.util.Arrays; import java.util.PriorityQueue; class Node implements Comparable<Node> { int id; int dist; public Node(int id, int dist) { this.id = id; this.dist = dist; } @Override public int compareTo(Node o) { return Integer.compare(this.dist, o.dist); } } public class ShortestPath { static final int INF = Integer.MAX_VALUE; static int[][] graph; static int[] dist; static boolean[] visited; public static void main(String[] args) { int n = 5; // 节点数 int m = 7; // 边数 int source = 0; // 源节点 // 构建邻接矩阵 graph = new int[n][n]; for (int[] row : graph) { Arrays.fill(row, INF); } graph[0][1] = 10; graph[0][3] = 30; graph[0][4] = 100; graph[1][2] = 50; graph[2][4] = 10; graph[3][2] = 20; graph[3][4] = 60; // 初始化距离数组和访问标记数组 dist = new int[n]; visited = new boolean[n]; Arrays.fill(dist, INF); dist[source] = 0; // 初始化优先队列 PriorityQueue<Node> pq = new PriorityQueue<>(); pq.add(new Node(source, 0)); // 分支界限法求解最路径 while (!pq.isEmpty()) { Node node = pq.poll(); int u = node.id; if (visited[u]) { continue; } visited[u] = true; for (int v = 0; v < n; v++) { if (graph[u][v] != INF && dist[v] > dist[u] + graph[u][v]) { dist[v] = dist[u] + graph[u][v]; pq.add(new Node(v, dist[v])); } } } // 输出结果 for (int i = 0; i < n; i++) { System.out.printf("Shortest distance from %d to %d is %d\n", source, i, dist[i]); } } } ``` 在上面的代码中,我们首先构建了一个邻接矩阵表示的图,然后使用分支界限法求解最路径问题,最后输出了每个节点到源节点的最距离。在实际应用中,我们可以根据需要对代码进行修改和优化,以适应不同的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值