【问题标题】:Map edgelist with string node labels to integer labels将带有字符串节点标签的边缘列表映射到整数标签
【发布时间】:2019-05-10 08:57:14
【问题描述】:

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

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

【问题讨论】:

    标签: c graph-theory


    【解决方案1】:

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

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

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

      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)。
    • @MOehm 我同意,而且我认为这里不需要任何散列,因为每个边的名称都是唯一的。
    • @kiranBiradar(或其他人)您能否评论一下为什么我们需要使用realloc 命令将edges 调整为numEdges * sizeof(edge) 的系数?这不会产生edges 内存块的指数扩展吗?
    • 因为你不知道文件中有多少条边。它以指数方式重新分配,因为在某些系统中内存分配成本更高。如果需要,您可以使用线性分配。
    • 供您参考“我们不需要任何哈希”:see here:)
    【解决方案2】:

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

    trie 相对于 hashmap 的优势如下:

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

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

    为此目的,一个更有效的数据结构是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 中插入字符串/值对

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

    在 trie 中搜索一个值:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      • 2015-04-20
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 1970-01-01
      • 2016-03-08
      相关资源
      最近更新 更多