package com.jiang.hamilton2;
public class Calculate {
// public LinkedList elem = new LinkedList();//
// 存放结点(结点均为int型从0开始)
public int[] elem;
// 经测试,当节点数小于19时,数组的效率要快于链表
public int depth = Matrix.data.length;// 数组(放图的邻接矩阵)的长度即将要遍历的总深度
public int currentDepth = 0;// 放当前正在遍历的深度(层次)
public int count = 0;// 记录总共计算过的 从根到叶子的 所有路径数
// public LinkedList best = null;// 存放当前最优路径
public int[] best;
public int leastLength = 0x7fffffff;// 存放当前最优路径(回路)的长度 缺省为一个最大的int型
private int currentLength = 0;// 用于存放从根节点到当前结点的长度,用于同leastLength比较以实现分支限界法
/**
* 构造函数 根据节点个数,建立一条链表,按照用自然数标记每个节点的序号,依次增1 在把所有节点放入链表后,最终要添加一个 0
* 节点,此处假设哈密顿回路从 0开始,这样便于计算最后一个节点到出发节点的长度
*/
public Calculate() {
elem = new int[Matrix.data.length + 1];
best = new int[Matrix.data.length + 1];
for (int i = 0; i < Matrix.data.length; i++) {
elem[i] = i;
}
elem[elem.length - 1] = 0;
replace();
}
/**
* 核心递归方法 没有形参,但是通过各个实例变量 控制递归的层次以及判断结束的条件
*
* 主要思路: 成员变量thisLength暂存父节点到自身节点的距离,加到currentLength上, 如果currentLength已经
* 大于最优路径长度,返回; 如果小于则判断是否是最深层,即是否将所有点都遍历了一遍,如果是,则把最后一个
* 节点到出发节点的长度finalLength加到currentLength,之后判断currentLength和 leastLength的关系.
* 如果不属于以上两种情况,那就是普通的节点,记录好各个变量,进行循环
*/
public void show() {
currentDepth++;// 进入方法,首先标记层次加1
int thisLength = 0;
if (currentLength >= leastLength) {// 分支限界,如果当前
} else if (currentDepth == depth) {// 如果已经遍历过所有节点,并且当前路径还没有超过最优,则进行最后的计算
count++;
int finalLength = lengthOf(elem, currentDepth - 1, currentDepth);
currentLength += finalLength;
if (currentLength < leastLength) {// 替换掉当前最优路径
leastLength = currentLength;
replace();
//displayArray(elem);
//System.out.print('\t' + currentLength + "\n");
}
currentLength -= finalLength;
}
for (int i = currentDepth; i < depth; i++) {
// elem.add(depth - 1, elem.remove(currentDepth));
curl(elem, currentDepth);
thisLength = lengthOf(elem, currentDepth - 1, currentDepth);
currentLength += thisLength;// 同currentDepth的+-
show();
currentLength -= thisLength;
}
currentDepth--;// 退出方法,要标记层次减1
}
/**
* 计算链表中 第offset到第end之间,节点的距离
*
* @param ll
* 要计算的链表对象
* @param offset
* 进行计算的起始位置
* @param end
* 进行计算的结束位置
* @return 查Matrix.data 返回结果
*/
public int lengthOf(int[] array, int offset, int end) {
int length = 0;
for (int i = offset; i < end; i++) {
length += Matrix.data[array[i]][array[i + 1]];
}
return length;
}
public void replace() {
for (int i = 0; i < elem.length; i++) {
best[i] = elem[i];
}
}
void curl(int[] array, int index) {
int a = array[index];
for (int i = index + 1; i < array.length - 1; i++) {
array[i - 1] = array[i];
}
array[array.length - 2] = a;
}
void displayArray(int[] array) {
System.out.print('[');
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + ((i == array.length - 1) ? "" : ","));
}
System.out.print(']');
}
}// /:~
另外,为了方便测试,并使测试更贴近实际节点间的距离,采用如下方式生成节点
package com.jiang.hamilton2;
import java.util.Random;
import javax.swing.JOptionPane;
public class Matrix {
private static Random random = new Random();
public static int data[][] = { { 0x7fffffff, 15, 30, 20, 25, 60 },
{ 15, 0x7fffffff, 10, 35, 45, 60 },
{ 30, 10, 0x7fffffff, 40, 55, 60 },
{ 20, 35, 40, 0x7fffffff, 50, 60 },
{ 25, 45, 55, 50, 0x7fffffff, 60 },
{ 60, 60, 60, 60, 60, 0x7fffffff } };
static class Point {
public int x;
public int y;
Point() {
x = (random.nextInt(19) + 1) * 5;
y = (random.nextInt(19) + 1) * 5;
}
}
private static int distanceBetween(Point a, Point b) {
return (int) Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y)
* (a.y - b.y));
}
public static void generate(int size) {
data = new int[size][size];
Point points[] = new Point[size];
for (int i = 0; i < size; i++) {
points[i] = new Point();
}
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == i) {
data[i][j] = 0x7fffffff;
} else if (j > i) {
data[i][j] = distanceBetween(points[i], points[j]);
} else if (j < i) {
data[i][j] = data[j][i];
}
}
}
//for (int i = 0; i < size; i++) {
//for (int j = 0; j < size; j++) {
//
//System.out.print(data[i][j] == 0x7fffffff ? "MAX\t" : data[i][j]
//+ "\t");
//}
//System.out.println();
//}
}
public static void generate() {
int size = Integer.parseInt(JOptionPane.showInputDialog("输入数组大小"));
generate(size);
}
}// /:~
经测试,采用linkedlist,
节点数:时间(s)
5:0.015
6:0.016
7:0.015
8:0.047
9:0.031
10:0.156
11:1.453
12:15
13:185
14:2446
而采用数组
节点数:时间(s)
12:4.6
13:54.6
14:739
15:9895
总结:
java中数组要比c++复杂,会判断下标越界异常,如果换成C++来实现,可能性能会更好一些.