图的深度优先和广度优先搜索算法

                                                        图的深度优先和广度优先搜索算法

      本文取自《数据结构与算法》(C语言版)(第三版),出版社是清华大学出版社。

      本博文作为学习资料整理。附书的截图:
         图的深度优先和广度优先搜索算法_第1张图片

      1.图的深度优先搜索算法:

       图的深度优先搜索算法的基本思想是:从图G的某个顶点V0出发,访问V0,然后选择一个与V0相邻且未被访问过的顶点Vi访问,再从Vi出发选择一个与Vi相邻且未被访问的顶点Vj进行访问,依此下去,直到当前被访问过的顶点的所有邻接顶点都已被访问,则按相反顺序退回到已访问的顶点序列中,如果其中的顶点还存在未被访问的相邻顶点W,则从W出发,按相同的方法继续访问。直到图中的所有顶点均被访问。

      无向图的深度优先搜索过程示意图:

                                                               图的深度优先和广度优先搜索算法_第2张图片

      其程序如下:

  #include
  #include
  #include
  #define MaxVertexNum 100
  int visited[MaxVertexNum];

  typedef struct node
  {
    int adjvex;
    struct node *nextrarc;
    int info;
  }EdgeNode;

  typedef struct vnode
  {
    char vexdate;
    EdgeNode *firstarc;
  }VertexNode;

  typedef VertexNode AdjList[MaxVertexNum];

  typedef struct
  {
    AdjList adjlist;
    int n,e;
  }ALGraph;

  int initGraph(ALGraph* aGraph);
  int mFind(char aChar, ALGraph* aGraph);
  int createHead(char aChar, ALGraph* aGraph);
  void addBody(char aChar, int aPos, ALGraph* aGraph);
  void showGraph(ALGraph* aGraph);
  void DFSTraverse(ALGraph* aGraph);
  void DFS(ALGraph* aGraph, int v);

  int main(void)
  {
    char a;
    char sep1;
    char sep2;
    int isBody=0;
    int isFinish=0;
    int headPos=-1;
    ALGraph g_graph;
    initGraph(&g_graph);

    printf("Input arcs like this ' a-> b c d',end with $\n");
    while(isFinish==0)
    {
      isBody=0;
      while(1)
      {
        //a=getChar();
        scanf("%c",&a);
        if(a=='-'||a=='\n'||a==' '||a=='>')
        {
          if(a=='>')
            isBody=1;
          continue;
        }
        if(a=='$'||a=='#')
        {
          if(a=='#')
            isFinish=1;
          break;
        }

        if(a=='>')
        {
          isBody=1;
          continue;
        }
        if(isBody==1)
        {
          addBody(a,headPos,&g_graph);
        }
        else
        {
          if((headPos=mFind(a,&g_graph))==-1)
            headPos=createHead(a,&g_graph);
        }
      }
    }
    showGraph(&g_graph);
    printf("The DFS is:\n");
    DFSTraverse(&g_graph);
    return 0;
  }

  void DFSTraverse(ALGraph* aGraph)
  {
    int i=0;
    for(i=0; in; i++)
    {
      visited[i]=0;
    }
    for(i=0; in; i++)
    {
      if(!visited[i])
        DFS(aGraph,i);
    }
  }

  void DFS(ALGraph* aGraph, int v)
  {
    EdgeNode* w;
    visited[v]=1;
    printf(" %c", aGraph->adjlist[v].vexdate);
    w=aGraph->adjlist[v].firstarc;
    for(w=aGraph->adjlist[v].firstarc; w; w=w->nextrarc)
    {
      if(!visited[w->adjvex])
        DFS(aGraph, w->adjvex);
    }
  }

  void showGraph(ALGraph* aGraph)
  {
    int i=0;
    for(i=0; in; i++)
    {
      EdgeNode* pos;
      printf("%c->", aGraph->adjlist[i]);
      pos=aGraph->adjlist[i].firstarc;
      while(pos!=NULL)
      {
        printf("%d",pos->adjvex);
        pos=pos->nextrarc;
      }
      printf("\n");
    }
  }

  void addBody(char aChar, int aPos, ALGraph* aGraph)
  {
    int inversePos;
    EdgeNode* node=(EdgeNode*) malloc(sizeof(EdgeNode));
    if((node->adjvex=mFind(aChar,aGraph))==-1)
      node->adjvex=createHead(aChar,aGraph);
    node->info=-1;
    node->nextrarc=NULL;
    if(aGraph->adjlist[aPos].firstarc==NULL)
    {
      aGraph->adjlist[aPos].firstarc=node;
    }
    else
    {
      EdgeNode* tail=aGraph->adjlist[aPos].firstarc;
      while(tail->nextrarc!=NULL)
        tail=tail->nextrarc;
      tail->nextrarc=node;
    }
    inversePos=node->adjvex;
    node=(EdgeNode*)malloc(sizeof(EdgeNode));
    node->adjvex=aPos;
    node->info=-1;
    node->nextrarc=NULL;
    if(aGraph->adjlist[inversePos].firstarc==NULL)
    {
      aGraph->adjlist[inversePos].firstarc=node;
    }
    else
    {
      EdgeNode* tail=aGraph->adjlist[inversePos].firstarc;
      while(tail->nextrarc!=NULL)
        tail=tail->nextrarc;
      tail->nextrarc=node;
    }
  }

  int createHead(char aChar, ALGraph* aGraph)
  {
    int currPos=aGraph->n;
    aGraph->adjlist[currPos].vexdate=aChar;
    aGraph->n++;
    return currPos;
  }

  int mFind(char aChar, ALGraph* aGraph)
  {
    int i=0;
    for(i=0; in; i++)
    {
      if(aChar==aGraph->adjlist[i].vexdate)
        return i;
    }
    return -1;
  }

  int initGraph(ALGraph* aGraph)
  {
    int i=0;
    aGraph->e=0;
    aGraph->n=0;
    for(i=0; iadjlist[i].firstarc=NULL;
    }
    return 0;
  }
        在VC2010 C++控制台程序下的运行结果如下截图:

      图的深度优先和广度优先搜索算法_第3张图片
  

    2.图的广度优先遍历算法:

       图的广度优先遍历算法的基本思想是:从图G的某个顶点V0出发,访问V0,然后访问V0的所有未被访问过的邻接顶点V01,V02,...,V0i,接着再按照V01,V02,...,V0i的顺序访问每一个顶点的所有未被访问过的邻接顶点。依此下去,直到图中的所有顶点均被访问过。
      无向图的广度优先搜索示意图:
                                                       图的深度优先和广度优先搜索算法_第4张图片
      其程序如下:
  #include
  #include
  #include
  #define MaxVertexNum 100

  //队列的声明
  typedef struct Qnode
  {
    int data;
    struct Qnode* next;
    struct Qnode* prev;
  }Qnode;

  typedef struct queue
  {
    Qnode* first;
    Qnode* tail;
  }Queue;

  int isQueueEmpty(Queue* pQue)
  {
    if(pQue->first==pQue->tail)
      return 1;
    else
      return 0;
  }

  Queue* queueInit(Queue* pQue)
  {
    pQue->first=(Qnode*)malloc(sizeof(Queue));
    pQue->first->data=-1;
    pQue->tail=pQue->first;
    return pQue;
  }

  Qnode* queuePull(Queue* pQue)
  {
    pQue->tail=pQue->tail->prev;
    return pQue->tail->next;
  }

  void queuePush(Queue* pQue, Qnode* pNode)
  {
    pNode->next=pQue->first;
    pQue->first->prev=pNode;
    pQue->first=pNode;
  }

  Queue* queueEmpty(Queue* pQue)
  {
    while(pQue->first!=pQue->tail)
    {
      Qnode* pCurr=pQue->first;
      pQue->first=pQue->first->next;
      free(pQue->first);
    }
    return pQue;
  }

  int visited[MaxVertexNum];

  //图的声明
  typedef struct node
  {
    int adjvex;
    struct node *nextrarc;
    int info;
  }EdgeNode;

  typedef struct vnode
  {
    char vexdate;
    EdgeNode *firstarc;
  }VertexNode;

  typedef VertexNode AdjList[MaxVertexNum];

  typedef struct
  {
    AdjList adjlist;
    int n,e;
  }ALGraph;

  int initGraph(ALGraph* aGraph);
  int mFind(char aChar, ALGraph* aGraph);
  int createHead(char aChar, ALGraph* aGraph);
  void addBody(char aChar, int aPos, ALGraph* aGraph);
  void showGraph(ALGraph* aGraph);
  void BFSTraverse(ALGraph* aGraph);
  void BFS(ALGraph* aGraph, int i, Queue* pQue, int* visited);

  int main(void)
  {
    char a;
    //char sep1;
    //char sep2;
    int isBody=0;
    int isFinish=0;
    int headPos=-1;
    ALGraph g_graph;
    initGraph(&g_graph);

    printf("Input arcs like this 'a->b c d',end with $\n");
    while(isFinish==0)
    {
      isBody=0;
      while(1)
      {
        a=getchar();
        //scanf("%c",&a);
        if(a=='-'||a=='\n'||a==' '||a=='>')
        {
          if(a=='>')
            isBody=1;
          continue;
        }
        if(a=='$'||a=='#')
        {
          if(a=='#')
            isFinish=1;
          break;
        }

        if(a=='>')
        {
          isBody=1;
          continue;
        }
        if(isBody==1)
        {
          addBody(a,headPos,&g_graph);
        }
        else
        {
          if((headPos=mFind(a,&g_graph))==-1)
            headPos=createHead(a,&g_graph);
        }
      }
    }
    showGraph(&g_graph);
    printf("The BFS is:\n");
    BFSTraverse(&g_graph);
    return 0;
  }

  void BFS(ALGraph* aGraph, int i, Queue* pQue, int* visited)
  {
    Qnode* temNode=(Qnode*)malloc(sizeof(Qnode));
    temNode->data=i;
    queuePush(pQue,temNode);
    while(isQueueEmpty(pQue)==0)
    {
      Qnode* currNode=queuePull(pQue);
      if(visited[currNode->data]==0)
      {
        EdgeNode* temarc;
        printf("%c",aGraph->adjlist[currNode->data].vexdate);
        visited[currNode->data]=1;
        temarc=aGraph->adjlist[currNode->data].firstarc;
        while(temarc!=NULL)
        {
          Qnode* insertNode=(Qnode*)malloc(sizeof(Qnode));
          insertNode->data=temarc->adjvex;   //此处指针未初始化,导致错误
          if(visited[insertNode->data]==0)
            queuePush(pQue,insertNode);
          temarc=temarc->nextrarc;
        }
      }
    }
  }

  void BFSTraverse(ALGraph* aGraph)
  {
    Queue gQueue;
    int i=0;
    for(i=0; in; i++)
    {
      visited[i]=0;
    }
    queueInit(&gQueue);
    for(i=0; in; i++)
    {
      if(visited[i]==0)
        BFS(aGraph, i, &gQueue, visited);
    }
    printf("\n");
  }

  void showGraph(ALGraph* aGraph)
  {
    int i=0;
    for(i=0; in; i++)
    {
      EdgeNode* pos;
      printf("%c->", aGraph->adjlist[i]);
      pos=aGraph->adjlist[i].firstarc;
      while(pos!=NULL)
      {
        printf(" %c", pos->adjvex);
        pos=pos->nextrarc;
      }
      printf("\n");
    }
  }

  void addBody(char aChar, int aPos, ALGraph* aGraph)
  {
    int inversePos;
    EdgeNode* node=(EdgeNode*)malloc(sizeof(EdgeNode));
    if((node->adjvex=mFind(aChar,aGraph))==-1)
      node->adjvex=createHead(aChar, aGraph);
    node->info=-1;
    node->nextrarc=NULL;
    if(aGraph->adjlist[aPos].firstarc==NULL)
      aGraph->adjlist[aPos].firstarc=node;
    else
    {
      EdgeNode* tail=aGraph->adjlist[aPos].firstarc;
      while(tail->nextrarc!=NULL)
        tail=tail->nextrarc;
      tail->nextrarc=node;
    }

    inversePos=node->adjvex;
    node=(EdgeNode*)malloc(sizeof(EdgeNode));
    node->adjvex=aPos;
    node->info=-1;
    node->nextrarc=NULL;
    if(aGraph->adjlist[inversePos].firstarc==NULL)
      aGraph->adjlist[inversePos].firstarc=node;
    else
    {
      EdgeNode* tail=aGraph->adjlist[inversePos].firstarc;
      while(tail->nextrarc!=NULL)
        tail=tail->nextrarc;
      tail->nextrarc=node;
    }
  }

  int createHead(char aChar, ALGraph* aGraph)
  {
    int currPos=aGraph->n;
    aGraph->adjlist[currPos].vexdate=aChar;
    aGraph->n++;
    return currPos;
  }

  int mFind(char aChar, ALGraph* aGraph)
  {
    int i=0;
    for(i=0; in; i++)
    {
      if(aChar==aGraph->adjlist[i].vexdate)
        return i;
    }
    return -1;
  }

  int initGraph(ALGraph* aGraph)
  {
    int i=0;
    aGraph->e=0;
    aGraph->n=0;
    for(i=0; iadjlist[i].firstarc=NULL;
    }
    return 0;
  }
        以上程序输出结果为:
              图的深度优先和广度优先搜索算法_第5张图片
    Ctrl+F5执行时,出现错误!0xcccccccc内存不能read。
              图的深度优先和广度优先搜索算法_第6张图片
    
     Debug发现程序BFS函数:insertNode->data=temarc->adjvex;处指针未初始化,导致错 误!
               图的深度优先和广度优先搜索算法_第7张图片
       Debug版中的堆栈中的局部变量(包括指针)在明确初始化之前都用0x0cc进行初始化,因此,未初始化时候的指针是指向地址0x0cccccccc的,而这段地址是处于内核地址空间,一般的应用程序是无权访问的,上面的报错就是这样产生的。因此,一旦遇到上述报错,基本可以认定程序中出现了野指针。

      另外一方面cc对应着int 3调试中断,堆栈中的存放的局部数据一般情况下是只读的,当发生意外执行堆栈里面的数据就会引发该调试中断。可以认为0x0cc就是有特殊含义的占位符,对于指针而言,它跟NULL是一个意思。

      其它具有特殊意义的占位符还有:

      0x00000000 - 一般是NULL, 也就是0, 空指针

      0xcdcdcdcd- Created but not initialized(创建但未初始化,当字符串看就是 “屯屯屯屯……”

      0xdddddddd- Deleted(删除)

      0xfeeefeee- Freed memory set by NT's heap manager(堆管理器释放的内存区域。注:发现有值为0xfeeefeee的指针,就说明对应的内存已被释放掉了)

      0xcccccccc - Uninitialized locals in VC6 when you compile w/ /GZ (当编译时没有初始化的局部变量,即野指针,当作字符串看就是“烫烫烫烫……”)

      0xabababab - Memory following a block allocated by LocalAlloc()  (局部变量内存块)


     总结:C的指针真是让人头大,灵活代价就是复杂。自己还是一个小菜鸟啊,还得不断学习。

你可能感兴趣的:(算法,C++,数据结构,面试,程序员面试宝典)