构造一个字符串图(Levenshtein距离)

时间:2014-05-14 01:51:15

标签: c++ graph levenshtein-distance

目前,在我的计算机科学课程中,我们正在讨论图表以及如何使用图表找到最短距离。大约一周前我收到了一个作业,老师给了我们使用整数的图表代码,我们必须调整它以便能够使用单词列表计算Levenshtein距离。我遇到的问题是,我真的不明白图表是如何工作的,足以操纵图形。我试过用c ++搜索谷歌图,但我发现的东西都不像我给出的程序类型。

我们刚刚在链接列表上完成了一个单元,我认为图形操作类似吗?我知道每个节点都会指向许多其他节点,但是在我有2000个单词都指向对方的情况下,如何在不声明结构中的许多节点的情况下跟踪每个节点的2000个指针?我相信(不是100%)在程序中我给了我的老师使用了一个整数向量的向量来跟踪,但我不知道如何实现它。

我不是要求任何人充分评论每一行,因为这是一项庞大的工作,但如果有人能够大致解释我将如何完成我上面提到的内容并且可能会阅读代码并让我粗略地理解一些部分意味着(我会对某些部分发表评论,我特别难以理解)我将非常感激。

以下是我们给出的代码:

#include <iostream>
#include <vector>
#include <algorithm> //for max<>
#include <limits>

using namespace std;

typedef vector <int> ivec;
typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement
typedef vector <bool> bvec;

struct graph
{
    imatrix edges; //list of attached vertices for each node
    int numVertices;
};

//I understand the ostream overloading
ostream & operator << (ostream & stream, ivec &vec)
{
    for (int i = 0; i < vec.size(); i++)
    {
        stream << vec[i] << " ";
    }
    return stream;
}

ostream & operator << (ostream & stream, graph &g)
{
    stream << endl << "numVert = " << g.numVertices << endl;
    for (int i = 0; i < g.numVertices; i++)
    {
        stream << "vertex = " << i+1 << " | edges = " << g.edges[i] << endl;
    }
    return stream;
}

const int sentinel = -1;

bvec inTree;
ivec distanceNodes;
ivec parents;

void initGraph(graph * g);
void insertEdge(graph * g, int nodeNum, int edgeNum);
void initSearch(graph * g);
void shortestPath(graph * g, int start, int end);

int main()
{
    //I understand the main, the two numbers in insertEdge are being hooked together and the two numbers in shortestPath are what we are looking to connect in the shortest way possible
    graph g;
    initGraph(&g);
    insertEdge(&g, 1, 2);
    insertEdge(&g, 1, 3);
    insertEdge(&g, 2, 1);
    insertEdge(&g, 2, 3);
    insertEdge(&g, 2, 4);
    insertEdge(&g, 3, 1);
    insertEdge(&g, 3, 2);
    insertEdge(&g, 3, 4);
    insertEdge(&g, 4, 2);
    insertEdge(&g, 4, 3);
    insertEdge(&g, 4, 5);
    insertEdge(&g, 5, 4);
    insertEdge(&g, 6, 7);
    insertEdge(&g, 7, 6);
    cout << "The graph is " << g << endl;
    shortestPath(&g, 1, 5);
    shortestPath(&g, 2, 4);
    shortestPath(&g, 5, 2);
    shortestPath(&g, 1, 7);
    return 0;
}

void initGraph(graph * g)
{
    g -> numVertices = 0; //Why set the number of vertices to 0?
}

void insertEdge(graph * g, int nodeNum, int edgeNum)
{
    int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other
    numVertices = max(1, numVertices);
    if (numVertices > g->numVertices)
    {
        for (int i = g->numVertices; i <= numVertices; i++)
        {
            ivec nodes;
            if (g->edges.size() < i)
            {
                g -> edges.push_back(nodes);
            }
        }
        g->numVertices = numVertices;
    }
    g->edges[nodeNum - 1].push_back(edgeNum);
}

void initSearch(graph * g) //I believe this function simply resets the values from a previous search
{
    if (g == NULL)
    {
        return;
    }
    inTree.clear();
    distanceNodes.clear();
    parents.clear();
    for (int i = 0; i <= g->numVertices; i++)
    {
        inTree.push_back(false);
        distanceNodes.push_back(numeric_limits <int> :: max());
        parents.push_back(sentinel);
    }
}

void shortestPath(graph * g, int start, int end)
{
    //Very confused about how this function works
    initSearch(g);
    int edge;
    int curr; //current node
    int dist;
    distanceNodes[start] = 0; 
    curr = start;
    while (! inTree[curr])
    {
        inTree[curr] = true;
        ivec edges = g->edges[curr - 1];
        for (int i = 0; i < edges.size(); i++)
        {
            edge = edges[i];

            if (distanceNodes[edge] > distanceNodes[curr] + 1)
            {
                distanceNodes[edge] = distanceNodes[curr] + 1;
                parents[edge] = curr;
            }
        }
        curr = 1;
        dist = numeric_limits <int> :: max();
        for (int i = 1; i <= g->numVertices; i++)
        {
            if ((!inTree[i]) && (dist > distanceNodes[i]))
            {
                dist = distanceNodes[i];
                curr = i;
            }
        }
    }
    ivec path;
    if (distanceNodes[end] == numeric_limits <int> :: max()) //is there a numeric_limits <string> :: max?
    {
        cout << "No way from " << start << " to " << end << endl;
    }
    else
    {
        int temp = end;
        while (temp != start)
        {
            path.push_back(temp);
            temp = parents[temp];
        }
        path.push_back(start);
        reverse(path.begin(), path.end());
        cout << "From " << start << " to " << end << " is " << path << endl;
    }
}

如果你可以提供帮助,那将是非常受欢迎的,因为我很可能会有更多带有图表的项目,而且由于不了解它而我正在努力。

谢谢你, 特里斯坦

2 个答案:

答案 0 :(得分:0)

一些答案​​:

Q值。你问为什么numVertices在下面被设置为0:

void initGraph(graph * g)
{
    g -> numVertices = 0; //Why set the number of vertices to 0?
}

一个。看看g的声明 - 默认初始化:

int main()
{
    graph g;
    ....
}

现在看一下图的定义 - 它没有构造函数:

struct graph
{
    imatrix edges; //list of attached vertices for each node
    int numVertices;
};

因此,默认情况下会正确初始化边缘,因为向量具有构造函数。但numVertices是一种原始类型,因此它将包含恰好位于该内存位置的任何随机值 - 这意味着它需要手动初始化。这就是为什么initGraph不需要初始化边缘但是它确实需要初始化numVertices。

Q值。你问过如何找到两个std :: strings中较大的一个,知道max()返回两个整数中较大的一个:

int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other

一个。根据{{​​3}} max使用&#34;该函数使用运算符&lt; (或comp,如果提供)比较值。&#34;但是可以使用&lt;比较std :: strings。操作员所以确实没有问题。

Q值。你问过一个矢量矢量:

typedef vector <int> ivec;
typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement

一个。你可以用[]访问一个向量,所以如果你有一个名为x of imatrix类型的变量,你可以说x [0]会返回一个ivec(因为那是存储在imatrix向量中的对象类型。所以如果你说x [0] [0]将返回存储在x [0]返回的ivec中的第一个整数。要将其更改为使用字符串,只需说:

typedef vector <std::string> ivec;
typedef vector <ivec> imatrix;

如果需要,您还可以重命名变量。

您还需要#include <string>

答案 1 :(得分:0)

typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement

此处图表显示为Adjacency Matrix。您还可以使用Adjacency List表示图形,其中每个节点将包含相邻节点的数组/链接列表。

 g -> numVertices = 0; //Why set the number of vertices to 0?

初始化图形,启动时顶点/节点数为零。当使用insertEdge方法插入边和节点时,将更新此编号。

int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other

虽然您尚未发布完整代码,但我认为在插入边缘之前,最大值用于添加所需数量的顶点

ivec nodes;
if (g->edges.size() < i)
{
  g -> edges.push_back(nodes);
}

上面的代码插入新的顶点。对于您的版本,您可能会integer comparison,而不是string,string是节点的数据,而不是节点的数量。如果你需要字符串比较,C ++已经为此重载了运算符。

关于 initSearch shortestPath 方法,后者使用算法找到节点之间的最短路径(我不知道哪个,你可以搜索),以及在搜索最短路径之前,前一种方法初始化将用于搜索的值。例如,它可以将每对节点之间的距离设置为 infinity ,当它们之间找到路径时,它将被更新。