java 汉米尔顿回路_哈密顿回路分支限界遍历法

该博客介绍了使用Java实现汉米尔顿回路的分支限界遍历法。通过一个名为Calculate的类,包含了计算路径、记录最优路径、更新最优路径长度等方法。核心递归方法show()进行层次遍历,利用lengthOf()计算路径长度。博客还探讨了链表和数组在不同节点数下的性能对比,并提出在Java中由于数组会检查下标越界,性能可能不如C++。
摘要由CSDN通过智能技术生成

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++来实现,可能性能会更好一些.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值