20172303 2018-2019-1《程序设计与数据结构》深度优先遍历

20172303 2018-2019-1《程序设计与数据结构》深度优先遍历

遍历

  • 图的遍历是指从图中的某一顶点出发,按照一定的策略访问图中的每一个顶点。当然,每个顶点有且只能被访问一次。
  • 在图的遍历中,深度优先和广度优先是最常使用的两种遍历方式。这两种遍历方式对无向图和有向图都是适用的,并且都是从指定的顶点开始遍历的。

深度优先遍历

简单介绍

  • 深度优先遍历也叫深度优先搜索(Depth First Search)。
  • 遍历规则:不断地沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。具体点,给定一图G=<V,E>,用visited[i]表示顶点i的访问情况,则初始情况下所有的visited[i]都为false。假设从顶点V0开始遍历,则下一个遍历的顶点是V0的第一个邻接点Vi,接着遍历Vi的第一个邻接点Vj,直到所有的顶点都被访问过。
  • 所谓的第一个是指在某种存储结构中(邻接矩阵、邻接表),所有邻接点中存储位置最近的,通常指的是下标最小的或元素最小的。

遍历过程

  • 在遍历的过程中有两种情况经常出现:
    • 某个顶点的邻接点都已被访问过的情况,此时需回溯已访问过的顶点。
    • 图不连通,所有的已访问过的顶点都已回溯完了,仍找不出未被访问的顶点。此时需从下标0开始检测visited[i],找到未被访问的顶点i,从i开始新一轮的深度搜索。
  • 举个例子
    • V0->V1->V3->V2->V4
    • V1->V3->V0->V2->V4
    • V2->V0->V1->V3->V4
    • V3->V0->V1->V2->V4
    • V4->V2->V0->V1->V3

代码分析

  • 深度优先遍历——使用一个栈和一个无序列表来实现,栈用于管理遍历,无序列表用于存储遍历结果
    • 第一步:起始顶点进入栈。
    • 第二步:从栈中取出起始顶点加入无序列表的末端,标记为已访问,让与该顶点相连的顶点加入栈中。
    • 第三步:重复第二步的操作,每次取出栈顶元素加入无序列表,把顶点标记为已访问,直至栈为空。
  • 邻接矩阵实现的图中的深度优先遍历
public Iterator<T> iteratorDFS(int startIndex)
    {
        Integer x;
        boolean found;
        StackADT<Integer> traversalStack = new LinkedStack<Integer>();
        UnorderedListADT<T> resultList = new ArrayUnorderedList<T>();
        boolean[] visited = new boolean[numVertices];// 标记判断是否访问,防止出现重复遍历的情况

        if (!indexIsValid(startIndex)) {
            throw new ElementNotFoundException("Graph");
            // return resultList.iterator();
        }

        //  numVertices用于记录顶点的个数
        for (int i = 0; i < numVertices; i++) {
            visited[i] = false;
        }
        
        traversalStack.push(new Integer(startIndex));
        resultList.addToRear(vertices[startIndex]);
        visited[startIndex] = true;
        
        // 开始循环,每次把栈顶元素添加到resultList中,将与首顶点连接的还未进入队列的顶点加入栈
        while (!traversalStack.isEmpty())
        {
            x = traversalStack.peek();
            found = false;

            //找到一个与x相邻的没有访问过的顶点,并将其入栈
            for (int i = 0; (i < numVertices) && !found; i++)
            {
                if (adjMatrix[x.intValue()][i] && !visited[i])
                {
                    traversalStack.push(new Integer(i));
                    resultList.addToRear(vertices[i]);
                    visited[i] = true;
                    found = true;
                }
            }
            if (!found && !traversalStack.isEmpty()) {
                traversalStack.pop();
            }
        }
        return new GraphIterator(resultList.iterator());
    }
  • 邻接列表实现的图中的深度优先遍历
public Iterator iteratorBFS(int startIndex){
        Integer x;
        QueueADT<Integer> traversalQueue = new LinkedQueue<Integer>();
        UnorderedListADT resultList = new ArrayUnorderedList();

        // 若所给索引值无效,抛出错误
        if (!indexIsValid(startIndex)){
            throw new ElementNotFoundException("Graph");
        }

        // 设置每个顶点是否被访问,初始设置为未访问
        boolean[] visited = new boolean[numVertices];
        for (int i = 0;i < numVertices;i++){
            visited[i] = false;
        }

        // 起始顶点进入队列,并标记为已访问
        traversalQueue.enqueue(startIndex);
        visited[startIndex] = true;

        // 开始循环,每次把队列中的首顶点添加到resultList中,将与首顶点连接的还未进入队列的顶点加入队列,并标记为已访问
        while (!traversalQueue.isEmpty()){
            x = traversalQueue.dequeue();
            resultList.addToRear(vertices.get(x).getElement());

            for (int i = 0;i < numVertices;i++){
                if (hasEdge(x,i) && !visited[i]){
                    traversalQueue.enqueue(i);
                    visited[i] = true;
                    a++;
                }
            }
        }
        return new GraphIterator(resultList.iterator());
    }
    
    // 判断两顶点之间是否有边
    public boolean hasEdge(int a,int b){
        if (a == b){
            return false;
        }
        VerticeNode vertex1 = vertices.get(a);
        VerticeNode vertex2 = vertices.get(b);
        while (vertex1 != null){
            if (vertex1.getElement() == vertex2.getElement()){
                return true;
            }
            vertex1 = vertex1.getNext();
        }
        return false;
    }

一个例子

参考资料

posted @ 2018-11-26 19:34  框框框  阅读(97)  评论(0编辑  收藏