构造字符串图(Levenshtein距离)

Constructing a Graph of Strings (Levenshtein Distance)

本文关键字:Levenshtein 距离 字符串      更新时间:2023-10-16

目前,在我的计算机科学课程中,我们正在讨论图以及如何使用图找到最短距离。大约一周前,我收到了一份作业,老师给了我们一个使用整数的图的代码,我们必须调整它,以便能够使用单词列表计算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;
    }
}

如果你能帮忙,那将是最受欢迎的,因为我很可能会有更多的项目与图表,我正在努力,因为不理解他们。

谢谢你,特里斯坦

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

图用邻接矩阵表示。你也可以使用邻接表来表示一个图,其中每个节点将保存一个相邻节点的数组/链表。

 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,字符串是节点的数据,而不是节点的数量。如果你需要字符串比较,c++已经为它提供了重载操作符。

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

一些答案:

。你问为什么下面的numVertices被设置为0:

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

。看看g的声明——它是默认初始化的:

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

现在看看graph的定义——它没有构造函数:

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

边默认会被初始化因为向量有构造函数。但是numVertices是一种基本类型,所以它将包含碰巧在那个内存位置的任何随机值-所以这意味着它需要手动初始化。这就是为什么initGraph不需要初始化边,但它需要初始化numVertices。

。您问如何在知道max()返回两个整数中较大的一个的情况下找到两个std::字符串中较大的一个:

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

。根据http://www.cplusplus.com/reference/algorithm/max/max使用"函数使用operator<(或comp,如果提供的话)来比较值。"但是std::字符串可以使用<</p>

。你问向量的向量:

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

。你可以用[]来访问一个向量,所以如果你有一个矩阵类型的变量x,你可以说x[0],这将返回一个ivec(因为这是存储在矩阵向量中的对象类型)。所以如果你输入x[0][0]它会返回存储在ivec中的第一个整数它是由x[0]返回的。要将其改为字符串,只需输入:

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

如果你愿意,你也可以重命名变量。

您还需要#include <string>