栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

数据结构】图-图的存储

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构】图-图的存储

文章目录

一、概述二、邻接表的表示方法

1. 无向图邻接表

1). 解释2). 特点 2. 有向图的邻接表

1). 解释2). 特点 3. 有向图的逆邻接表

1). 解释2). 特点 三、有向图的创建

1. 数据结构的定义2. 邻接表存储方法3. 代码 四、完整代码五、总结

1. 优点2. 缺点3. 综合

GitHub同步更新(已分类):Data_Structure_And_Algorithm-Review(能给个star最好了!!!)

以下是本篇文章正文内容,下面案例可供参考。


一、概述

邻接表(Adjacency LIst)是图的一种链式存储方法。邻接表包含两部分:顶点和临界点。顶点包括顶点信息和指向第一个邻接点的指针。邻接点包括邻接点的存储下标和指向下一个邻接点的指针。顶点 vi 的所有邻接点构成一个单链表。 二、邻接表的表示方法 1. 无向图邻接表

以下图无向图为例,创建邻接表如图。

1). 解释

a 的邻接点是 b、d,其邻接点的存储下表为 1、3,按照头插法(逆序)将其放入 a 后面的单链表中;b 的邻接点是 a、c、d,其邻界点的存储下标为 0、2、3,将其放入 b 后边的单链表中;…… 2). 特点

    无向图有 n 个顶点和 e 条边,则顶点表有 n 个节点,邻接点表有 2e 个节点;顶点的度为该顶点后面单链表中的节点数。
2. 有向图的邻接表

以下图有向图为例,创建邻接表如图。

1). 解释

只看出度:

a 的邻接点(只看出度)是 b、d,其邻接点的储存下标为 1、3,按头插法(逆序)将其放入 a 后面的单链表中;b 的邻接点是 c,其邻接点的存储下标为 2,将其放入 b 后面的单链表中;c 没有邻接点,其后面单链表为空;…… 2). 特点

    有向图有 n 个顶点,e 条边,则顶点表有 n 个节点,邻接点表有 e 个节点;顶点的出度为该顶点后面单链表中的节点数。
3. 有向图的逆邻接表

以下图有向图为例,创建逆邻接表如图。

1). 解释

逆邻接表是按照入度建表。

a 没有逆邻接点(只看入度),其后面得单邻接表为空;b 得逆邻接点是 a、d,其存储下标为 0、3,按头插法将其放入 b 后面的单链表中;…… 2). 特点

    有向图有 n 个顶点,e 条边,则顶点表有 n 个节点,邻接点表有 e 个节点;顶点的入度为该顶点后面单链表中的节点数。
三、有向图的创建 1. 数据结构的定义

邻接表用到 2 个数据结构。

    顶点节点:包括顶点信息和指向第一个邻接点得指针,可用一维数组存储;邻接点节点:包括邻接点的存储下标和指向下一个邻接点得指针。顶点 vi 的所有邻接点构成一个单链表。(如果是网,则再加一个存放权的储存空间)


c++代码如下(示例):

struct AdjNode {//邻接点结构体
    int v;
    AdjNode *next;
};

struct VexNode {//节点结构体
    VexType data;
    AdjNode *first;//first 指向邻接点
};

struct AlGraph {//节点数组结构体
    VexNode Vex[MaxVnum];
    int vexnum, edgenum;
};

java代码如下(示例):

public static class AdjNode {
    int v;
    AdjNode next;
}

public static class VexNode {
    String data;
    AdjNode first;
}

public static class AlGraph {
    VexNode vex[] = new VexNode[MaxVnum];
    int vexnum, edgenum;
}
2. 邻接表存储方法

算法步骤:

    输入顶点数和边数;依次输入顶点信息,存储到顶点数组 Vex[ ] 的 data 域中,Vex[ ] 的 first 域置空;依次输入每条边依附的两个顶点,如果是网,还需要输入该边的权。查询两个顶点在 Vex[ ] 中的储存下标 i、j
      无向图:创建新邻接点 s1,令 s1 -> v = j; s1 -> next = NULL;然后将 s1 节点插入第 i 个顶点的第一个邻接表之前(头插法)。 再创建新邻接点 s2,令 s2 -> v = i; s2 -> next = NULL;然后将 s2 节点插入第 j 个顶点的第一个邻接表之前(头插法);有向图:创建新邻接点 s,令 s -> v = j; s -> next = NULL;然后将 s1 节点插入第 i 个顶点的第一个邻接表之前(头插法)。
3. 代码

c++代码如下(示例):

void CreateGraph(AlGraph &G) {
    cin >> G.vexnum >> G.edgenum;
    for (int i = 0; i < G.vexnum; i++) {
        cin >> G.Vex[i].data;
        G.Vex[i].first = NULL;//指向空
    }

    VexType u, v;
    while (G.edgenum--) {
        cin >> u >> v;
        int i = LocateVex(G, u);
        int j = LocateVex(G, v);
        if (i != -1 && j != -1) {
            InsertEdge(G, i, j);//头插法
        } else {//不存在该节点
            cout << "错误" << endl;
            G.edgenum++;
        }
    }
}

java代码如下(示例):

public static void createGraph(AlGraph g) {
    g.vexnum = sc.nextInt();
    g.edgenum = sc.nextInt();
    for (int i = 0; i < g.vexnum; i++) {
        g.vex[i] = new VexNode();
        g.vex[i].data = sc.next();
        g.vex[i].first = null;
    }
    String u, v;
  	while (g.edgenum-- > 0) {
        u = sc.next();
        v = sc.next();
        int i = locateVex(g, u);
        int j = locateVex(g, v);
        if (i != -1 && j != -1) {
            insertEdge(g, i, j);
        } else {
            System.out.println("错误");
            g.edgenum++;
       	}
    }
}
四、完整代码

c++代码如下(示例):

#include

using namespace std;
#define MaxVnum 100
typedef char VexType;

struct AdjNode {
    int v;
    AdjNode *next;
};

struct VexNode {
    VexType data;
    AdjNode *first;
};

struct AlGraph {
    VexNode Vex[MaxVnum];
    int vexnum, edgenum;
};

int LocateVex(AlGraph G, VexType x) {
    for (int i = 0; i < G.vexnum; i++) {
        if (G.Vex[i].data == x) {
            return i;
        }
    }
    return -1;
}

void InsertEdge(AlGraph &G, int i, int j) {
    AdjNode *s = new AdjNode;
    s->v = j;
    s->next = G.Vex[i].first;
    G.Vex[i].first = s;
}

void CreateGraph(AlGraph &G) {
    cin >> G.vexnum >> G.edgenum;
    for (int i = 0; i < G.vexnum; i++) {
        cin >> G.Vex[i].data;
        G.Vex[i].first = NULL;
    }

    VexType u, v;
    while (G.edgenum--) {
        cin >> u >> v;
        int i = LocateVex(G, u);
        int j = LocateVex(G, v);
        if (i != -1 && j != -1) {
            InsertEdge(G, i, j);
        } else {
            cout << "错误" << endl;
            G.edgenum++;
        }
    }
}

void Print(AlGraph G) {
    cout << "如下" << endl;
    for (int i = 0; i < G.vexnum; i++) {
        cout << G.Vex[i].data;
        AdjNode *t = G.Vex[i].first;
        while (t != NULL) {
            cout << "->[" << t->v << "]";
            t = t->next;
        }
        cout << endl;
    }
}

int main() {
    AlGraph G;
    CreateGraph(G);
    Print(G);
    return 0;
}

java代码如下(示例):

import java.util.Scanner;

public class A {
    private static final int MaxVnum = 100;
    private static Scanner sc = new Scanner(System.in);

    public static class AdjNode {
        int v;
        AdjNode next;
    }

    public static class VexNode {
        String data;
        AdjNode first;
    }

    public static class AlGraph {
        VexNode vex[] = new VexNode[MaxVnum];
        int vexnum, edgenum;
    }

    public static int locateVex(AlGraph g, String x) {
        for (int i = 0; i < g.vexnum; i++) {
            if (g.vex[i].data.equals(x)) {
                return i;
            }
        }
        return -1;
    }

    public static void insertEdge(AlGraph g, int i, int j) {
        AdjNode s = new AdjNode();
        s.v = j;
        s.next = g.vex[i].first;
        g.vex[i].first = s;
    }

    public static void createGraph(AlGraph g) {
        g.vexnum = sc.nextInt();
        g.edgenum = sc.nextInt();
        for (int i = 0; i < g.vexnum; i++) {
            g.vex[i] = new VexNode();
            g.vex[i].data = sc.next();
            g.vex[i].first = null;
        }
        String u, v;
        while (g.edgenum-- > 0) {
            u = sc.next();
            v = sc.next();
            int i = locateVex(g, u);
            int j = locateVex(g, v);
            if (i != -1 && j != -1) {
                insertEdge(g, i, j);
            } else {
                System.out.println("错误");
                g.edgenum++;
            }
        }
    }

    public static void print(AlGraph g) {
        for (int i = 0; i < g.vexnum; i++) {
            System.out.print(g.vex[i].data);
            AdjNode t = g.vex[i].first;
            while (t != null) {
                System.out.print("->[" + t.v + "]");
                t = t.next;
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        AlGraph g = new AlGraph();
        createGraph(g);
        print(g);
    }
}

五、总结 1. 优点

便于增删顶点;便于访问所有邻接点;访问所有顶点的邻接点,时间复杂度为 O(n+e);空间复杂度低。顶点占用 n 个空间,无向图的邻接点表占用 n+2e 个空间,有向图的邻接点表占用 n+e 个空间,总体空间复杂度为 O(n+e),而邻接矩阵的空间复杂度为 O ( n 2 ) O(n^2) O(n2);因此对于稀疏图可以采用邻接表存储,对于稠密图可以采用邻接矩阵存储。 2. 缺点

不便于判断两顶点之间是否有边。要判断两顶点是否有边,需要遍历该顶点后面的邻接点链表;不便于计算各顶点的度; 3. 综合

虽然邻接表访问单个邻接点的效率不高,但是访问一个顶点的所有邻接点,仅需访问该顶点后面的单链表即可,时间复杂度为该顶点的度 O(d(v~i~));而邻接矩阵访问一个顶点的所有邻接点,时间复杂度为 O(n);总体上邻接表比邻接矩阵效率更高;有向图邻接表求出度容易,而逆邻接表求出度容易,如果想快速求顶点的出度和入度,可以将邻接表和逆邻接表结合起来,采用十字链表存储。


下期预告:图的存储_边集数组

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/759196.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号