您的位置:首页 > 产品设计 > UI/UE

【算法】欧拉图,欧拉回路,Eular Circuit,随机生成欧拉图,搜索欧拉回路

2008-10-23 16:33 393 查看
背景:图论起源于18世纪,1736年瑞士数学家欧拉(Eular)发表了图论的第一篇论文“哥尼斯堡七桥问题”。在当时的哥尼斯堡城有一条横贯全市的普雷格尔河,河中的两个岛与两岸用七座桥联结起来,见图(1)。当时那里的居民热衷于一个难题:游人怎样不重复地走遍七桥,最后回到出发点。

欧拉回路
package eulercircuit;

/*
filename:EularCircuit.java
author:gaoshangshang
version:0.9
date:2008-10-22
run environment:jdk 1.4
description: 随机生成欧拉图,稀疏图 邻接表表示 复杂度O(|E|+|V|)
算法描述:先对欧拉图执行一次深度优先搜索,找到第一个回路,此时,
仍有部分边未被访问,则找出有尚未访问的边的路径上的第一个顶点,
执行另外一次DFS,得到另外一个回路,然后把第二个回路拼接在第一
个回路上,继续该过程,直到所有的边都被遍历。
*/

import java.io.*;
import java.util.*;

publicclass EularCircuit {
public EularCircuit() {
}

publicstaticvoid main(String[] args) {
System.out.println("please input n:");
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
int n =4;
try {
n = Integer.parseInt(br.readLine());
}
catch (Exception ex) {
return;
}
try {
Graph g =new Graph(n);
g.printg();
g.circuit();
}
catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return;
}
}
}

class Node {
//该变量纯粹为了便于给顶点默认命名,在此程序中无特殊用途
privatestaticint count =0;
private String name;
//该顶点的邻接表,里面存储的是SNode,内含该顶点邻接的顶点在图的顶点列表中的index和该边是否被访问
private ArrayList adjacencyList;

public Node() {
name ="node "+ count;
adjacencyList =new ArrayList();
}

public Node(String name) {
this.name = name;
adjacencyList =new ArrayList();
}

//该函数用于测试本顶点的所有边是否都已经被访问,本程序未用
publicboolean isAllVisited() {
for (int i =0; i < adjacencyList.size(); i++) {
SNode sn = (SNode) adjacencyList.get(i);
if (sn.visited ==false) {
returnfalse;
}
}
returntrue;
}

//返回该结点的邻接点的个数
publicint getAdjacencyCount() {
return adjacencyList.size();
}

//用于测试图中的index为i的顶点是否在本顶点的邻接表中
publicboolean contains(int i) {
returnthis.adjacencyList.contains(new SNode(i));
}

//删除本顶点的一个邻接点,该点的index为i
publicvoid removeAdjacencyNode(int i) {
this.adjacencyList.remove(new SNode(i));
}

publicvoid addAdjacencyNode(int i) { //i为邻接顶点在图顶点列表中的index。
this.adjacencyList.add(new SNode(i));
}

//返回邻接表中的第i个邻接点
public SNode getAdjacencyNode(int i) {
return (SNode)this.adjacencyList.get(i);
}

//返回邻接表中一个SNode,该SNode的属性“index”为i_ref
public SNode getAdjacencyNodeEX(int i_ref) {
for (int i =0; i <this.getAdjacencyCount(); i++) {
if (getAdjacencyNode(i).index == i_ref) {
return getAdjacencyNode(i);
}
}
returnnull;
}

public String toString() {
returnthis.name;
}
}

//simple node,主要用于邻接表中,包含index(该点在图的nodelist中index)和visited(该边是否访问过)
class SNode {
publicboolean visited =false;
publicint index =0;

public SNode(int index) {
this.index = index;
}

//必须重载
publicboolean equals(Object o) {
if ( ( (SNode) o).index ==this.index) {
returntrue;
}
returnfalse;
}

public String toString() {
return"adjacency "+ index;
}
}

//欧拉图,随机生成,如果生成失败,则抛出异常。
class Graph {
private ArrayList nodeList; //顶点列表
private ArrayList path; //欧拉回路
privateint count; //顶点数

public Graph(int n) throws Exception {
this.count = n;
nodeList =new ArrayList(count);
if (!ginit(count)) {
thrownew Exception("sorry,a failure,retry please");
}
}

//搜索欧拉回路,算法描述见文件顶部注释
publicvoid circuit() {
path =new ArrayList();
int top =0; //当前回游的起点
int k =0; //当前回游的起点在path中的index
path.add(new Integer(0));
while (true) {
int i, j;
//int init=0;
i = top; //i为一次回游的当前点
ArrayList path1 =new ArrayList();
path1.add(new Integer(top));
while (true) { //执行一遍回路遍历,但不一定遍历所有的边
Node node = (Node) nodeList.get(i);
for (j =0; j <this.count; j++) {
if (node.contains(j) && node.getAdjacencyNodeEX(j).visited ==false) {
path1.add(new Integer(j));
node.getAdjacencyNodeEX(j).visited =true;
( (Node) nodeList.get(j)).getAdjacencyNodeEX(i).visited =true;
i = j;
break;
}
}
if (i == top) {
break;
}
}
path.remove(k);
path.addAll(k, path1);
k++;
if (k >= path.size()) {
break;
}
top = ( (Integer) path.get(k)).intValue();
}
for (int z =0; z < path.size(); z++) {
System.out.print(path.get(z).toString() +"");
}
}

//随机生成欧拉图
privateboolean ginit(int n) {
int i;
for (i =0; i < n; i++) {
nodeList.add(new Node("node"+ i));
}
ArrayList linked =new ArrayList();
linked.add(new Integer(0));
Random rand =new Random();
//生成随机连通图
for (i =1; i < n; i++) {
int size = linked.size(); //取得连通集合里面的最后进入的顶点index
int top = ( (Integer) (linked.get(size -1))).intValue();
Node node = (Node) (nodeList.get(top)); //根据top取得该node
while (true) {
int randint = rand.nextInt(n);
if (randint == top) {
continue;
}
if (node.contains(randint)) {
continue;
}
else {
if (!linked.contains(new Integer(randint))) {
linked.add(new Integer(randint));
}
elseif (node.getAdjacencyCount() >=
(linked.size() -1>6?6 : linked.size() -1)) {
continue;
}
else {
i--;
}
node.addAdjacencyNode(randint);
Node randnode = (Node) nodeList.get(randint);
randnode.addAdjacencyNode(top);
break;
} //end if
} //end while
} //end for
//printg();//for test

//使所有的顶点度数为偶数
/*如果该顶点v1的度数为奇数,则从后面找一个度数也为奇数的点v2,
1、如果v1和v2已经有边,则如果两个点的度数不为1,则去掉它们的连边,
否则继续往后查找度数为奇数的点。
2、如果v1和v2没有边,则在它们之间连边
3、如果没有找到合适的点,则再找一度数为奇的点v3,和一个度数为偶的点v4,如果v4
和v1,v3没有相连,则在v4和v1,v4和v3之间加边。
4、如果仍然没有找到,4、1 则将该点与任意一个不相连的点之间加边,重新执行该“变偶”操作;
4、2 如果找不到与该点不相连的点,则找一度数大于2的点,去除与该点的边,重新执行
*/
for (i =0; i <this.count -1; i++) {
Node node = (Node) nodeList.get(i);
if (node.getAdjacencyCount() %2!=0) {
int j =0;
for (j = i +1; j <this.count; j++) {
Node nn = (Node) nodeList.get(j);
if (nn.getAdjacencyCount() %2!=0) {
if (node.contains(j)) { //1、见上注释
if (nn.getAdjacencyCount() !=1&& node.getAdjacencyCount() !=1) {
node.removeAdjacencyNode(j);
nn.removeAdjacencyNode(i);
break;
}
else {
continue;
}
}
else { //2、见上注释
node.addAdjacencyNode(j);
nn.addAdjacencyNode(i);
//i = j;
break;
} //end if
} //end if
} //end for
if (j ==this.count) {
int k;
Node nk =null;
for (k = i +1; k <this.count; k++) {//3、见上注释
nk = (Node) nodeList.get(k);
if (nk.getAdjacencyCount() %2!=0) {
break;
}
}
int kk = k;
for (k =0; k < i; k++) {
Node n1 = (Node) nodeList.get(k);
if (!n1.contains(kk) &&!n1.contains(i)) {
n1.addAdjacencyNode(kk);
nk.addAdjacencyNode(k);
n1.addAdjacencyNode(i);
node.addAdjacencyNode(k);
break;
}
}
boolean retry =false;
if (k == i) {//4、1 见上注释
int vv;
for (vv =0; vv <this.count; vv++) {
Node vn = (Node) nodeList.get(vv);
if (!vn.contains(i) && i != vv) {
vn.addAdjacencyNode(i);
node.addAdjacencyNode(vv);
retry =true;
break;
}
}
if (vv == count) {//4、2 见上注释
for (vv =0; vv < count; vv++) {
Node vnn = (Node) nodeList.get(vv);
if (vnn.getAdjacencyCount() >1) {
vnn.removeAdjacencyNode(i);
node.removeAdjacencyNode(vv);
retry =true;
break;
}
}
}
}
if (retry) {
i =-1;
}
}
} //end if
}
returnthis.isEularG();
} //end function

//判断生成的图是否为欧拉图
publicboolean isEularG() {
boolean isEular =true;
for (int i =0; i <this.count; i++) {
Node n = (Node) nodeList.get(i);
if (n.getAdjacencyCount() %2!=0) {
isEular =false;
break;
}
}
return isEular;
}

publicvoid printg() {
for (int i =0; i <this.count; i++) {
Node n = (Node) nodeList.get(i);
System.out.print(n.toString() +"");
for (int j =0; j < n.getAdjacencyCount(); j++) {
System.out.print(n.getAdjacencyNode(j).toString() +"");
}
System.out.println();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: