关于图的数据结构和算法实现,可做参考。


数据结构定义和相关函数

数据结构

/* 优先队列节点 */
typedef struct
{
    int first;
    int second;
} node_t;

typedef bool (*cmp)(const void *, const void *);

/* 优先队列,用于实现最短路径算法 */
typedef struct
{
    node_t *arr;
    int capacity;
    int queueSize;
    cmp compare;
} priority_queue_t;

/* 边 */
typedef struct edge_s
{
    int to;
    int cost;
    struct edge_s *next;
} edge_t;

/* 图 */
typedef struct
{
    edge_t **graph;
    int nodeSize;
} graph_t;

优先队列相关函数

/* 创建优先队列 */
priority_queue_t *create_priority_queue(int size, cmp compare)
{
    priority_queue_t *obj = (priority_queue_t *)malloc(sizeof(priority_queue_t));
    obj->arr = (node_t *)malloc(sizeof(node_t) * size);
    obj->queueSize = 0;
    obj->capacity = size;
    obj->compare = compare;
    return obj;
}

/* 释放优先队列 */
void free_priority_queue(priority_queue_t *obj)
{
    free(obj->arr);
    free(obj);
}

/* 创建节点 */
node_t *create_node(long long x, int y)
{
    node_t *obj = (node_t *)malloc(sizeof(node_t));
    obj->first = x;
    obj->second = y;
    return obj;
}

/* 入队 */
void push(priority_queue_t *obj, node_t *node)
{
    memcpy_s(&obj->arr[obj->queueSize], sizeof(node_t), node, sizeof(node_t));
    for (int i = obj->queueSize; i > 0 && obj->compare(&obj->arr[(i - 1) / 2], &obj->arr[i]); i = (i - 1) / 2) {
        swap(obj->arr, i, (i - 1) / 2);
    }
    obj->queueSize++;
}

/* 出队 */
node_t* pop(priority_queue_t *obj)
{
    swap(obj->arr, 0, obj->queueSize - 1);
    down(obj->arr, obj->queueSize - 1, 0, obj->compare);
    node_t *ret =  &obj->arr[obj->queueSize - 1];
    obj->queueSize--;
    return ret;
}

/* 队列是否为空 */
bool is_empty(priority_queue_t *obj)
{
    return obj->queueSize == 0;
}

/* 队头节点 */
node_t* top(priority_queue_t *obj)
{
    if (obj->queueSize == 0) {
        return NULL;
    } else {
        return &obj->arr[0];
    }
}

/* 交换两个节点 */
static void swap(node_t *arr, int i, int j)
{
    node_t tmp;
    memcpy_s(&tmp, sizeof(node_t), &arr[i], sizeof(node_t));
    memcpy_s(&arr[i], sizeof(node_t), &arr[j], sizeof(node_t));
    memcpy_s(&arr[j], sizeof(node_t), &tmp, sizeof(node_t));
}

/* 堆的交换 */
static void down(node_t *arr, int size, int i, cmp compare)
{
    for (int k = 2 * i + 1; k < size; k = 2 * k + 1) {
        // 父节点 (k - 1) / 2,左子节点 k,右子节点 k + 1
        if (k + 1 < size && compare(&arr[k], &arr[k + 1])) {
            k++;
        }
        if (compare(&arr[k], &arr[(k - 1) / 2])) {
            break;
        }
        swap(arr, k, (k - 1) / 2);
    }
}

/* heapify 函数用于将传入的 priority_queue_t 优先队列对象的内部数组调整为堆结构。它通过从最后一个非叶子节点开始,依次向下调整每个节点,以确保整个队列满足堆的性质。 */
void heapify(priority_queue_t *obj)
{
    for (int i = obj->queueSize / 2 - 1; i >= 0; i--) {
        down(obj->arr, obj->queueSize, i, obj->compare);
    }
}

/* 两个节点的比较函数 */
bool greater(const void *a, const void *b)
{
   return ((node_t *)a)->first > ((node_t *)b)->first;
}

边相关函数

/* 创建边 */
edge_t *create_edge(int to, int cost)
{
    edge_t *obj = (edge_t *)malloc(sizeof(edge_t));
    obj->to = to;
    obj->cost = cost;
    obj->next = NULL;
    return obj;
}

/* 释放边列表 */
void free_edge_list(edge_t *list)
{
    while (list) {
        edge_t *p = list;
        list = list->next;
        free(p);
    }
}

图相关函数

/* 创建图 */
graph_t* graph_create(int n, int** edges, int edgesSize, int* edgesColSize)
{
    graph_t *obj = (graph_t *)malloc(sizeof(graph_t));
    obj->nodeSize = n;
    obj->graph = (edge_t **)malloc(sizeof(edge_t *) * n);
    for (int i = 0; i < n; i++) {
        obj->graph[i] = NULL;
    }
    for (int i = 0; i < edgesSize; i++) {
        int x = edges[i][0];
        int y = edges[i][1];
        int cost = edges[i][2];
        edge_t *e = (edge_t *)malloc(sizeof(edge_t));
        e->to = y;
        e->cost = cost;
        e->next = obj->graph[x];
        obj->graph[x] = e;
    }

    return obj;
}

/* 释放图 */
void graph_free(graph_t* obj)
{
    for (int i = 0; i < obj->nodeSize; i++) {
        free_edge_list(obj->graph[i]);
    }
    free(obj->graph);
    free(obj);
}

/* 给图添加边 */
void graph_add_edge(graph_t* obj, int* edge, int edgeSize)
{
    int x = edge[0];
    int y = edge[1];
    int cost = edge[2];
    edge_t *e = create_edge(y, cost);
    e->next = obj->graph[x];
    obj->graph[x] = e;
}

相关算法

dijkstra最短路径算法

/**
 * 最短路径算法dijkstra
 * 详细解释:
 * 该算法用于计算图中两个节点之间的最短路径。
 * 它使用优先队列来高效地选择当前距离最短的节点进行扩展。
 * 算法初始化时,将所有节点的距离设置为无穷大,起始节点的距离设置为0。
 * 然后将起始节点加入优先队列。
 * 在每次迭代中,从优先队列中取出距离最短的节点,检查其所有邻居节点。
 * 如果通过当前节点到达邻居节点的距离小于已知的距离,则更新邻居节点的距离并将其加入优先队列。
 * 该过程持续直到找到目标节点或优先队列为空(表示无法到达目标节点)。
 * 最终返回起始节点到目标节点的最短距离,如果无法到达则返回-1。
 */
int graph_shortest_path(graph_t* obj, int node1, int node2)
{
    int n = obj->nodeSize;
    int dist[n];
    priority_queue_t *pq = create_priority_queue(n * n, greater);

    for (int i = 0; i < n; i++) {
        dist[i] = INT_MAX;
    }

    dist[node1] = 0;
    node_t val;
    val.first = 0;
    val.second = node1;
    push(pq, &val);
    while (!is_empty(pq)) {
        node_t *p = pop(pq);
        int cost = p->first;
        int cur = p->second;

        if (cur == node2) {
            free_priority_queue(pq);
            return cost;
        }

        for (edge_t *pEntry = obj->graph[cur]; pEntry; pEntry = pEntry->next) {
            int next = pEntry->to;
            int ncost = pEntry->cost;
            if (dist[next] > cost + ncost) {
                dist[next] = cost + ncost;
                val.first = cost + ncost;
                val.second = next;
                push(pq, &val);
            }
        }
    }
    free_priority_queue(pq);
    return -1;
}