1、圖的定義。
圖分爲兩個部分組長,包括邊和點。將點用邊連接起來就形成了圖。
圖也分爲有向圖與無向圖。有向圖就是邊會帶上方向。指明從哪個點到哪個點,反之無向圖指沒有方向得邊。更多的時候會給邊加上值,在圖中,我們稱之爲該邊得權。有向圖中,叫做,有向帶權圖。無向圖中,叫做,無向帶權圖。
2、圖的構造
圖是由邊和點組成。那麼構造就從邊和點開始。
邊:
每條邊得兩端各對應一個點,邊得大小。所以圖得邊構造類如下:
/**
* 圖中的邊
*/
//邊的左節點
GraphNode leftNode;
//邊的右節點
GraphNode rightNode;
//邊的權值
int value;
public GraphEdge(GraphNode leftNode,GraphNode rightNode,int value){
this.leftNode = leftNode;
this.rightNode = rightNode;
this.value = value;
}
點:
一個點可對應零條或者多條邊。以及爲了圖得遍歷,可對點設置boolean值。用來判斷該點是否遍歷過。點得構造類如下:
/**
* 圖的節點
*/
int value;//節點得值
boolean tf;//節點是否遍歷過
List<GraphEdge> edges;//該節點連接得邊
public GraphNode(int value,boolean tf){
this.value = value;
this.tf = tf;
}
public void addEdge(GraphEdge edge){
if(edges == null){
edges= new ArrayList<>();
}
edges.add(edge);
}
3、圖的遍歷
遍歷之前,先構造一個簡單得圖。構造代碼如下:
/**
* 生成圖
*/
//存放點得集合
List<GraphNode> nodeList = null;
//初始化點
public void initNode(int n ){
if(nodeList == null){
nodeList = new ArrayList<>();
}
GraphNode node = null;
for(int i = 0; i < n ; i++){
node = new GraphNode(i,false);
nodeList.add(node);
}
}
//初始化邊
public void initGraph(int n){
initNode(n);
GraphEdge edge01 = new GraphEdge(nodeList.get(0),nodeList.get(1),0);
GraphEdge edge02 = new GraphEdge(nodeList.get(0),nodeList.get(2),0);
GraphEdge edge13 = new GraphEdge(nodeList.get(1),nodeList.get(3),0);
GraphEdge edge14 = new GraphEdge(nodeList.get(1),nodeList.get(4),0);
GraphEdge edge25 = new GraphEdge(nodeList.get(2),nodeList.get(5),0);
GraphEdge edge26 = new GraphEdge(nodeList.get(2),nodeList.get(6),0);
GraphEdge edge37 = new GraphEdge(nodeList.get(3),nodeList.get(7),0);
GraphEdge edge47 = new GraphEdge(nodeList.get(4),nodeList.get(7),0);
GraphEdge edge56 = new GraphEdge(nodeList.get(5),nodeList.get(6),0);
GraphEdge edge67 = new GraphEdge(nodeList.get(6),nodeList.get(7),0);
nodeList.get(0).addEdge(edge01);
nodeList.get(0).addEdge(edge02);
nodeList.get(1).addEdge(edge13);
nodeList.get(1).addEdge(edge14);
nodeList.get(2).addEdge(edge25);
nodeList.get(2).addEdge(edge26);
nodeList.get(3).addEdge(edge37);
nodeList.get(4).addEdge(edge47);
nodeList.get(5).addEdge(edge56);
nodeList.get(6).addEdge(edge67);
}
//獲取所有點
public List<GraphNode> getNodeList() {
return nodeList;
}
構造完成之後進行圖的遍歷,可通過深度遍歷與廣度遍歷完成
深度遍歷可通過遞歸或棧完成。廣度遍歷可通過隊列完成。
1、圖得深度遍歷-棧
public void dfSearchTraversing(GraphNode node) {
if (node == null) {
return;
}
Stack<GraphNode> stack = new Stack<GraphNode>();//創建棧
stack.push(node);//加入首節點
while (!stack.isEmpty()) {
GraphNode node1 = stack.pop();//彈出首節點
node1.setTf(true);//設置標記,該節點已訪問
System.out.println("節點得值" + node1.getValue());
List<GraphEdge> list = node1.getEdges();//根據節點獲得關聯得邊
if (list == null) {//該點無對應得邊了
continue;
}
for (int i = 0; i < list.size(); i++) {
GraphEdge graphEdge = list.get(i);//獲取每條邊對應得另一端節點
GraphNode temp = graphEdge.getRightNode();
if (temp.getTf()) {//已訪問過,就跳過該節點。
continue;
}
stack.push(temp);//將沒訪問過得節點加入棧中
}
}
}
2、圖得深度遍歷-遞歸
對遞歸算法不太瞭解得可參考上篇博客博客地址。
public void dfSearchTraversing(GraphNode node) {
if (node == null || node.getTf()) { //判斷節點是否爲空,或者是否已經遍歷過
return;
}
node.setTf(true);//設置已遍歷
System.out.println("節點:"+node.getValue());
List<GraphEdge> graphEdgeList = node.getEdges();//獲取左節點的應得邊
if(graphEdgeList == null){
return;
}
for(int i = 0; i < graphEdgeList.size(); i ++){
GraphNode graphNode = graphEdgeList.get(i).getRightNode();//獲取邊得右節點
if(graphNode.getTf()) {//判斷是否已經遍歷過
continue;
}
dfSearchTraversing(graphNode);//遞歸調用
}
}
3、圖得廣度遍歷-隊列
public void bfSearchTraversing(GraphNode node) {
if(node == null){
return;
}
Queue<GraphNode> queue = new LinkedList<>();//創建隊列
queue.add(node);//加入第一個節點
while(queue.isEmpty() == false){
GraphNode node1 = queue.remove();//先進先出。移除節點
node1.setTf(true);//設置該節點已遍歷過
System.out.println("值:"+node1.getValue());
List<GraphEdge> list = node1.getEdges();//獲取點相關聯得邊
if(list == null){
continue;
}
for(int i = 0; i <list.size(); i++){
GraphEdge graphEdge = list.get(i);//獲取邊對應得右節點
GraphNode temp = graphEdge.getRightNode();
if(temp.getTf()){//判斷該節點是否已經遍歷過
continue;
}
queue.add(temp);//加入到隊列中
}
}
}
個人記錄,僅供參考。