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

时间:2019-05-10 08:57:14

标签: c graph-theory

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

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;
}

2 个答案:

答案 0 :(得分:2)

您需要天真的地图实现(将字符串映射为整数)

  • 定义如下的结构以存储字符串。

        typedef struct {
           unsigned int hashed;
           char **map;
       } hash;
    
  • 定义一个函数,该函数将在不存在字符串的情况下将其插入到哈希图中,并返回哈希图中的字符串索引。

    int insertInMap(hash *map, char *entry)

  • 将返回的索引存储到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

答案 1 :(得分:1)

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

相对于哈希图,特里树的优点如下:

  • 查找元素更快
  • 没有碰撞
  • 轻松遍历trie或按字母顺序返回所有值的方法
  • 直接实现(没有哈希函数,没有链表...)。这是一棵简单的树。

在trie中,内存使用通常比在哈希表中低,但是在最坏的情况下,它将使用更多的内存。

DAWG (或确定性非循环有限状态自动机)为此目的提供了更为有效的数据结构,但是它的构造要复杂得多,因此,如果您的图形中没有数百万个节点, d建议您坚持使用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';
}

在字符串中插入一个字符串/值对

void trie_insert_rec(TrieNode_t *node, char *str, int val, int depth) {
    if (str[depth] == '\0') {
        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);
}

在特里搜索值:

int trie_fetch_rec(TrieNode_t *node, char *str, int depth) {
    if (str[depth] == '\0') {
        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);
}

微小的玩具测试

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