【问题标题】:double pointer to a node指向节点的双指针
【发布时间】:2019-04-19 23:04:30
【问题描述】:

我的怀疑只是关于指针,如果我们使用 *head,这里 head 是一个指向 Queue 的双指针,而不是我们访问 main 内部的位置(或传递的地址)但是当我们简单地使用 head 时我们只在当前函数中使用标题,它将保存指向 Queue 的指针的地址,现在当我们这样做时 head=&(*head)->next 因为 (*head)->next 本身就是一个地址,而当我们之前使用 &这将创建一个单独的块,并将创建一个内存块并保存 (*head)->next 的地址,我们将该地址分配给 head 我有这个疑问,因为它就像一个两步过程,我们不能直接把 (*head)->next 放在head 里面,我们需要传递地址的地址,因为我们需要一个额外的块,当循环将执行 n 次比会有 n 个中间块? 请告诉我我是否正确 并告诉正确的逻辑谢谢

void queue_push(Queue **head, int d, int p)
{
    Queue *q = queue_new(d, p);

    while (*head && (*head)->priority < p) {
        head = &(*head)->next;
    }

    q->next = *head;
    *head = q;
}

完整程序是

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

    typedef struct Queue Queue;

    struct Queue {
        int data;
        int priority;
        Queue *next;
    };

    Queue *queue_new(int d, int p)
    {
        Queue *n = malloc(sizeof(*n));

        n->data = d;
        n->priority = p;
        n->next = NULL;

        return n;
    }

    int queue_pop(Queue **head)
    {
        assert(*head);

        Queue *old = *head;
        int res = old->data;

        *head = (*head)->next;
        free(old);

        return res;
    }

    void queue_remove(Queue **head, int data)
    {
        while (*head && (*head)->data != data) {
            head = &(*head)->next;
        }

        if (*head) queue_pop(head);
    }

    void queue_push(Queue **head, int d, int p)
    {
        Queue *q = queue_new(d, p);

        while (*head && (*head)->priority < p) {
            head = &(*head)->next;
        }

        q->next = *head;
        *head = q;
    }


    int queue_empty(Queue *head)
    {
        return (head == NULL);
    }

    void queue_print(const Queue *q)
    {
        while (q) {
            printf("%d[%d] ", q->data, q->priority);
            q = q->next;
        }

        puts("$");
    }

    typedef struct Graph Graph;
    typedef struct Edge Edge;

    struct Edge {
        int vertex;
        int weight;
        Edge *next;
    };

    struct Graph {
        int v;
        Edge **edge;
        int *dist;
        int *path;
    };

    Graph *graph_new(int v)
    {
        Graph *G = malloc(sizeof(*G));

        G->v = v;
        G->edge = calloc(v, sizeof(*G->edge));
        G->dist = calloc(v, sizeof(*G->dist));
        G->path = calloc(v, sizeof(*G->path));

        return G;
    }

    void graph_delete(Graph *G)
    {
        if (G) {
            for (int i = 0; i < G->v; i++) {
                Edge *e = G->edge[i];

                while (e) {
                    Edge *old = e;

                    e = e->next;
                    free(old);
                }
            }

            free(G->edge);
            free(G->dist);
            free(G->path);
            free(G);
        }
    }

    Edge *edge_new(int vertex, int weight, Edge *next)
    {
        Edge *e = malloc(sizeof(*e));

        e->vertex = vertex;
        e->weight = weight;
        e->next = next;

        return e;
    }

    void graph_edge(Graph *G, int u, int v, int w)
    {
        G->edge[u] = edge_new(v, w, G->edge[u]);
        G->edge[v] = edge_new(u, w, G->edge[v]);
    }

    void dijkstra(const Graph *G, int s)
    {
        Queue *queue = NULL;

        for (int i = 0; i < G->v; i++) G->dist[i] = -1;
        G->dist[s] = 0;

        queue_push(&queue, s, 0);

        while (!queue_empty(queue)) {
            int v = queue_pop(&queue);
            Edge *e = G->edge[v];

            while (e) {
                int w = e->vertex;
                int d = G->dist[v] + e->weight;

                if (G->dist[w] == -1) {
                    G->dist[w] = d;
                    G->path[w] = v;

                    queue_push(&queue, w, d);
                }

                if (G->dist[w] > d) {
                    G->dist[w] = d;
                    G->path[w] = v;

                    queue_remove(&queue, w);
                    queue_push(&queue, w, d);
                }

                e = e->next;
            }
        }
    }

    int main()
    {
        int t;

        scanf("%d", &t);

        while (t--) {
            Graph *G;
            int v, e, s;

            scanf("%d %d", &v, &e);

            G = graph_new(v);

            for (int i = 0; i < e; i++) {
                int u, v, w;

                scanf("%d %d %d", &u, &v, &w);
                graph_edge(G, u - 1, v - 1, w);
            }

            scanf("%d", &s);
            dijkstra(G, s - 1);

            for (int i = 0; i < G->v; i++) {
                if (i != s - 1) {
                    printf("%d ", G->dist[i]);
                }
            }

            puts("");
            graph_delete(G);
        }

        return 0;
    }

【问题讨论】:

  • while (*head &amp;&amp; (*head)-&gt;priority &lt; p) { head = &amp;(*head)-&gt;next; } 应该遍历列表,而不是更改 head
  • 什么是地址`&(*head)->next`计算机如何生成地址地址而不存储(*head)->next 任何应该有一些内存块的地方我们可以存储(*head)->next 的地址,现在该内存块的地址将分配给head,如果发生这种情况,那么每当循环运行时,计算机会将所有中间体的地址存储在同一块或不同的内存块中跨度>
  • G = malloc(sizeof(*G)) 中很好地使用sizeof(*G) 而不是malloc(sizeof(Graph))

标签: c pointers memory-management


【解决方案1】:

queue_push() 未能正确插入新节点。

仅更新一个节点的.next。通常 2 个节点需要更新其 .next 成员。一个在原始列表中(在新节点的位置之前)和一个新的。


我发现在列表之前创建一个临时节点 superhead 可以简化代码。

void queue_push(Queue **head, int d, int p) {
  Queue *q = queue_new(d, p);

  Queue superhead; // Only superhead.next member important.
  superhead.next = *head;  
  Queue *previous = &superhead;

  while (previous->next && previous->next->priority < p) {
    previous = previous->next;
  }

  q->next = previous->next;
  previous->next = q;
  *head = superhead.next;
}

【讨论】:

    猜你喜欢
    • 2021-02-19
    • 2023-03-20
    • 2014-12-13
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多