我的疑问仅是关于指针,如果我们使用Queue
,则头部是指向*head
的双指针,而不是访问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;
}
答案 0 :(得分:0)
queue_push()
无法正确插入新节点。
仅一个节点的.next
被更新。通常,两个节点需要更新其.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;
}