第 36 天: 邻连表
对于图来说,邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费的。因此我们考虑另外一种存储结构方式:邻接表(Adjacency List),即数组与链表相结合的存储方法。
邻接表的处理方法是这样的。
1、图中顶点用一个一维数组存储,另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
2、图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图称为顶点vi作为弧尾的出边表。
public AdjacencyList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
// Step 1. Initialize. The data in the headers are not meaningful.
AdjacencyNode tempPreviousNode, tempNode;
headers = new AdjacencyNode[numNodes];
for (int i = 0; i < numNodes; i++) {
headers[i] = new AdjacencyNode(-1);
tempPreviousNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
} // Of if
// Create a new node.
tempNode = new AdjacencyNode(j);
// Link.
tempPreviousNode.next = tempNode;
tempPreviousNode = tempNode;
} // Of for j
} // Of for i
}// Of class AdjacentTable
在这个有参构造中,相当于依靠headers类把邻接表的不同的row给连接在一起了。另外对于
感觉其中的参数并不重要,就是new一个这个类的对象,对其中参数的要求没有,换成其他数值也是可以的。
/**
*********************
* Breadth first traversal.
*
* @param paraStartIndex
* The start index.
* @return The sequence of the visit.
*********************
*/
public String breadthFirstTraversal(int paraStartIndex) {
CircleObjectQueue tempQueue = new CircleObjectQueue();
String resultString = "";
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[paraStartIndex] = true;
// Initialize the queue.
// Visit before enqueue.
tempVisitedArray[paraStartIndex] = true;
resultString += paraStartIndex;
tempQueue.enqueue(new Integer(paraStartIndex));
// Now visit the rest of the graph.
int tempIndex;
Integer tempInteger = (Integer) tempQueue.dequeue();
AdjacencyNode tempNode;
while (tempInteger != null) {
tempIndex = tempInteger.intValue();
// Enqueue all its unvisited neighbors. The neighbors are linked
// already.
tempNode = headers[tempIndex].next;
while (tempNode != null) {
if (!tempVisitedArray[tempNode.column]) {
// Visit before enqueue.
tempVisitedArray[tempNode.column] = true;
resultString += tempNode.column;
tempQueue.enqueue(new Integer(tempNode.column));
} // Of if
tempNode = tempNode.next;
} // Of for i
// Take out one from the head.
tempInteger = (Integer) tempQueue.dequeue();
} // Of while
return resultString;
}// Of breadthFirstTraversal
广度优先遍历,同样是用到了之前的队列完成。算是比较熟悉了。最后贴上toString方法,测试用例及主函数。
/**
*********************
* Overrides the method claimed in Object, the superclass of any class.
*********************
*/
public String toString() {
String resultString = "";
AdjacencyNode tempNode;
for (int i = 0; i < numNodes; i++) {
tempNode = headers[i].next;
while (tempNode != null) {
resultString += " (" + i + ", " + tempNode.column + ")";
tempNode = tempNode.next;
} // Of while
resultString += "\r\n";
} // Of for i
return resultString;
}// Of toString
/**
*********************
* Unit test for breadthFirstTraversal. The same as the one in class Graph.
*********************
*/
public static void breadthFirstTraversalTest() {
// Test an undirected graph.
int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1 }, { 0, 1, 1, 0 } };
Graph tempGraph = new Graph(tempMatrix);
System.out.println(tempGraph);
String tempSequence = "";
try {
tempSequence = tempGraph.breadthFirstTraversal(2);
} catch (Exception ee) {
System.out.println(ee);
} // Of try.
System.out.println("The breadth first order of visit: " + tempSequence);
}// Of breadthFirstTraversalTest
/**
*********************
* The entrance of the program.
*
* @param args
* Not used now.
*********************
*/
public static void main(String args[]) {
int[][] tempMatrix = { { 0, 1, 0 }, { 1, 0, 1 }, { 0, 1, 0 } };
AdjacencyList tempTable = new AdjacencyList(tempMatrix);
System.out.println("The data are:\r\n" + tempTable.toString());
breadthFirstTraversalTest();
}// Of main
其实最后主函数的输出语句里是没有我上面写的”.toString()“的,当时想了半天怎么会输出tempTable 会自己打印出内容,没有返回值啊,结果一搜素发现这个方法它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法。