简体   繁体   English

在迭代深度优先搜索(DFS)算法中确定堆栈大小

[英]Determining stack size in iterative depth first search (DFS) algorithm

I have written an iterative implementation of depth first search (DFS) algorithm in C++. 我用C ++编写了深度优先搜索(DFS)算法的迭代实现。 It produces correct visiting order as output. 它产生正确的访问顺序作为输出。 Algorithm goes like that: 算法是这样的:

  1. Initiate visited[] array with false values. 用错误的值初始化visit []数组。
  2. Push first vertex into stack. 将第一个顶点推入堆栈。
  3. Pop element from stack and assign it to variable v. 从堆栈中弹出元素,并将其分配给变量v。
  4. If v was not visited (visited[v] == false), print v and set it as visited. 如果没有访问v(visited [v] == false),则打印v并将其设置为“访问”。
  5. Push every not visited neighbors of v into stack (biggest value first). 将所有v的未访问邻居推入堆栈(首先取最大值)。
  6. Repeat 3-5 until stack is empty. 重复3-5,直到堆栈为空。

The problem I have is to determine proper Stack s size in DFSIteratively method of GraphUtilities class. 我的问题是在GraphUtilities类的DFSIteratively方法中确定正确的Stack大小。 My teacher stated it has to be stored as array. 我的老师说它必须存储为数组。 I am able to calculate it's size using (n * n - 3 * n + 2) / 2 equation, where n is vertex set count, assuming no visited vertex is ever pushed into stack and full graph was provided (most dense graph; pessimistic case). 我可以使用(n * n-3 * n + 2)/ 2等式计算它的大小,其中n是顶点集计数,假设没有访问过的顶点被压入堆栈并提供了全图(最密集的图;悲观的)案件)。

Can stack size be determined for factual graph, which most likely will not be a full graph? 是否可以为事实图确定堆栈大小,而事实图很可能不是完整图? Or, better yet, is there a way to push every vertex into stack only once? 或者更好的是,是否有一种方法可以将每个顶点仅压入堆栈一次? I know recursive implementations solves this limitation, as well as using dynamic data struct as stack, but my project assumes using array (educational purposes, that's what I was told). 我知道递归实现可以解决此限制,并且可以使用动态数据结构作为堆栈,但是我的项目假定使用数组(出于教育目的,这就是我所知道的)。

#include <iostream>
#include <stdexcept>
#include <list>
#include <sstream>
#include <fstream>
#include <cstdlib>
using namespace std;

template <typename T> class Stack
{
private:
    int ptr;
    T *stackArray;
    int stackSize;

public:
    Stack(int n)
    {
        ptr = -1;
        stackSize = n;
        stackArray = new T[stackSize];
    }

    ~Stack()
    {
        delete[] stackArray;
    }

    void push(T x)
    {
        if(ptr + 1 == stackSize)
            throw length_error("Cannot push.");

        stackArray[++ptr] = x;
    }

    T top()
    {
        if(ptr == -1)
            throw length_error("Cannot pop.");

        return stackArray[ptr];
    }

    T pop()
    {
        T temp = top();
        ptr--;

        return temp;
    }

    bool isEmpty()
    {
        if(ptr == -1)
            return true;

        return false;
    }
};

class Graph
{
private:
    int numberOfVertices;
    list<int> *adjacencyList;

public:
    Graph(int n)
    {
        numberOfVertices = n;
        adjacencyList = new list<int>[numberOfVertices];
    }

    int getNumberOfVertices()
    {
        return numberOfVertices;
    }

    list<int>* getAdjacencyList(int v)
    {
        return &adjacencyList[v];
    }

    list<int>* getAdjacencyList()
    {
        return adjacencyList;
    }

    ~Graph()
    {
        delete[] adjacencyList;
    }

    void addEdge(int v1, int v2)
    {
        adjacencyList[v1].push_back(v2);
    }
};

class GraphUtilities
{
private:
    bool *visited;
    stringstream visitingOrder;

public:
    void DFSIteratively(Graph &g, int v)
    {

        int n = g.getNumberOfVertices();
        list<int> *adjacencyList = g.getAdjacencyList();
        visited = new bool[n];
        Stack<int> *s;

        // Determine size of stack.
        if(n == 1)
            s = new Stack<int>(1);
        else
            s = new Stack<int>( (n*n - 3*n + 2)/2 );

        for(int i = 0; i < n; i++)
            visited[i] = false;

        s -> push(v);

        while(!(s -> isEmpty()))
        {
            v = s -> pop();

            if(!visited[v])
            {
                visitingOrder << v << " ";
                visited[v] = true;

                for(list<int>::reverse_iterator i = adjacencyList[v].rbegin(); i != adjacencyList[v].rend(); ++i)
                    if(!(visited[*i]))
                        s -> push(*i);
            }
        }
        cout << visitingOrder.str() << endl;

        visitingOrder.clear();
        delete[] visited;
        delete s;
    }
};

int main()
{
    Graph graph(6);
    GraphUtilities utilities;

    graph.addEdge(0, 1);
    graph.addEdge(0, 2);
    graph.addEdge(0, 4);
    graph.addEdge(1, 0);
    graph.addEdge(1, 5);
    graph.addEdge(2, 0);
    graph.addEdge(2, 5);
    graph.addEdge(3, 5);
    graph.addEdge(4, 0);
    graph.addEdge(5, 1);
    graph.addEdge(5, 2);
    graph.addEdge(5, 3);

    utilities.DFSIteratively(graph, 4);

    return 0;
}

My graph (paint quality): http://i.imgur.com/pkGKNFo.jpg 我的图表(画质): http : //i.imgur.com/pkGKNFo.jpg

Output: 输出:

4 0 1 3 5 2 4 0 1 3 5 2

Probably you might be happier if you'll use additional addedToStack flag array of size n next to your visited array. 如果在visited数组旁边使用大小为n其他addedToStack标志数组,可能会更快乐。 So if you'll add a vertex to stack it will not be visited but added to stack. 因此,如果将顶点添加到堆栈,它将不会被访问,而是会添加到堆栈。 There is no need in adding it to the stack again. 无需再次将其添加到堆栈中。 Check addedToStack flag each time you want to add a vertex to the stack. 每次要将顶点添加到堆栈时,请检查addedToStack标志。 Eventually every vertex will occur in the stack not more than once and the stack size will be n at most. 最终,每个顶点在堆栈中出现的次数不会超过一次,并且堆栈大小最多为n

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM