zoukankan      html  css  js  c++  java
  • 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;
        }
    

    一个例子

    参考资料

  • 相关阅读:
    vim编辑器入门
    线程概念
    forkJoin
    join()方法跟踪
    mybatis 注解和xml 优缺点
    sql 索引 sql_safe_updates
    spirngcloud文件
    springCloud com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
    创建线程池的四种方式
    ThreadLocal
  • 原文地址:https://www.cnblogs.com/PFrame/p/10022390.html
Copyright © 2011-2022 走看看