1. 程式人生 > >圖的dfs遞迴(非遞迴)遍歷和bfs遍歷(鄰接表)

圖的dfs遞迴(非遞迴)遍歷和bfs遍歷(鄰接表)

1.深度優先遍歷是連通圖的一種遍歷策略.其基本思想如下:

設x是當前被訪問的頂點,在對x做過訪問的標記之後,選擇一條從x出發的未檢測過的邊(x,y),若發現頂點y已經訪問過了,則重新選擇另一條從x出發的未檢測過的邊,否則沿邊(x,y)到達未曾訪問過的y,對y訪問並將其標記為已訪問過,然後從y開始搜尋,直到搜尋完從y出發的所有路徑,即訪問完所有從y出發可達的頂點之後,才回溯到頂點x,並且再選擇一條從x出發的未檢測的邊,直到從x出發的所有的邊都已經檢測過為止;

2.廣度優先搜尋:廣度優先搜尋是一種遍歷策略;從一個頂點出發,輻射狀地優先遍歷其周圍較廣的區域,例如,從圖的某個頂點vo出發,並訪問此節點.然後依次訪問v0的各個未曾訪問的鄰接點w1,w2,w3...,然後依次從w1,w2..出發訪問各自未被訪問的鄰接點.重複此步驟,直到所有的頂點都被訪問.

上面是兩種遍歷圖的基本思想,用我寫的程式碼來看具體的過程中:如圖:

如上圖:節點ABCDEFG,我們就給每個頂點依次編號1,2,3,4,5,6;(在這裡,我們就以無向圖來說)

首先,我們輸入節點個數和關係的個數,然後依次ABCDEFG,並用相應的的結構儲存它,然後輸入每個節點之間的關係:AB,AC,AD,DF,DG,BE,EG,FG,CF,BD;用鄰接表儲存它;儲存後的示意圖:

1   A:2,3,4 ;          2   B:1,4,5 ;      3  C:1,6 ;          4   E:2,7;             5  F:3,4,7;               6 G:4,5,6

下面是我實現的圖的建立,dfs遞迴和非遞迴,以及bfs遍歷:

*************************************************************************
	> File Name: linjiebiao.c
	> Author:yang 
	> Mail:[email protected]
	> Created Time: 2015年11月26日 星期四 22時38分28秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#define MAXVEX  20
typedef struct Stack
{
    int data;
    struct Stack *next;
}LinkStack;
typedef struct Queue
{
    int data;
    struct Queue *next;
}LNode;
typedef struct
{
    LNode *front;
    LNode *rear;
}LinkQueue;
typedef struct ArcNode
{
    int adjvex;
    struct ArcNode *next;
}ArcNode;
typedef struct VertexNode
{
    char vexdata;
    ArcNode *head;
}VertexNode;
typedef struct
{
    VertexNode vertex[MAXVEX];
    int vexnum;  //頂點數 
    int arcnum;  //邊數
}AdjList;
/********************************棧的操作******************************************/
LinkStack *Init_LinkStack(LinkStack *T)
{
    T=(LinkStack *)malloc(sizeof(LinkStack));
    T->next=NULL;
    return T;
}
int IsEmpty_LinkStack(LinkStack *T)
{
    if(T->next!=NULL){
        return 0;
    }
    return 1;
}
LinkStack* Push_LinkStack(LinkStack *T,int t)
{
    LinkStack *s=(LinkStack *)malloc(sizeof(LinkStack));
    if(s==NULL){
        return NULL;
    }
    s->data=t;
    s->next=T->next;
    T->next=s;
}
LinkStack *Pop_LinkStack(LinkStack *T,int *t)
{
    LinkStack *p=T->next;
    if(T->next==NULL){
        return NULL;
    }
    *t=p->data;
    T->next=p->next;
    free(p);
}
/*************************佇列的操作****************************/
LinkQueue *Init_LinkQueue()
{
    LinkQueue *q=(LinkQueue *)malloc(sizeof(LinkQueue));
    LNode *p=(LNode *)malloc(sizeof(LNode));
    p->next=NULL;
    q->front=q->rear=p;
    return q;
}
int IsEmpty_LinkQueue(LinkQueue *q)
{
    if(q->front == q->rear){
        return 1;
    }
    return 0;
}
void EnterQueue(LinkQueue *q,int t)
{
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=t;
    s->next=NULL;
    q->rear->next=s;
    q->rear=s;
}
int OutQueue(LinkQueue *q,int *t)
{
    LNode *p;
    if(IsEmpty_LinkQueue(q)){
        printf("the Queue is Empty!\n");
        return 0;
    }else{
        p=q->front->next;
        *t=p->data;
        q->front->next=p->next;
        free(p);
        if(q->front->next==NULL){
            q->rear=q->front;
        }
        return 1;
    }
}
VertexNode *Insert(VertexNode *h,ArcNode *p) //此函式的意義是把每個連結串列根據adjvex的按從小到大的順序排列;
{
     ArcNode *pre,*cur,*q;
    cur=h->head;
    if(cur == NULL){
        p->next=cur;
       cur->next=p;
    
    }else{
        pre =h->head;
        q=h->head->next;
        while(q){
            if(p->adjvex < q->adjvex ){
                p->next=q;
                pre->next=p;
                break;
            }
            pre = q;
            q=q->next;
        }
        if(q == NULL){  //當新的節點比當前連結串列中的所有的adjvex都大時,直接插在連結串列的最後面.
            p->next==NULL;
            pre->next = p;
        }
    }
    return h;
    
}
AdjList *Created_Graph(AdjList *G)
{
    int i,j,k,n1,n2;
    ArcNode *s;
    char vex1,vex2;
    G=(AdjList *)malloc(sizeof(AdjList));
    printf("請輸入頂點的個數和邊數:");
    scanf("%d%d",&G->vexnum,&G->arcnum);
    printf("請輸入頂點:\n");
    for(i=1;i<=G->vexnum;i++)
    {
        printf("No.%d號頂點的值:",i);
        scanf(" %c",&G->vertex[i].vexdata);
        G->vertex[i].head=(ArcNode *)malloc(sizeof(ArcNode)); //為每個頭節點開闢空間;有頭節點的連結串列;
        G->vertex[i].head->next=NULL;   //頭節點指向為空;
    }
    printf("請輸入由兩個頂點構成的邊:");
    for(k=1;k<=G->arcnum;k++){
        scanf(" %c%c",&vex1,&vex2);
        for(i=1;i<=G->vexnum;i++){
            if(G->vertex[i].vexdata == vex1){  
                n1=i;
            }
            if(G->vertex[i].vexdata == vex2){
                n2=i;
            }
        }
        s=(ArcNode *)malloc(sizeof(ArcNode));
        s->adjvex = n2;
        Insert(&G->vertex[n1],s);
        /*如果是有向圖,則下面的語句去掉就行*/
         s=(ArcNode *)malloc(sizeof(ArcNode));
        s->adjvex = n1;
        Insert(&G->vertex[n2],s);
    }
    return G;
}
int visited[MAXVEX]={0};
void dfs(AdjList *G,int i)
{
  ArcNode *p;
  printf("%c ",G->vertex[i].vexdata);
  visited[i]=1;
  p=G->vertex[i].head->next; 
    while(p){
        if(visited[p->adjvex]==0){
            dfs(G,p->adjvex);
        }
        p=p->next;
    }
}
void trans_dfs(AdjList *G)
{
    int v;
    for(v=1;v<=G->vexnum;v++){
        visited[v]=0;
    }
    for(v=1;v<=G->vexnum;v++){   
        if(visited[v]==0){
            dfs(G,v);      //當圖只有一個連通分量時,此句只會執行一次;
        }
    }
}
void undfs(AdjList *G,int vo)
{
    LinkStack *T;
    ArcNode *p;
    T=Init_LinkStack(T);
    int visited[MAXVEX]={0},i, t;
    Push_LinkStack(T,vo);
    while(!IsEmpty_LinkStack(T)){
        Pop_LinkStack(T,&t);
        if(visited[t]==0){
            printf("%c ",G->vertex[t].vexdata);
            visited[t]=1;
        }
        p=G->vertex[t].head->next;
        while(p){
            if(visited[p->adjvex] == 0){
                printf("%c ",G->vertex[p->adjvex].vexdata);
                visited[p->adjvex]=1;
                Push_LinkStack(T,p->adjvex);
                p=G->vertex[p->adjvex].head->next;
            }else{
            p=p->next;
            }
    }
}
    //for(i=1;i<=G->vexnum;i++){}
}
void bfs(AdjList *G,int v)
{
    int i,t;
    ArcNode *p;
    LinkQueue *S=Init_LinkQueue();
    for(i=1;i<=G->vexnum;i++)
    {
        visited[i]=0;
    }
    visited[v]=1;
    printf("%c ",G->vertex[v].vexdata);
    EnterQueue(S,v);
    while(!IsEmpty_LinkQueue(S)){
        OutQueue(S,&t);
        p=G->vertex[t].head->next;
        while(p){
            if(visited[p->adjvex]==0){
                printf("%c ",G->vertex[p->adjvex].vexdata);
                visited[p->adjvex]=1;
                EnterQueue(S,p->adjvex);
            }
            p=p->next;
        }
    }
}
void  print(AdjList *G)
{
    ArcNode *p;
    int i;
    for(i=1;i<=G->vexnum;i++){
        printf(" %c:",G->vertex[i].vexdata);
        p=G->vertex[i].head->next;
        while(p)
        {
            printf("%d ",p->adjvex);
            p=p->next;
        }
        printf("\n");
    }
}
int main(int argc,char *argv[])
{
    AdjList *G;
    G=Created_Graph(G);
    print(G);
    printf("**************dfs遞迴遍歷*****************************\n");
    dfs(G,1);
    printf("\n");
    printf("*************dfs遞迴遍歷多個連通分量********************\n");
    trans_dfs(G);
    printf("\n");
    printf("*******************dfs非遞迴遍歷*************************\n");
    undfs(G,1);
    printf("\n");
    printf("*********************bfs遍歷****************************\n");
    bfs(G,1);
    printf("\n");
    return 0;
}

相關推薦

dfs()bfs(鄰接)

1.深度優先遍歷是連通圖的一種遍歷策略.其基本思想如下: 設x是當前被訪問的頂點,在對x做過訪問的標記之後,選擇一條從x出發的未檢測過的邊(x,y),若發現頂點y已經訪問過了,則重新選擇另一條從x出發的未檢測過的邊,否則沿邊(x,y)到達未曾訪問過的y,對y訪問並將其標

鄰接儲存有向並實現DFS+BFS)兩種

程式碼如下: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; #define MA

利用鄰接矩陣儲存無向,並實現BFSDFS+)兩種

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; //------------鄰接矩陣----------- #def

實驗四(建,無向+鄰接矩陣(BFSDFS+)),有向+鄰接BFSDFS+)),拓撲排序)

//Sinhaeng Hhjian #include<bits/stdc++.h> using namespace std; const int N=100; const int MAX=1000; int book[N], cnt; struct node{

BFS演算法DFS演算法

#include<iostream> #include<fstream> #include<queue> #include<stack> using namespace std; #define MAX 10 typedef

二叉樹前序、中序、後序( /

前語  二叉樹的遍歷是指按一定次序訪問二叉樹中的每一個結點,且每個節點僅被訪問一次。 前序遍歷  若二叉樹非空,則進行以下次序的遍歷:   根節點—>根節點的左子樹—>根節點的右子樹   若要遍歷左子樹和右子樹,仍然需要按照以上次序進行,所以前序遍歷也是一個遞

二叉樹的層次

資料結構 struct node{     int val;     node *lchild,*rchild; }; 先序非遞迴遍歷  1)  訪問結點p,並將結點P入棧;  2)  判

二叉樹的前中後序+

/** * 二叉樹節點類 * @author wj * */ class TreeNode{ int value; TreeNode left_Node; TreeNode right_Node; public TreeNode(int value) { this.value

二叉樹DFSBFS /

二叉樹DFS和BFS 遞迴/非遞迴方式 1.DFS DFS, 深度優先遍歷 (1)遞迴形式 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int

樹的廣度優先深度優先、Java實現)

在程式設計生活中,我們總會遇見樹性結構,這幾天剛好需要對樹形結構操作,就記錄下自己的操作方式以及過程。現在假設有一顆這樣樹,(是不是二叉樹都沒關係,原理都是一樣的) 1.廣度優先遍歷  英文縮寫為BFS即Breadth FirstSearch。其過程檢驗來說是對每一層

二叉樹(前序)(+

題目 Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes’ values. For example: Given binary

二叉樹(中序)(+

Binary Tree Inorder Traversal(二叉樹中序遍歷) Given a binary tree, return the inorder traversal of its nodes’ values. For example: Given binary tree{

二叉樹的

二叉樹定義結構: struct BtNode{ int data; BtNode * lchild; BtNode * rchild; }; 二叉樹有三種遍歷,前序遍歷,中序遍歷,後序遍歷 前序遍歷的順序是對每一棵樹(子樹),先訪問根節點,然後訪問左子樹,然後訪問右子樹 中序遍

二叉樹 / 模板(??)

遞迴版 void First_order_traversal(int i) //先序 { printf("%d\n", key[i]); First_order_traversal(lc[i]);

JAVA 先序、中序、後序、層序,二叉樹

定義一個二叉樹 package com.niuke.binaryTree; public class binaryTree { int data; binaryTree left; binaryTree right; public binaryTree(int

二叉樹的前中後序(&)

中序遞迴: class Solution { public: vector<int> res; vector<int> inorderTraversal(Tre

二叉樹的三種層次

1 .三種非遞迴遍歷(棧) 所要遍歷的樹是: 先序 + 中序 思路:就拿先序遍歷為例來說吧。 1.訪問根節點,根節點入棧,進入左子樹。 2.訪問左子樹的根節點,根節點入棧,進入下一層左子樹。 3.重複直到當前節點為

二叉樹,層次,反轉,輸出路徑等常見操作詳細總結

1.序言 在實際工作中,很多業務場景其實也需要一些比較巧妙的演算法來支撐,並不是業務邏輯就全是複製貼上或者說重複的程式碼寫一百遍。越是隨著演算法研究的深入,越是發現數據結構的重要性。或者說,資料結構中就蘊藏著無數精妙演算法的思想,很多演算法的思想在資料結構中體現得非常突出。而作為一種

二叉樹演算法(實現先序中序後續)(實現中序先續)

二叉樹遍歷 這兩天抓緊把二叉樹遍歷複習了一遍,遞迴實現還是一如既往地簡潔,迭代版本寫了好久還是隻實現了先序和中序,後續一直沒搞明白,有空了再更新。 遞迴實現 void RecursionBackTree(TreeNode * root) {

、棧、棧實現二叉樹的

先序遍歷的三種演算法: //遞迴實現先序遍歷 void preorderTree(binNode<Elem>* root){ if(root==NULL){ return; } else{ cout<<root->getE