数据结构(6_2_3)——十字链表法和多重领接表

十字链表存储有向图

橙色入度,绿色出度

代码示例:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义十字链表节点结构体
typedef struct OLNode {
    int row;         // 行号
    int col;         // 列号
    int value;       // 节点值
    struct OLNode* right; // 指向右边节点的指针
    struct OLNode* down;  // 指向下方节点的指针
} OLNode, * OLink;

// 定义十字链表的头节点结构体
typedef struct {
    OLink* row_head; // 行表头指针数组
    OLink* col_head; // 列表头指针数组
    int m, n, len;   // 矩阵的行数、列数和非零元素的个数
} CrossList;
// 创建十字链表
CrossList CreateCrossList(int m, int n) {
    CrossList M;
    M.m = m;
    M.n = n;
    M.len = 0;

    // 初始化行和列的头指针数组
    M.row_head = (OLink*)malloc((m + 1) * sizeof(OLink));
    M.col_head = (OLink*)malloc((n + 1) * sizeof(OLink));
    if (!M.row_head || !M.col_head) {
        exit(1); // 内存分配失败
    }

    for (int i = 1; i <= m; i++) {
        M.row_head[i] = NULL;
    }
    for (int j = 1; j <= n; j++) {
        M.col_head[j] = NULL;
    }

    return M;
}
// 向十字链表插入元素
void Insert(CrossList* M, int i, int j, int value) {
    if (i > M->m || j > M->n || value == 0) {
        return; // 插入位置不合法或值为0
    }

    // 创建新节点
    OLNode* newNode = (OLNode*)malloc(sizeof(OLNode));
    newNode->row = i;
    newNode->col = j;
    newNode->value = value;
    newNode->right = NULL;
    newNode->down = NULL;

    // 插入行
    if (M->row_head[i] == NULL) {
        M->row_head[i] = newNode;
    }
    else {
        OLNode* current = M->row_head[i];
        while (current->right && current->right->col < j) {
            current = current->right;
        }
        newNode->right = current->right;
        current->right = newNode;
    }

    // 插入列
    if (M->col_head[j] == NULL) {
        M->col_head[j] = newNode;
    }
    else {
        OLNode* current = M->col_head[j];
        while (current->down && current->down->row < i) {
            current = current->down;
        }
        newNode->down = current->down;
        current->down = newNode;
    }

    M->len++; // 更新非零元素个数
}
// 从十字链表删除元素
void Delete(CrossList* M, int i, int j) {
    if (i > M->m || j > M->n) {
        return; // 位置不合法
    }

    // 查找要删除的节点
    OLNode* p = M->row_head[i];
    while (p && p->col < j) {
        p = p->right;
    }

    if (p && p->col == j) {
        // 删除行中的节点
        if (p == M->row_head[i]) {
            M->row_head[i] = p->right;
        }
        else {
            OLNode* q = M->row_head[i];
            while (q->right != p) {
                q = q->right;
            }
            q->right = p->right;
        }

        // 删除列中的节点
        if (p == M->col_head[j]) {
            M->col_head[j] = p->down;
        }
        else {
            OLNode* q = M->col_head[j];
            while (q->down != p) {
                q = q->down;
            }
            q->down = p->down;
        }

        free(p); // 释放节点内存
        M->len--; // 更新非零元素个数
    }
}
// 在十字链表中查找元素
OLNode* Find(CrossList M, int i, int j) {
    if (i > M.m || j > M.n) {
        return NULL; // 位置不合法
    }

    OLNode* p = M.row_head[i];
    while (p && p->col < j) {
        p = p->right;
    }

    if (p && p->col == j) {
        return p; // 找到元素,返回节点指针
    }
    else {
        return NULL; // 未找到元素
    }
}
// 打印十字链表
void PrintCrossList(CrossList M) {
    printf("十字链表如下:\n");
    for (int i = 1; i <= M.m; i++) {
        OLNode* p = M.row_head[i];
        while (p) {
            printf("(%d, %d, %d) ", p->row, p->col, p->value);
            p = p->right;
        }
        printf("\n");
    }
}
// 释放十字链表
void FreeCrossList(CrossList* M) {
    for (int i = 1; i <= M->m; i++) {
        OLNode* p = M->row_head[i];
        while (p) {
            OLNode* q = p;
            p = p->right;
            free(q);
        }
    }
    free(M->row_head);
    free(M->col_head);
}
int main() {
    int m = 3, n = 4; // 定义一个3行4列的稀疏矩阵
    CrossList M = CreateCrossList(m, n); // 创建十字链表

    // 插入元素
    Insert(&M, 1, 2, 12);
    Insert(&M, 1, 4, 9);
    Insert(&M, 3, 1, -3);
    Insert(&M, 3, 3, 14);

    // 打印十字链表
    PrintCrossList(M);

    // 删除元素
    Delete(&M, 1, 2);

    // 再次打印十字链表
    printf("删除元素后的十字链表:\n");
    PrintCrossList(M);

    // 释放十字链表
    FreeCrossList(&M);

    return 0;
}

十字链表法性能分析

领接矩阵、邻接表存储无向图的缺点

邻接多重表存储无向图

优点:

每一条边只对应一个边结点,没有冗余数据,删除结点或者删除边的时候会方便很多

代码示例:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义邻接多重表的边节点结构体
typedef struct EdgeNode {
    int ivex;            // 边的起点
    int jvex;            // 边的终点
    struct EdgeNode* ilink; // 指向起点相同的下一条边
    struct EdgeNode* jlink; // 指向终点相同的下一条边
    int mark;            // 标记边是否被访问过
} EdgeNode;

// 定义邻接多重表的顶点节点结构体
typedef struct VertexNode {
    int data;            // 顶点数据
    EdgeNode* firstedge; // 指向第一条依附于该顶点的边
} VertexNode;

// 定义邻接多重表结构体
typedef struct {
    VertexNode* vertices; // 顶点表
    int vexnum, edgenum;  // 顶点数和边数
}AMLGraph;
// 创建邻接多重表
AMLGraph CreateAMLGraph(int vexnum, int edgenum) {
    AMLGraph graph;
    graph.vexnum = vexnum;
    graph.edgenum = edgenum;

    // 初始化顶点表
    graph.vertices = (VertexNode*)malloc(vexnum * sizeof(VertexNode));
    if (!graph.vertices) {
        exit(1); // 内存分配失败
    }

    for (int i = 0; i < vexnum; i++) {
        graph.vertices[i].data = i;
        graph.vertices[i].firstedge = NULL;
    }

    return graph;
}
// 插入边
void InsertEdge(AMLGraph* graph, int ivex, int jvex) {
    // 创建边节点
    EdgeNode* newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
    newEdge->ivex = ivex;
    newEdge->jvex = jvex;
    newEdge->ilink = graph->vertices[ivex].firstedge;
    newEdge->jlink = graph->vertices[jvex].firstedge;
    newEdge->mark = 0;

    // 插入到顶点ivex的边表
    graph->vertices[ivex].firstedge = newEdge;

    // 插入到顶点jvex的边表
    graph->vertices[jvex].firstedge = newEdge;
}
// 删除边
void DeleteEdge(AMLGraph* graph, int ivex, int jvex) {
    EdgeNode* p = graph->vertices[ivex].firstedge;
    EdgeNode* pre = NULL;

    while (p && (p->ivex != ivex || p->jvex != jvex)) {
        pre = p;
        if (p->ivex == ivex) {
            p = p->ilink;
        }
        else {
            p = p->jlink;
        }
    }

    if (p) {
        if (pre) {
            if (p->ivex == ivex) {
                pre->ilink = p->ilink;
            }
            else {
                pre->jlink = p->jlink;
            }
        }
        else {
            if (p->ivex == ivex) {
                graph->vertices[ivex].firstedge = p->ilink;
            }
            else {
                graph->vertices[jvex].firstedge = p->jlink;
            }
        }
        free(p);
    }
}
// 查找顶点
VertexNode* FindVertex(AMLGraph graph, int data) {
    for (int i = 0; i < graph.vexnum; i++) {
        if (graph.vertices[i].data == data) {
            return &graph.vertices[i];
        }
    }
    return NULL;
}
// 打印邻接多重表
void PrintAMLGraph(AMLGraph graph) {
    printf("邻接多重表如下:\n");
    for (int i = 0; i < graph.vexnum; i++) {
        EdgeNode* p = graph.vertices[i].firstedge;
        while (p) {
            int ivex = p->ivex;
            printf("(%d, %d) ", ivex, jvex);
            // 根据当前顶点,决定移动到ilink还是jlink
            if (ivex == i) {
                p = p->ilink;
            }
            else {
                p = p->jlink;
            }
        }
        printf("\n");
    }
}
// 释放邻接多重表
void FreeAMLGraph(AMLGraph* graph) {
    for (int i = 0; i < graph->vexnum; i++) {
        EdgeNode* p = graph->vertices[i].firstedge;
        while (p) {
            EdgeNode* q = p;
            p = p->ilink;
            free(q);
        }
    }
    free(graph->vertices);
}
int main() {
    int vexnum = 4; // 定义顶点数为4
    int edgenum = 5; // 定义边数为5
    AMLGraph graph = CreateAMLGraph(vexnum, edgenum); // 创建邻接多重表

    // 插入边
    InsertEdge(&graph, 0, 1);
    InsertEdge(&graph, 0, 2);
    InsertEdge(&graph, 1, 2);
    InsertEdge(&graph, 1, 3);
    InsertEdge(&graph, 2, 3);

    // 打印邻接多重表
    PrintAMLGraph(graph);

    // 删除边
    DeleteEdge(&graph, 1, 2);

    // 再次打印邻接多重表
    printf("删除边后的邻接多重表:\n");
    PrintAMLGraph(graph);

    // 释放邻接多重表
    FreeAMLGraph(&graph);

    return 0;
}

总结:

相关推荐
JSU_曾是此间年少33 分钟前
数据结构——线性表与链表
数据结构·c++·算法
sjsjs1140 分钟前
【数据结构-合法括号字符串】【hard】【拼多多面试题】力扣32. 最长有效括号
数据结构·leetcode
blammmp2 小时前
Java:数据结构-枚举
java·开发语言·数据结构
昂子的博客2 小时前
基础数据结构——队列(链表实现)
数据结构
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
~yY…s<#>4 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
XuanRanDev5 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding5 小时前
力扣1 两数之和
数据结构·算法·leetcode
南宫生7 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
weixin_432702268 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论