图(一)

图(Graph)

图(graph)是一种比线性表、树更为复杂的数据结构。在线性表中,数据元素之间呈线性关系,即每个元素只有一个直接前驱和一个直接后继。在树型结构中,数据元素之间有明显的的层次关系,即每个结点只有一个直接前驱,但可有多个直接后继,而在图结构中,每个结点即可有多个直接前驱,也可有多个直接后继,因此,树结构是图结构的一种特殊情形。当一个树结构中允许同一结点出现在不同分支上时,该树结构实际上就是一个图结构。

邻接:如果两个顶点被同一条边连接,就称这两个顶点是邻接的。

路径:边的序列。

连通图:至少有一条路径可以连接器所有的顶点,这个图就称为连通图。

有向图:如果边是没有方向的,称为无向图,反之为有向图。

带权图:在某些图,边被赋予一种权值,权值是一个数字,它代表两个顶点的物理距离,或时间或花费,这种图称为带权图。


图的存储结构

1)邻接矩阵

邻接矩阵是一个二维数组,数据项表示两点间是否存在边,如果图有 N 个顶点,则邻接矩阵就是 N*N 的数组。两个顶点间有边的表示为1,没有边则为0。也可以用 boolean 表示。

       A     B     C     D
   A      0     1     1     1
   B      1     0     0     1
   C      1     0     0     0
   D      1     1     0     0
                             如图: 
 
2)邻接表
   顶点   包含邻接顶点的链表
    A   B -> C -> D
    B   A -> D
    C   A
    D   A -> B

 

 

 

在邻接表中,符号 -> 表示链表中的一个节点,每个节点都是一个顶点。邻接表仅表示了当前顶点与哪些顶点连接,与顶点顺序无关。

 

顶点代码:

public class Vertex {

    private char label;

    private boolean isVisited;

    public Vertex(char label) {
        this.label = label;
    }

    public char getLabel() {
        return label;
    }

    public boolean isVisited() {
        return isVisited;
    }

    public void setVisited(boolean isVisited) {
        this.isVisited = isVisited;
    }

}

图的代码:

public class Graph0 {

    private final int MAX_VERTS = 20;

    private Vertex[] vertexArray;

    private int[][] adjMat;

    private int nVerts;

    public Graph0() {
        vertexArray = new Vertex[MAX_VERTS];
        adjMat = new int[MAX_VERTS][MAX_VERTS];
        nVerts = 0;
    }

    public void addVertex(char label) {
        vertexArray[nVerts++] = new Vertex(label);
    }

    public void addEdge(int start, int end) {
        adjMat[start][end] = 1;
        adjMat[end][start] = 1;
    }

}

   图x

图的遍历

1)深度优先遍历

深度优先要得到距离起始点最远的顶点,然后再不能继续前进的时候返回。栈的内容是从起始点到各个顶点访问的整个过程。

规则:

  1. 如果可能,访问一个邻接的未访问顶点,标记它,放入栈中。
  2. 当不能执行规则1,如果栈不空,则从栈中弹出一个顶点。
  3. 如果不能执行规则1、规则2,就完成了整个遍历过程。
public class StackX {

    private final int SIZE;

    private int[] array;

    private int top;

    public StackX(int size) {
        this.SIZE = size;
        array = new int[SIZE];
        top = -1;
    }

    public void push(int i) {
        array[++top] = i;
    }

    public int pop() {
        return array[top--];
    }

    public int peek() {
        return array[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }

}
public class Graph {

    private final int MAX_VERTS;

    private Vertex[] vertexArray;

    private int[][] adjMat;

    private StackX stack;

    private int nVerts;

    public Graph(int verts) {
        this.MAX_VERTS = verts;
        vertexArray = new Vertex[MAX_VERTS];
        adjMat = new int[MAX_VERTS][MAX_VERTS];
        stack = new StackX(MAX_VERTS);
        nVerts = 0;
    }

    public void addVertex(char label) {
        vertexArray[nVerts++] = new Vertex(label);
    }

    public void addEdge(int start, int end) {
        adjMat[start][end] = 1;
        adjMat[end][start] = 1;
    }

    public void displayVertex(int index) {
        System.out.print(vertexArray[index].getLabel() + " -> ");
    }

    //depth first search
    public void dfs() {
        vertexArray[0].setVisited(true);
        displayVertex(0);
        stack.push(0);

        while (!stack.isEmpty()) {
            int v = getAdjUnvisitedVertex(stack.peek());
            if (v == -1) {
                stack.pop();
            }
            else {
                vertexArray[v].setVisited(true);
                displayVertex(v);
                stack.push(v);
            }
        }

        for (int j = 0; j < MAX_VERTS; j++) {
            if (vertexArray[j] != null) {
                vertexArray[j].setVisited(false);
            }
        }
    }

    public int getAdjUnvisitedVertex(int v) {
        for (int k = 0; k < nVerts; k++) {
            if (adjMat[v][k] == 1 && vertexArray[k].isVisited() == false) {
                return k;
            }
        }
        return -1;
    }

}

在图x中,遍历的顺序为:A -> B -> E -> F -> C -> D -> G -> H -> I 


2)广度优先遍历

与深度优先相反,它首先访问起始顶点的所有邻接点,再一层一层地访问其它较远的顶点。

寻求两个顶点之间最短距离,可以使用广度优先遍历。

规则:

  1. 访问下一个未来访问的邻接点(如果存在),这个顶点必须当前顶点的邻接点,标记它,并把它插入队列中。
  2. 如果因为已经没有未访问的顶点而不能执行规则1,那么从队列头取一个顶点(如果存在),并使其成为当前顶点。
  3. 如果因为队列为空而不能执行规则2,则遍历结束。
public class Queue {

    private final int SIZE;

    private int[] queArray;

    private int front;

    private int rear;

    public Queue(int size) {
        this.SIZE = size;
        queArray = new int[SIZE];
        front = 0;
        rear = -1;
    }

    public void insert(int d) {
        if (rear == SIZE - 1) {
            rear = -1;
        }
        queArray[++rear] = d;
    }

    public int remove() {
        int temp = queArray[front++];
        if (front == SIZE) {
            front = 0;
        }
        return temp;
    }

    public boolean isEmpty() {
        return (rear + 1 == front) || (front + SIZE - 1 == rear);
    }

}
public class Graph2 {

    private final int MAX_VERTS;

    private Vertex[] vertexArray;

    private int[][] adjMat;

    private Queue queue;

    private int nVerts;

    public Graph2(int verts) {
        this.MAX_VERTS = verts;
        vertexArray = new Vertex[MAX_VERTS];
        adjMat = new int[MAX_VERTS][MAX_VERTS];
        queue = new Queue(MAX_VERTS);
        nVerts = 0;
    }

    public void addVertex(char label) {
        vertexArray[nVerts++] = new Vertex(label);
    }

    public void addEdge(int start, int end) {
        adjMat[start][end] = 1;
        adjMat[end][start] = 1;
    }

    public void displayVertex(int index) {
        System.out.print(vertexArray[index].getLabel() + " -> ");
    }

    public int getAdjUnvisitedVertex(int v) {
        for (int k = 0; k < nVerts; k++) {
            if (adjMat[v][k] == 1 && vertexArray[k].isVisited() == false) {
                return k;
            }
        }
        return -1;
    }

    //breadth first search
    public void bfs() {
        vertexArray[0].setVisited(true);
        displayVertex(0);
        queue.insert(0);

        while (!queue.isEmpty()) {
            int r = queue.remove();
            int v;
            while ((v = getAdjUnvisitedVertex(r)) != -1) {
                vertexArray[v].setVisited(true);
                displayVertex(v);
                queue.insert(v);
            }

        }

        for (int j = 0; j < MAX_VERTS; j++) {
            if (vertexArray[j] != null) {
                vertexArray[j].setVisited(false);
            }
        }
    }
    
}

在图x中,遍历的顺序为:A -> B -> C -> D -> E -> F -> G -> H -> I 

posted @ 2013-02-16 15:13  Kyle_Java  阅读(284)  评论(0编辑  收藏  举报