思路:重开一个新图,按着邻接列表的顺序从上到下遍历,每遍历一行链表前,清空visited数组,如果没有访问过这个元素,则加入新图,如果已经访问过了(重边),则不动。
伪代码:
复杂度:O(V+E)
for each u 属于 Vertex
visited[u] = false;
for u 属于 Vertex
visited[u] = true;
for v 属于 Adj[u]
if(!visited[v])
Adj1[u].insert(v);
visited[v] = true;
for v 属于 Adj[u]
visited[v]=false;
visited[u] = false;
证明算法正确性:
命题:给定一条边(u,v),此边为有向边,visited[v]=false 当且仅当 (u,v)需加入E'.
=>已知起点为u,visited[v]=false,则说明v曾经并没有被u访问到,因为如果访问到,则visited[v]被置为true,则如果当访问边(u,v)时,visited[v]==false,则会将(u,v)加入E'中.
<=已知(u,v)需要加入E',如果visited[v]=true,则不会执行if里的语句,则说明(u,v)不会加入E',与条件矛盾。
输入:
3 8
a b
a b
a b
b c
b c
b c
c a
c c
源代码:
package C22;
import java.util.Iterator;
/**
* 化简多重图
* @author xiazdong
*
*/
public class C1_4 {
static Adjacent_List g;
public static void main(String[] args) throws Exception {
Adjacent_List adjacent_list = GraphFactory.getAdjacentListInstance("input\\22.1-4.txt");
C1_4.g = adjacent_list;
Adjacent_List new_adj = remove_multiedge(adjacent_list);
adjacent_list.printAllEdges();
System.out.println("==============");
new_adj.printAllEdges();
}
/**
* 去掉重边的函数
* @param g
* @return
*/
public static Adjacent_List remove_multiedge(Adjacent_List g){
int size = g.getSize();
Adjacent_List adj1 = new Adjacent_List(size);
boolean visited[] = new boolean[size];
for(int i=0;i<visited.length;i++) visited[i] = false;//O(V)
for(int i=0;i<size;i++){ //O(V+E)
visited[i] = true;
Iterator<String> iter = g.getListByVertexIndex(i).iterator();
while(iter.hasNext()){
String vstr = iter.next();
int v = g.getVertexIndex(vstr);
if(!visited[v]){
visited[v] = true;
adj1.addEdge(g.getVertexValue(i), vstr);
}
}
/*下面一句话 对新图遍历比较快,虽然速度只会提升常数级别。
较快:iter = adj1.getListByVertexValue(g.getVertexValue(i)).iterator();
较慢:iter = g.getListByVertexIndex(i).iterator(); 因为重边
*/
iter = adj1.getListByVertexValue(g.getVertexValue(i)).iterator();
while(iter.hasNext()){ //再一次遍历这个链表,并对这些元素清除数组 O(E)
String vstr = iter.next();
int v = g.getVertexIndex(vstr);
visited[v] = false;
}
visited[i] = false;
}
return adj1;
}
}