4.1 无向图

摘要:
1、 图的表示1.顶点的表示:整数0~V-1。即使顶点由字母表示,也可以使用符号表将其转换为顶点名称和整数之间的一对一对应关系。

一.图的表示

1.顶点的表示:使用整数0~V-1来表示。即使顶点是字母表示的,也可以利用符号表转换为顶点名字和整数一一对应的关系。

2.图的表示方法:实际中最常用的一种是邻接表数组(Adjaxency-list )

(1)使用数组表示以每一个顶点为索引的列表

(2)数组中的元素表示与该顶点邻接的顶点所构成的集合(这里使用ArrayList/bag来承载邻接元素)

4.1 无向图第1张

3.代码实现

4.1 无向图第2张4.1 无向图第3张
package com.cx.graph;

import edu.princeton.cs.algs4.Bag;

//无向图的表示
public class Graph {
    private final int V;
    //邻接表数组,里面的每个元素都是一个集合类
    private Bag<Integer>[] adj;
    
    //初始化V个顶点的图
    public Graph(int V) {
        this.V=V;
        adj=(Bag<Integer>[])new Bag[V];
        //将每个元素初始化,不然会为null
        for(int v=0;v<V;v++) {
            adj[v]=new Bag<Integer>();
        }
    }

    public void addEdge(int v,int w) {
        adj[v].add(w);
        adj[w].add(v);
    }
    //顶点v的邻接元素集合
    public Iterable<Integer> adj(int v){
        return adj[v];
    }
    //点的度数
    public static int degree(Graph G,int v) {
        int degree=0;
        for(int w:G.adj(v)) degree++;
        return degree;
    }
    public int V() {return V;}
    
}
View Code
4.1 无向图第4张4.1 无向图第5张
/******************************************************************************
 *  Compilation:  javac Bag.java
 *  Execution:    java Bag < input.txt
 *  Dependencies: StdIn.java StdOut.java
 *
 *  A generic bag or multiset, implemented using a singly-linked list.
 *
 *  % more tobe.txt 
 *  to be or not to - be - - that - - - is
 *
 *  % java Bag < tobe.txt
 *  size of bag = 14
 *  is
 *  -
 *  -
 *  -
 *  that
 *  -
 *  -
 *  be
 *  -
 *  to
 *  not
 *  or
 *  be
 *  to
 *
 ******************************************************************************/

package edu.princeton.cs.algs4;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 *  The {@code Bag} class represents a bag (or multiset) of 
 *  generic items. It supports insertion and iterating over the 
 *  items in arbitrary order.
 *  <p>
 *  This implementation uses a singly-linked list with a static nested class Node.
 *  See {@link LinkedBag} for the version from the
 *  textbook that uses a non-static nested class.
 *  The <em>add</em>, <em>isEmpty</em>, and <em>size</em> operations
 *  take constant time. Iteration takes time proportional to the number of items.
 *  <p>
 *  For additional documentation, see <a href="http://t.zoukankan.com/http://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of
 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
 *
 *  @author Robert Sedgewick
 *  @author Kevin Wayne
 *
 *  @param <Item> the generic type of an item in this bag
 */
public class Bag<Item> implements Iterable<Item> {
    private Node<Item> first;    // beginning of bag
    private int n;               // number of elements in bag

    // helper linked list class
    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    /**
     * Initializes an empty bag.
     */
    public Bag() {
        first = null;
        n = 0;
    }

    /**
     * Returns true if this bag is empty.
     *
     * @return {@code true} if this bag is empty;
     *         {@code false} otherwise
     */
    public boolean isEmpty() {
        return first == null;
    }

    /**
     * Returns the number of items in this bag.
     *
     * @return the number of items in this bag
     */
    public int size() {
        return n;
    }

    /**
     * Adds the item to this bag.
     *
     * @param  item the item to add to this bag
     */
    public void add(Item item) {
        Node<Item> oldfirst = first;
        first = new Node<Item>();
        first.item = item;
        first.next = oldfirst;
        n++;
    }


    /**
     * Returns an iterator that iterates over the items in this bag in arbitrary order.
     *
     * @return an iterator that iterates over the items in this bag in arbitrary order
     */
    public Iterator<Item> iterator()  {
        return new ListIterator<Item>(first);  
    }

    // an iterator, doesn't implement remove() since it's optional
    private class ListIterator<Item> implements Iterator<Item> {
        private Node<Item> current;

        public ListIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext()  { return current != null;                     }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next; 
            return item;
        }
    }

    /**
     * Unit tests the {@code Bag} data type.
     *
     * @param args the command-line arguments
     */
    public static void main(String[] args) {
        Bag<String> bag = new Bag<String>();
        while (!StdIn.isEmpty()) {
            String item = StdIn.readString();
            bag.add(item);
        }

        StdOut.println("size of bag = " + bag.size());
        for (String s : bag) {
            StdOut.println(s);
        }
    }

}

/******************************************************************************
 *  Copyright 2002-2016, Robert Sedgewick and Kevin Wayne.
 *
 *  This file is part of algs4.jar, which accompanies the textbook
 *
 *      Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne,
 *      Addison-Wesley Professional, 2011, ISBN 0-321-57351-X.
 *      http://algs4.cs.princeton.edu
 *
 *
 *  algs4.jar is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  algs4.jar is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with algs4.jar.  If not, see http://www.gnu.org/licenses.
 ******************************************************************************/
bag

4.说明:

(1)在实际中,往往顶点是巨大的,而顶点的平均度数是很小的,即图往往是稀疏的,在这种情况下,图的表示方法依旧显示很好的性能

(2)除此以外还有2种表示方式,其一是维持边的数组,将所有的边记录下来,但是这种方式对于遍历顶点的邻接顶点极其麻烦。其二是使用二维矩阵表示图的邻接矩阵,由于(1)的特性,会造成该矩阵巨大,但是稀疏,对空间造成极大的浪费。

4.1 无向图第6张

二.深度优先算法Depth-first Search

1.目标(作用):

(1)连通性的判断:判断给定的顶点是否连通

(2)单点路径:找出与起点s连通的所有顶点和对应的路径

2.思想:mimic maze exploration。在访问一个顶点的时候:

(1)将它标记为已访问

(2)递归地访问它的所有未被标记的领域顶点

3.算法:

(1)使用递归

(2)标记每一个已访问的顶点,并记录到达它的顶点

(3)当没有未访问的点时返回

4.举例

4.1 无向图第7张

如图所示:起点是0,marked[]用于标记是否已访问过该顶点,edgeTo[v]用于记录从起点到一个顶点的已知路径上的最后一个顶点,便于记录这条路径。

首先处理起点0,记录marked为T,然后遍历所有邻域5,1,2,6(DFS),例如先处理6,marked[6]=T,edge[6]=0。处理6的邻域,只能是4,因为0已被标记。记录marked[4]=T,edge[4]=6。处理4的领域,6已被标记,遍历所有邻域3,5。例如处理5,marked[5]=T,edge[5]=4。处理5的未标记邻域,只能是3,marked[3]=T,edge[3]=5。3没有未标记的邻域,返回。同理5,4,6也没有未处理的邻域。最后分别处理1,2。深度优先算法结束。

4.1 无向图第8张

5.代码实现

4.1 无向图第9张4.1 无向图第10张
package com.cx.graph;

import java.util.Stack;

public class DepthFirstPaths {
    //用于标记是否已访问过该顶点
    private boolean[] marked;
    //用于标记从起点到一个顶点的已知路径上的最后一个顶点
    //边v-w是第一次访问w经过的路径,则edgeTo(w)=v,从而可以记住该路径
    private int[] edgeTo;
    //起点为s
    private int s;
    
    //递归的标记与起点s连通的所有顶点
    public DepthFirstPaths(Graph G,int s) {
        marked=new boolean[G.V()];
        edgeTo=new int[G.V()];
        s=this.s;
        //找到和s连通的顶点
        dfs(G,s);
    }
    //标记每一个已访问的顶点,并记录到达它的顶点
    private void dfs(Graph G,int v) {
        marked[v]=true;
        for(int w:G.adj(v)) {
            //访问所有未被标记的邻域顶点
            if(!marked[w]) {
                edgeTo[w]=v;
                dfs(G, w);                
            }
        }
    }
    //判断任意两个顶点是否连通
    public boolean hasPathTo(int v) {
        return marked[v];
    }
    //找到一条s-v的路径
    public Iterable<Integer> pathTo(int v){
        if(!hasPathTo(v)) return null;
        Stack<Integer> path=new Stack<Integer>();
        //从终点逆向得到路径
        for(int x=v;v!=s;x=edgeTo[x]) {
            path.push(x);
        }
        path.push(s);
        return path;
    }
}
View Code

6.说明:

(1)标记与起点连通的所有顶点所需的时间和顶点的度数之和成正比

(2)在DFS以后,可以在常数时间内找到与s连通的所有顶点,并且找到从起点到任意标记顶点的路径所需的时间与路径的长度成正比

(3)递归的时候,每个顶点仅标记一次,并且对每一个可能的分支路径深入到不能再深入为止。

三.广度优先算法 Breadth-first Search

1.用处:

(1)连通性的判断:判断给定的顶点是否连通

(2)单点最短路径:找出与起点s连通的所有顶点和对应的最短路径

2.算法:将起点加入队列,然后重复以下步骤直到队列为空:

(1)取队列中的下一个顶点v并标记它

(2)将与v相邻的所有未被标记过的顶点加入队列

3.举例说明

4.1 无向图第11张

将起点0,加入队列,取0并标记,然后将2,1,5加入队列。比如先加入的2,则取2并标记,将3.4加入队列。取1出队列,并标记,没有未标记的相邻顶点,不加新元素到队列。同理。取5出队列,并标记。取3出队列并标记,取4出队列并标记。

edgeTo[]用于记录到达该点路径的上一个点,distTo[]记录到顶点的距离。

4.1 无向图第12张

4.代码实现

4.1 无向图第13张4.1 无向图第14张
package com.cx.graph;

import java.util.Stack;

import edu.princeton.cs.algs4.Queue;

public class BreadthFirstPaths {
    private boolean[] marked;
    private int[] edgeTo;
    private  int s;
    
    public BreadthFirstPaths(Graph G,int s) {
        marked=new boolean[G.V()];
        edgeTo=new int[G.V()];
        s=this.s;
        //找到和s连通的顶点
        bfs(G,s);
    }
    
    private void bfs(Graph G,int s) {
        Queue<Integer> queue=new Queue<Integer>();
        queue.enqueue(s);
        marked[s]=true;
        while(!queue.isEmpty()) {
            int v=queue.dequeue();
            for(int w:G.adj(v)) {
                if(!marked[w]) {
                    //1.标记
                    marked[w]=true;
                    //2.入队列
                    queue.enqueue(w);
                    //3.写前一个顶点
                    edgeTo[w]=v;
                }
            }
        }
    }
    public boolean hasPathTo(int v) {
        return marked[v];
    }
    public Iterable<Integer> pathTo(int v){
        if(!hasPathTo(v)) return null;
        Stack<Integer> path=new Stack<Integer>();
        //从终点逆向得到路径
        for(int x=v;v!=s;x=edgeTo[x]) {
            path.push(x);
        }
        path.push(s);
        return path;
    }
}
View Code
4.1 无向图第15张4.1 无向图第16张
/******************************************************************************
 *  Compilation:  javac Queue.java
 *  Execution:    java Queue < input.txt
 *  Dependencies: StdIn.java StdOut.java
 *  Data files:   http://algs4.cs.princeton.edu/13stacks/tobe.txt  
 *
 *  A generic queue, implemented using a linked list.
 *
 *  % java Queue < tobe.txt 
 *  to be or not to be (2 left on queue)
 *
 ******************************************************************************/

package edu.princeton.cs.algs4;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 *  The {@code Queue} class represents a first-in-first-out (FIFO)
 *  queue of generic items.
 *  It supports the usual <em>enqueue</em> and <em>dequeue</em>
 *  operations, along with methods for peeking at the first item,
 *  testing if the queue is empty, and iterating through
 *  the items in FIFO order.
 *  <p>
 *  This implementation uses a singly-linked list with a static nested class for
 *  linked-list nodes. See {@link LinkedQueue} for the version from the
 *  textbook that uses a non-static nested class.
 *  The <em>enqueue</em>, <em>dequeue</em>, <em>peek</em>, <em>size</em>, and <em>is-empty</em>
 *  operations all take constant time in the worst case.
 *  <p>
 *  For additional documentation, see <a href="http://t.zoukankan.com/http://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of
 *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
 *
 *  @author Robert Sedgewick
 *  @author Kevin Wayne
 *
 *  @param <Item> the generic type of an item in this queue
 */
public class Queue<Item> implements Iterable<Item> {
    private Node<Item> first;    // beginning of queue
    private Node<Item> last;     // end of queue
    private int n;               // number of elements on queue

    // helper linked list class
    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    /**
     * Initializes an empty queue.
     */
    public Queue() {
        first = null;
        last  = null;
        n = 0;
    }

    /**
     * Returns true if this queue is empty.
     *
     * @return {@code true} if this queue is empty; {@code false} otherwise
     */
    public boolean isEmpty() {
        return first == null;
    }

    /**
     * Returns the number of items in this queue.
     *
     * @return the number of items in this queue
     */
    public int size() {
        return n;
    }

    /**
     * Returns the item least recently added to this queue.
     *
     * @return the item least recently added to this queue
     * @throws NoSuchElementException if this queue is empty
     */
    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return first.item;
    }

    /**
     * Adds the item to this queue.
     *
     * @param  item the item to add
     */
    public void enqueue(Item item) {
        Node<Item> oldlast = last;
        last = new Node<Item>();
        last.item = item;
        last.next = null;
        if (isEmpty()) first = last;
        else           oldlast.next = last;
        n++;
    }

    /**
     * Removes and returns the item on this queue that was least recently added.
     *
     * @return the item on this queue that was least recently added
     * @throws NoSuchElementException if this queue is empty
     */
    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = first.item;
        first = first.next;
        n--;
        if (isEmpty()) last = null;   // to avoid loitering
        return item;
    }

    /**
     * Returns a string representation of this queue.
     *
     * @return the sequence of items in FIFO order, separated by spaces
     */
    public String toString() {
        StringBuilder s = new StringBuilder();
        for (Item item : this) {
            s.append(item);
            s.append(' ');
        }
        return s.toString();
    } 

    /**
     * Returns an iterator that iterates over the items in this queue in FIFO order.
     *
     * @return an iterator that iterates over the items in this queue in FIFO order
     */
    public Iterator<Item> iterator()  {
        return new ListIterator<Item>(first);  
    }

    // an iterator, doesn't implement remove() since it's optional
    private class ListIterator<Item> implements Iterator<Item> {
        private Node<Item> current;

        public ListIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext()  { return current != null;                     }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next; 
            return item;
        }
    }


    /**
     * Unit tests the {@code Queue} data type.
     *
     * @param args the command-line arguments
     */
    public static void main(String[] args) {
        Queue<String> queue = new Queue<String>();
        while (!StdIn.isEmpty()) {
            String item = StdIn.readString();
            if (!item.equals("-"))
                queue.enqueue(item);
            else if (!queue.isEmpty())
                StdOut.print(queue.dequeue() + " ");
        }
        StdOut.println("(" + queue.size() + " left on queue)");
    }
}

/******************************************************************************
 *  Copyright 2002-2016, Robert Sedgewick and Kevin Wayne.
 *
 *  This file is part of algs4.jar, which accompanies the textbook
 *
 *      Algorithms, 4th edition by Robert Sedgewick and Kevin Wayne,
 *      Addison-Wesley Professional, 2011, ISBN 0-321-57351-X.
 *      http://algs4.cs.princeton.edu
 *
 *
 *  algs4.jar is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  algs4.jar is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with algs4.jar.  If not, see http://www.gnu.org/licenses.
 ******************************************************************************/
Queue

5.说明:

(1)广度优先算法计算从给定顶点s到所有别的顶点的最短路径需要的时间和E+V成正比。

(2)是一种非递归的算法

(3)深度优先通过栈来实现,广度优先通过队列来实现

四.连通分量

1.目标:常数时间内判断v和w是否相连接。

2.连通分量:相互连接的顶点的最大集合。

如果可以给定连通分量,则可以实现上述目标,即在常数时间内判断v和w是否相连接。

4.1 无向图第17张

3.连通分量的确定可以使用类似深度优先算法的思想。遍历所有未标记的顶点,例如v,做如下操作:

(1)将v标记为已访问

(2)递归的访问所有和v邻接且未标记的顶点

4.代码实现:

4.1 无向图第18张4.1 无向图第19张
package com.cx.graph;

public class CC {
    private boolean[] marked;
    //v所在的连通分量的标识符
    private int[] id;
    //连通分量个数
    private int count;

    public CC(Graph G) {
        marked=new boolean[G.V()];
        id=new int[G.V()];
        //对所有顶点执行dfs操作进行标记
        for(int s=0;s<G.V();s++) {
            //对未标记的执行dfs
            if(!marked[s]) {
                dfs(G,s);
                count++;
            }
        }
    }
    private void dfs(Graph G,int v) {
        marked[v]=true;
        id[v]=count;
        for(int w:G.adj(v)) {
            if(!marked[w]) {
                dfs(G, w);
            }
        }
    }
    //判断是否连通
    public boolean connected(int v,int w) {
        return id[v]==id[w];
    }
    public int id(int v) {
        return id[v];
    }    
    public int count() {
        return count;
    }
}
View Code

5.说明:

(1)预处理使用的时间和空间与V+E成正比且可以在常数时间内处理关于图的连通性的查询

免责声明:文章转载自《4.1 无向图》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C# Json格式字符串图片懒加载与预加载下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

讲透学烂二叉树(一):图的概念和定义—各种属性特征浅析

树和图的概念 图是一种特殊的数据结构,由点和边构成,它可以用来描述元素之间的网状关系,这个网状没有顺序,也没有层次,就是简单的把各个元素连接起来。 图的概念和基本性质 图(graph):图(graph)由边(edge)的集合及顶点(vertex)的集合组成。通常记为:G=(V,E)。对于两个图G和G’,如果G’的顶点集合与边集合均为G的顶点集合与边集合的子...

深度优先生成树及其应用

在上一篇博客判断有向图是否有圈中从递归的角度简单感性的介绍了如何修改深度优先搜索来判断一个有向图是否有圈。事实上, 它的实质是利用了深度优先生成树(depth-first spanning tree)的性质。那么什么是深度优先生成树?顾名思义,这颗树由深度优先搜索而生成的,由于无向图与有向图的深度优先生成树有差别,下面将分别介绍。 一. 无向图的深度优先生...

点双连通分量

它是什么? 对于一个无向图,如果它没有割点,则称其为“点双联通图” 无向图的极大点双连通子图成为“点双连通分量” 它可以用来做什么? 如果对无向图中的所有点双连通分量缩点,可以得到一颗树,可以比较方便地将一些路径问题转化为树上问题 怎么求? 我们可以在(Tarjan)求割点时,顺便把所有(v-DCC)求出来,流程如下: 当一个节点第一次被访问时,入栈 当...

poj 2942 Knights of the Round Table(无向图的双连通分量+二分图判定)

#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector>...

点双连通分量与割点

前言 在图论中,除了在有向图中的强连通分量,在无向图中还有一类双连通分量 双连通分量一般是指点双连通分量 当然,还有一种叫做边双连通分量 点双连通分量 对于一个连通图,如果任意两点至少存在两条“点不重复”的路径,则说图是点双连通的(即任意两条边都在一个简单环中),点双连通的极大子图称为点双连通分量。 计算方法比较简单 在tarjan的过程中,如果由(i)...