圖的路徑搜索

1. 深度優先遍歷(Depth-First Traversal)

2.1 圖的深度優先遍歷的遞歸定義

  假設給定圖G的初態是所有頂點均未曾訪問過。在G中任選一頂點v爲初始出發點(源點),則深度優先遍歷可定義如下:首先訪問出發點v,並將其標記爲已訪問過;然後依次從v出發搜索v的每個鄰接點w。若w未曾訪問過,則以w爲新的出發點繼續進行深度優先遍歷,直至圖中所有和源點v有路徑相通的頂點(亦稱爲從源點可達的頂點)均已被訪問爲止。若此時圖中仍有未訪問的頂點,則另選一個尚未訪問的頂點作爲新的源點重複上述過程,直至圖中所有頂點均已被訪問爲止。
  圖的深度優先遍歷類似於樹的前序遍歷。採用的搜索方法的特點是儘可能先對縱深方向進行搜索。這種搜索方法稱爲深度優先搜索(Depth-First Search)。相應地,用此方法遍歷圖就很自然地稱之爲圖的深度優先遍歷。

1.2 深度優先搜索的過程

設x是當前被訪問頂點,在對x做過訪問標記後,選擇一條從x出發的未檢測過的邊(x,y)。若發現頂點y已訪問過,則重新選擇另一條從x出發的未檢測過的邊,否則沿邊(x,y)到達未曾訪問過的y,對y訪問並將其標記爲已訪問過;然後從y開始搜索,直到搜索完從y出發的所有路徑,即訪問完所有從y出發可達的頂點之後,才回溯到頂點x,並且再選擇一條從x出發的未檢測過的邊。上述過程直至從x出發的所有邊都已檢測過爲止。此時,若x不是源點,則回溯到在x之前被訪問過的頂點;否則圖中所有和源點有路徑相通的頂點(即從源點可達的所有頂點)都已被訪問過,若圖G是連通圖,則遍歷過程結束,否則繼續選擇一個尚未被訪問的頂點作爲新源點,進行新的搜索過程。

2. 圖路徑搜索實際問題

求下圖中節點0到節點5的所有路徑:
這裏寫圖片描述

2.1 求解過程

第一步:建立相鄰節點存儲表,節點0與節點1和2;節點1與節點2、3和4;節點2與節點4;節點3與節點4和5;節點4與節點5;
第二步建立空棧,將其實節點0壓人棧中;

1、 我們建立一個存儲結點的棧結構,將起點0入棧,將結點0標記爲入棧狀態;
2、 從結點0出發,找到結點3的第一個非入棧狀態的鄰結點2,將結點2標記爲入棧狀態;
3、 從結點2出發,找到結點2的第一個非入棧狀態的鄰結點4,將結點4標記爲入棧狀態;
4、 從結點4出發,找到結點4的第一個非入棧狀態的鄰結點5,將結點5標記爲入棧狀態;
5、 棧頂結點5是終點,那麼,我們就找到了一條起點到終點的路徑,輸出這條路徑;
6、 從棧頂彈出結點5,將5標記爲非入棧狀態;
7、 現在棧頂結點爲5,結點5沒有除終點外的非入棧狀態的結點,所以從棧頂將結點5彈出;
8、現在棧頂結點爲4,結點4除了剛出棧的結點5之外,沒有非入棧狀態的相鄰結點,那麼我們將結點4出棧;
9、現在棧頂爲結點2,結點2除了剛出棧的結點4之外,沒有非入棧狀態的相鄰結點,那麼我們將結點2出棧;
10、現在棧頂結點爲0,從節點0出發,找到結點0的第一個非入棧狀態的鄰結點1,將結點1標記爲入棧狀態;一直查找到終點節點5。
11、重複步驟7-11,就可以找到從起點3到終點6的所有路徑;
12、棧爲空,算法結束。

求解詳細代碼如下:

#include <iostream>
#include <map>
using namespace std;
class node
{
public:
    int number;
    node *next;
    node(int a,node *b)
    {
       number=a;
       next=b;
    }
};

class stacks
{
    public:
    node * top;
    stacks(node * a=NULL)
    {
       top=NULL;
    }
    void push(int a)
    {
        if (top==NULL)
            top =new node(a,NULL);
        else top=new node(a,top);
    }
    void pop()
    {
       node *b=top;
       top=top->next;
       delete b;
    }
}; //保存已加入路徑結點的棧
node* neighbour(int a);// ,int b
int cur_node;//當前結點,即爲棧頂的結點
int next_node=8 ;//當前結點的下一個鄰接點,即剛從棧頂彈出的結點,初始化爲8
map<int,int> map_next;//每個結點的下一個鄰接點,即剛從棧頂彈出的結點

int start=0;
int end=5;//起點爲3,終點爲6
stacks aray[6]={stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL),stacks(NULL)};
stacks stack(NULL);
int states[6];//保存結點狀態的數組
int main()
{
    //初始化map_next
    for(int i=0;i<=5;i++)
    {
       map_next[i] = -1;
    }
    //初始化節點鄰接表的信息  
    aray[0].push(1);aray[0].push(2);
    aray[1].push(2);aray[1].push(3);aray[1].push(4);
    aray[2].push(4);
    aray[3].push(4);    aray[3].push(5);
    aray[4].push(5);
    stack.push(start);//將起點入棧
    states[start]=1;//將起點標記爲入棧狀態
    node* tempnode=neighbour(3);
    cout<<"鄰居節點:"<<tempnode->number<<"下一個節點:" <<tempnode->next <<endl;
    int path[6];int len=0;
    while(NULL != stack.top) {//棧不爲空
        if (stack.top->number==end){
            cout<<"end->start:   ";
            node* abc=stack.top;
            int i;
            i=0;
            while(abc->number != start){

                cout<<abc->number<<",";

                path[i++]=abc->number;
                abc=abc->next;
            }
            len=i+1;
            cout<<start <<" "<<"路徑節點數="<<len<<endl;
            //cout << "start"<<endl;//輸出已找到的路徑
            stack.pop();//將棧頂結點彈出
            states[end]=0;//清除終點的狀態
            map_next[end]=-1;
        }
        else{
            cur_node=stack.top->number;
            if(neighbour(cur_node) != NULL){//鄰居不爲空
                node *d =neighbour(cur_node);
                map_next[cur_node] = d->number;
                cur_node=d->number;
                stack.push(cur_node);
                states[cur_node]=1;
            }
            else{
                stack.pop();
                states[cur_node]=0;//刪除的棧頂節點states置爲0  通過該節點到不了目的地 
                map_next[cur_node] = -1;
            }
        }
    }
    return 0;
}

node* neighbour(int a){//,int b
    node *abc=aray[a].top;
    while ((NULL!=abc)){//結點abc不空
        if( states[abc->number]==1 )//鄰居節點已經在棧stack裏了
        {
            abc=abc->next;//所有的鄰居節點初始化成一個棧了,繼續找下一個鄰居節點 
        }
        else//不在棧stack裏
        {
            if(-1 == map_next[a])//就要abc作爲返回值  如果a是最棧頂節點 
            {
                while(NULL!=abc && states[abc->number]==1)
                {
                    abc = abc->next;
                }
                return abc;
            }
            else if(abc->number == map_next[a])  //判斷當前節點是否是a節點的鄰居節點 
            {
                abc=abc->next;
                while(NULL!=abc && states[abc->number]==1)
                {
                    abc = abc->next;
                }
                return abc; //將abc的下一個結點返回
            }
            else
            {
                abc=abc->next;
            }
        }
    }
    return NULL;
}

程序運行結果如下;
這裏寫圖片描述

發佈了61 篇原創文章 · 獲贊 49 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章