将带有字符串节点标签的边列表映射到整数标签

Map edgelist with string node labels to integer labels

我有一个边列表格式的巨大图,其中字符串作为节点标签。我想知道将字符串映射到整数的 "best" 方法是什么。输入文件如下示例:

Mike Andrew
Mike Jane
John Jane

输出(即映射文件)应为:

1 2
1 3
4 3

下面粘贴的是读取输入文件的 C 框架。有人可以告诉我如何进行吗。

#include <stdio.h>

int LoadFile(const char * filename) {
  FILE *fp = NULL;
  char node1[10];
  char node2[10];
  int idx = 0;

  fp = fopen(filename, "r");
  if (fp == NULL) {
    perror("Error");
  }

  while (fscanf(fp, "%s %s", &node1, &node2) == 2) {
    idx++;
  }

  fclose(fp);

  return idx;
}

int main(void) {
  int n = LoadFile("./test.txt");
  printf("Number of edges: %d\n", n);
  return 0;
}

您需要映射的简单实现(将字符串映射到整数)

  • 定义一个结构体来存储字符串。

        typedef struct {
           unsigned int hashed;
           char **map;
       } hash;
    
  • 定义一个函数,如果字符串不存在则将其插入到 hashmap 中,并且 return 字符串在 hashmap 中的索引。

    int insertInMap(hash *map, char *entry)

  • 将 returned 索引存储到 edge 结构中。

    edges[i].first =insertInMap(&map,first_string); edges[i].second =insertInMap(&map,second_string)

示例代码:

typedef struct {
    unsigned int first;
    unsigned int second;
} edge;

typedef struct {
    unsigned int hashed;
     char **map;
} hash;


int insertInMap(hash *map, char *entry)
{
  int i =0;
  for (i=0;i<map->hashed;i++)
  {
    if (strcmp(map->map[i],entry) == 0)
    return i+1;
  }
  /* Warning no boundary check is added */
  map->map[map->hashed++] = strdup(entry);   
  return map->hashed;
}


edge *LoadFile(const char * filename) {
  FILE *fp = NULL;
  char node1[10];
  char node2[10];
  int idx = 0;

  edge *edges;
  hash map;    

  int numEdges = 10;
  edges = malloc( numEdges * sizeof(edge));

  map.map = malloc(numEdges * sizeof(char*));
  map.hashed = 0;

  fp = fopen(filename, "r");
  if (fp == NULL) {
    perror("Error");
  }

  while (fscanf(fp, "%s %s", &node1, &node2) == 2) {
    if (idx >= numEdges)
    {
         numEdges *=2;
         edges = realloc(edges, numEdges * sizeof(edge));

         map.map = realloc(map.map, numEdges * sizeof(char*));
    }
    edges[idx].first =insertInMap(&map,node1);
    edges[idx].second =insertInMap(&map,node2);
    idx++;
  }

  fclose(fp);

  return edges;
}

稍后打印 edges

我建议您使用 Trie 数据结构。它旨在存储单词并将它们关联到一个值。

trie 相对于 hashmap 的优点如下:

  • 查找元素更快
  • 没有碰撞
  • 按字母顺序遍历 trie 或 return 所有值的简单方法
  • Straight-forward 实现(没有散列函数,没有链表......)。这是一棵简单的树。

trie 中的内存使用通常低于哈希 table,但在最坏的情况下它会使用更多内存。

用于此目的的更有效的数据结构是 DAWG (或确定性非循环有限状态自动机),但其构造要复杂得多,因此如果您的图中没有数百万个节点我建议你坚持使用 Trie。

C 中的可能实现如下: 数据结构:

#include <stdlib.h>
#include <stdio.h>

#define ALPHABET_SIZE 26
#define IMPOSSIBLE_VALUE -42

typedef struct TrieNode_struct {
    struct TrieNode_struct *children[ALPHABET_SIZE];
    int value;
} TrieNode_t;

typedef TrieNode_t *Trie_t;


TrieNode_t *new_node() {
    TrieNode_t *new_node = malloc(sizeof(TrieNode_t));
    new_node->value = IMPOSSIBLE_VALUE;
    for (int i = 0; i < ALPHABET_SIZE; i++) {
        new_node->children[i] = NULL;
    }
    return new_node;
}

int char_to_idx(char c){
    return c - 'a';
}

在 trie 中插入 string/value 对

void trie_insert_rec(TrieNode_t *node, char *str, int val, int depth) {
    if (str[depth] == '[=11=]') {
        node->value = val;
    } else {
        if (node->children[char_to_idx(str[depth])] == NULL) {
            node->children[char_to_idx(str[depth])] = new_node();
        }
        trie_insert_rec(node->children[char_to_idx(str[depth])], str, val, depth+1);
    }
}

void trie_insert(Trie_t trie, char *str, int val) {
    trie_insert_rec(trie, str, val, 0);
}

在 trie 中搜索一个值:

int trie_fetch_rec(TrieNode_t *node, char *str, int depth) {
    if (str[depth] == '[=12=]') {
        return node->value;
    } else if (node->children[char_to_idx(str[depth])] == NULL) {
        return IMPOSSIBLE_VALUE;
    } else {
        return trie_fetch_rec(node->children[char_to_idx(str[depth])], str, depth+1);
    }
}

int trie_fetch(TrieNode_t *node, char *str){
    return trie_fetch_rec(node, str, 0);
}

小toy-test

int main() {
    Trie_t trie = new_node();
    char str[5] = "john[=13=]";
    trie_insert(trie, str, 11);
    printf("%d\n", trie_fetch(trie, str));
}