【问题标题】:reading integers from a file (in C) which including data of a directed graph从包含有向图数据的文件(C 语言)中读取整数
【发布时间】:2018-05-26 10:27:27
【问题描述】:

假设我创建了一个名为 graph-file.txt 的文件,其中包含一个

的数据

有向图如下:

7
{5, 2, 3}, {1,5}, {}, { }, {3}, { }, { }

文件的第一行显示顶点的数量(在这种情况下为 7)。 第二行描述了每个顶点的邻居 N+(v)。例如,从顶点 1 开始,边指向顶点 5,2 和 3,而对于顶点 7,没有边指向该图中的任何其他顶点。

我想问一下,从该文件中读取 BFS 算法所需的边缘信息(如上所述)的方法是什么?

我对 BFS 使用以下函数:

#define SIZE 40

struct queue {
    int items[SIZE];
    int front;
    int rear;
};

struct queue* createQueue();
void enqueue(struct queue* q, int);
int dequeue(struct queue* q);
void display(struct queue* q);
int isEmpty(struct queue* q);
void printQueue(struct queue* q);

struct node
{
    int vertex;
    struct node* next;
};

struct node* createNode(int);

struct Graph
{
    int numVertices;
    struct node** adjLists;
    int* visited;
};

struct Graph* createGraph(int vertices);
void addEdge(struct Graph* graph, int src, int dest);
void printGraph(struct Graph* graph);
void bfs(struct Graph* graph, int startVertex);


void bfs(struct Graph* graph, int startVertex) {

    struct queue* q = createQueue();

    graph->visited[startVertex] = 1;
    enqueue(q, startVertex);

    while(!isEmpty(q)){
        printQueue(q);
        int currentVertex = dequeue(q);
        printf("Visited %d\n", currentVertex);

       struct node* temp = graph->adjLists[currentVertex];

       while(temp) {
            int adjVertex = temp->vertex;

            if(graph->visited[adjVertex] == 0){
                graph->visited[adjVertex] = 1;
                enqueue(q, adjVertex);
            }
            temp = temp->next;
       }
    }
}


struct node* createNode(int v)
{
    struct node* newNode = malloc(sizeof(struct node));
    newNode->vertex = v;
    newNode->next = NULL;
    return newNode;
}


struct Graph* createGraph(int vertices)
{
    struct Graph* graph = malloc(sizeof(struct Graph));
    graph->numVertices = vertices;

    graph->adjLists = malloc(vertices * sizeof(struct node*));
    graph->visited = malloc(vertices * sizeof(int));


    int i;
    for (i = 0; i < vertices; i++) {
        graph->adjLists[i] = NULL;
        graph->visited[i] = 0;
    }

    return graph;
}

void addEdge(struct Graph* graph, int src, int dest)
{
    // Add edge from src to dest
    struct node* newNode = createNode(dest);
    newNode->next = graph->adjLists[src];
    graph->adjLists[src] = newNode;

    // Add edge from dest to src
    newNode = createNode(src);
    newNode->next = graph->adjLists[dest];
    graph->adjLists[dest] = newNode;
}

struct queue* createQueue() {
    struct queue* q = malloc(sizeof(struct queue));
    q->front = -1;
    q->rear = -1;
    return q;
}


int isEmpty(struct queue* q) {
    if(q->rear == -1) 
        return 1;
    else 
        return 0;
}

void enqueue(struct queue* q, int value){
    if(q->rear == SIZE-1)
        printf("\nQueue is Full!!");
    else {
        if(q->front == -1)
            q->front = 0;
        q->rear++;
        q->items[q->rear] = value;
    }
}

int dequeue(struct queue* q){
    int item;
    if(isEmpty(q)){
        printf("Queue is empty");
        item = -1;
    }
    else{
        item = q->items[q->front];
        q->front++;
        if(q->front > q->rear){
            printf("Resetting queue");
            q->front = q->rear = -1;
        }
    }
    return item;
}

void printQueue(struct queue *q) {
    int i = q->front;

    if(isEmpty(q)) {
        printf("Queue is empty");
    } else {
        printf("\nQueue contains \n");
        for(i = q->front; i < q->rear + 1; i++) {
                printf("%d ", q->items[i]);
        }
    }    
}

【问题讨论】:

  • 使用递归下降解析器是一个好方法。编写一个函数getedges,你可以调用它7次。编写一个 词法分析 函数,该函数返回单个字符,例如 '{'',''}',或从相邻的数字字符运行转换而来的整数。在getedges 中,调用你的词法分析器来检查你是否看到了'{',然后反复调用它来获取整数和逗号,直到你找到'}',然后返回。在编写此类函数来解析字符串中已包含的文本时,我发现将 char ** 指针向下传递给 getedges 和词法分析器函数很有用。
  • @SteveSummit 没有简单的方法来传递逗号和括号并只读整数吗?
  • 这部分取决于您想如何处理(如果您想尝试处理)格式错误的输入。
  • 您是否可以控制输入格式,或者它是强加给您的?如果您对大括号和逗号不感兴趣,如果您宁愿忽略它们,那么为什么不重新定义输入格式以首先不包括它们呢?一种更简单、更易于解析的输入格式是每个节点一行,每一行包含一个节点的空格分隔的边号。
  • @SteveSummit 这是强加给我的。你能告诉我如何忽略大括号逗号吗?如何重新定义输入格式以首先不包括它们?

标签: c file graph


【解决方案1】:

假设输入是有效的,作为一个有趣的练习,我尝试提出所需的最小解析器。对于 x86_64,它使用少量寄存器编译为 less than 40 instructions

void edge(int from, int to);

void parse(void)
{
    int v = 0;
    for (;;) {
        const int c = getchar();
        if (c == EOF)
            return;

        // Next 'from' vertex?
        if (c == '{') {
            ++v;
            continue;
        }

        // Ignore vertex count
        if (v == 0)
            continue;

        // Found 'to' vertex?
        int w = c - '0';
        if (w < 0 || w > 9)
            continue;

        // Parse 'to' vertex
        for (;;) {
            const int d = getchar() - '0';
            if (d < 0 || d > 9)
                break;
            w = w * 10 + d;
        }

        edge(v, w);
    }
}

当然,如果您需要验证输入,那么您将需要更多的状态来处理逗号、右括号、不匹配的顶点数、超出范围的顶点数、无效字符等。

【讨论】:

  • 这是 StackOverflow,不是 Code Golf。不验证其输入的解析器一直是安全漏洞的主要原因之一。我认为这种危险做法的泛滥在这里是不合适的。
  • 也在这里比较答案:meta.stackoverflow.com/questions/368509/…
  • @HermannDöppes:这个答案不是代码高尔夫——它不是为了最小化源代码长度而编写的。相反,它努力成为一个非常简单(最简单?)的解析器。最重要的是,OP 指出不需要输入验证。最后,安全漏洞仅在某些情况下很重要,并非所有软件都会受到恶意/不受信任的输入。
  • @HermannDöppes:顺便说一下,在这种特殊情况下,代码很难被利用——它甚至不需要 x86 中的内存,并且可以证明在 O(n) 步骤 w.r.t 中完成。输入(如果需要,检查d == EOF)。边缘本身可以在edge() 中独立验证。
猜你喜欢
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-14
  • 2017-03-18
  • 1970-01-01
  • 2021-12-31
相关资源
最近更新 更多