鄰接鏈表實現下的搜索兩點之間所有路徑的算法

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

1.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、棧爲空,算法結束。

C++版 求解詳細代碼如下:

#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;//起點爲0,終點爲5
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;
}

程序運行結果如下;
在這裏插入圖片描述

C# 版 求解詳細代碼如下:

using System;
using System.Collections.Generic;

public class GetRoute
{
    //保存已加入路徑結點的棧
    public node neighbour(int a)
    {
        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;
    }
    public int cur_node; //當前結點,即爲棧頂的結點
    //public static int next_node = 8; //當前結點的下一個鄰接點,即剛從棧頂彈出的結點,初始化爲8
    public Dictionary<int, int> map_next = new Dictionary<int, int>(); //每個結點的下一個鄰接點,即剛從棧頂彈出的結點
    //點總數
    public int totalPoint = 1000;
    public int start = 3;
    public int end = 5; //起點爲3,終點爲6
    public List<stacks> aray = new List<stacks>();
    static stacks stack = new stacks();
    public int[] states; //保存結點狀態的數組

    //路徑搜索結果
    public List<RouteList> routeList = new List<RouteList>();

    public void Test()
    {
        //代表當前有效路徑序號
        int routeIndex = -1;

        states = new int[totalPoint]; //保存結點狀態的數組
                                      //初始化map_next
        for (int i = 0; i < totalPoint; i++)
        {
            map_next[i] = -1;
        }
        //for (int i = 0; i < totalPoint; i++)
        //{
        //    aray.Add(new stacks());
        //}
        //初始化節點鄰接表的信息  
        //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] = 0; //將起點標記爲入棧狀態

        int[] path = new int[totalPoint];
        int len = 0;
        while (null != stack.top) //棧不爲空
        {
            if (stack.top.number == end)
            {
                Console.Write("end->start:   ");
                routeIndex++;
                routeList.Add(new RouteList());
                node abc = stack.top;
                int i;
                i = 0;
                while (abc.number != start)
                {

                    Console.Write(abc.number);
                    Console.Write(",");
                    routeList[routeIndex].route.Add(abc.number);
                    path[i++] = abc.number;
                    abc = abc.next;
                }
                len = i + 1;
                Console.Write(start);
                routeList[routeIndex].route.Add(start);
                Console.Write(" ");
                Console.Write("路徑節點數=");
                Console.Write(len);
                Console.Write("\n");
                //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;
                }
            }
        }
        foreach (var item in routeList)
        {
            //反轉順序
            item.route.Reverse();
        }
    }
}
//路徑結果類
public class RouteList
{
    public List<int> route = new List<int>();
}
public class node
{
    public int number;
    public node next;
    public node(int a, node b)
    {
        number = a;
        next = b;
    }
}

public class stacks
{
    public node top;
    public stacks()
    {
    }
    //C++ TO C# CONVERTER NOTE: Overloaded method(s) are created above to convert the following method having default parameters:
    //ORIGINAL LINE: stacks(node * a = null)
    public stacks(node a)
    {
        top = null;
    }
    public void push(int a)
    {
        if (top == null)
            top = new node(a, null);
        else
            top = new node(a, top);
    }
    public void pop()
    {
        node b = top;
        top = top.next;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章