数据结构之图的创建

【数据结构】图的构建(邻接表法) 最近整理电脑,发现了以前写的数据结构的代码,由于时间久了,好多代码都找不到了,现在扒出来复习一下。 如果看不懂下面关于图的术语或者压根就不知道图。建议看一下严蔚敏版的《数据结构》中对图的介绍 图的构建方法有好几种,如邻接矩阵法,邻接表法,十字链表法,邻接多重表。今天介绍邻接表法。 邻接表(Adjacency List) 是图的一种链式存储结构,在邻接表中,对图中每个顶点建立一个单链表 阅读详情

1.图的定义

图(Graph):是由顶点的又穷非空集合和定点之间的边集组成,通常表示为G(V,E),其中G表示一个图,V是其顶点集合,E是其边集合。

有向图(Directed graphs): 任意两个点之间的边都是有向边。

入度(InDegree):以顶点为v为头的弧的数目称为入度。

出度(OutDegree):以顶点v为尾的弧的数目成为出度。


2.图的存储结构

常见的存储结构有五种:

  • 邻接矩阵
  • 邻接表
  • 十字链表
  • 邻接多重表
  • 边集数组

邻接矩阵:图的定义G(V,E),顶点可以用一维数组来存储type vex[n],边可以理解为线,当然就可以用二维数组
type arc[n][n]进行存储。对于无向表该矩阵一定是对称矩阵,如果顶点i,j之间存在边那么arc[i][j],arc[j][i]=1否则arc[i][j]=0
实例图

存在的边:V0—-V1,V1—-V2 ,V2—V3 ,V3—V0即:

arc[0][1]=arc[1][0]=1;
arc[1][2]=arc[2][1]=1;
arc[2][3]=arc[3][2]=1;
arc[3][0]=arc[0][3]=1;

其矩阵应该为:

这里写图片描述

某个顶点i所在行或者所在列元素之和即其度。
对于有向表,矩阵不再是对称的,可以定义列顶点作为起点,行作为终点。那么顶点i所在行的元素和即为出度,列元素和即为入度。
这里写图片描述
由图可知:
arc[0][3]=1;
arc[1][0]=1;
arc[1][2]=1;
arc[2][0]=1;
arc[2][1]=1;
其矩阵为:
这里写图片描述
这种存储结构优缺点都十分明显,优点在于结构简单,能分清楚看出顶点的出度和入度,简单判断两个顶点间是否存在边。
但是创建是遍历数组复杂都n^2,动态扩展困难,很多的存储空间的浪费。


邻接表
基于邻接矩阵,顶点依然用一维数据存放,但不仅仅存放顶点数据,还存放一个存储由以该定点为弧头邻接点的一维链表。
这里写图片描述
这种数据结构下,图就由一个链表数组构成。链表数据结构为:
这里写图片描述
在例子图中
这里写图片描述
依然可以轻松看出每一个顶点的出度或者入度(如果链表存放的是以顶点Vi为弧头的邻接点则是出度,为弧尾则是入度)。在有向表的情况下也是一样。只关注一个方向进行记录就好。
虽然解决了邻接矩阵难以动态扩展和空间浪费的问题,但是依然存在一个问题,不能同时反应顶点的出度和入度,链表和数组相比,链表始终需要进行遍历(当然有算法可以减少查找次数),导致效率上始终比不上数组毕,竟数组只是一串连续的存储空间,很轻松就可以获取到目标值。

边集数组
这个办法思路更简单,用一个一维数组(或者链表)来存放所有边的信息,其结构是:
begin end weight(权,如果有用到的话)
这里写图片描述
这种方法会使得出度入度及顶点信息都不是很好获得所以不常用。

十字链表和多重链接表
克服了邻接表不能同时显示入度和出度的问题,实现比前几个都复杂所以留到后面再写,不然这篇就太长了= =b。



3.图的建立

是时候敲敲代码了,这里的建立方法使用邻接表的方式,本来我想用Python来做图这种数据类型,但是数据结构本来的目的就是接近底层,所以这里还是使用C/C++来实现尽管要麻烦一些 = =。

class Graph
{
public:
    typedef struct item
    {
        int index;
        int power;
        item*next=NULL;
    }NodeList,*Node;
    int num;
    Graph();
    ~Graph();
private:
    NodeList vexs[20];//最多支持20个顶点
};
Graph::Graph()
{
    int temp=0;
    int counts = 0;
    cout << "输入顶点个数:" << endl;
    cin >> num;
    for (int i = 1; i < num + 1; i++)
    {
        Node ptr = &vexs[i-1];
        cout << "输入第"<<i<<"个顶点信息" << endl;
        counts = 0;
        while (1)
        {
            cout << "输入链接下标" << endl;
            cin >> temp;
            if (temp == -1)
            {
                ptr->next = NULL;
                cout << "第" << i << "个节点录入完成" << endl;
                break;
            }
            else
            {
                if (counts > 0)
                {
                    ptr->next = (Node)malloc(sizeof(NodeList));
                    ptr = ptr->next;
                }
                ptr->index = temp;
                cout << "输入该边的权" << endl;
                cin >> temp;
                ptr->power = temp;
                counts++;
            }
        }
    }
}

Graph::~Graph()
{

}

这个版本很早以前写的,但还是可以用。
这里又存在了一个数组,又可以进行抉择,追求速度可以就是用数组,想更高效的利用存储空间就可以利用链表。即顶点链表中每一个节点都包含着一个边链表,实现方法如下:
首先因为是两个链表,直接整逻辑会显得很复杂,所以这里将它拆分为两个类,各自实现添加操作。

/*******************边集链表*********************/
class Node//边信息
{
public:
    char date;
    int wight;//权 暂未使用
    Node*next;
};

class LinkList
{
public:
    Node * head;//头指针
    Node * tail;//尾部指针
    int lenth=0;//链表长度

    LinkList(char *s);//用一个char数组初始化链表
    Node* add_one(char s);//返回一个当前指针
    void display();
    bool del(int index);
};
LinkList::LinkList(char*s)
{
    if (s == NULL)
    {
        cout << "create a empty LinkList!" << endl;
        head = NULL;
        tail = NULL;
    }
    else
    {
        head = (Node*)malloc(sizeof(Node));
        Node *ptr = head;
        while (*s!='\0')
        {
            lenth++;
            ptr->date = *s++;
            ptr->next = (Node*)malloc(sizeof(Node));
            ptr = ptr->next;
        }
        ptr->date = '#';
        ptr->next = NULL;
        tail = ptr;
    }
}

Node* LinkList::add_one(char s)
{
    Node *ptr;
    Node*curr;
    if (lenth == 0)//链表未曾进行过添加
    {
        head = (Node*)malloc(sizeof(Node));
        ptr = head;
        ptr->date = s;
        ptr->next= (Node*)malloc(sizeof(Node));
        ptr = ptr->next;
        ptr->date = '#';
        ptr->next = NULL;
        tail = ptr;
        lenth++;
        return head;
    }
    else
    {
        ptr = tail;
        ptr->date = s;
        curr = ptr;
        ptr->next = (Node*)malloc(sizeof(Node));
        ptr = ptr->next;
        ptr->date = '#';
        ptr->next = NULL;
        tail = ptr;
        lenth++;
        return curr;
    }
}

bool LinkList::del(int index)
{
    if (index > lenth || index < 0)return false;
    Node*ptr=head;
    if (index == 0){
        head = head->next;
        free(ptr);
    }
    else {
        for (int i = 0; i < index - 1; i++)
        {
            ptr = ptr->next;
        }
        Node*temp = ptr->next;
        ptr->next = ptr->next->next;
        free(temp);
    }
    lenth--;
    return true;
}

void LinkList::display()
{
    Node*ptr = head;
    for (int i = 0; i < lenth; i++)
    {
        cout << "LinkList[" << i << "]:" << ptr->date<<"  ";
        ptr = ptr->next;
    }
    cout << endl;
}

这个链表就用于存放顶点集,其构造方法和display方法是用于测试该表链是否有问题,构造图主要使用的是add_one()方法
自动增加一个节点。

/****************顶点集链表******************/
class vex//顶点信息
{
public:
    LinkList *current;
    vex *next;
    char date;
};

class VexLinkList
{
public:
    vex*head;
    vex*tail;
    int lenth = 0;
    VexLinkList(char *s);
    vex* add_one(char s);
};

VexLinkList::VexLinkList(char *s)//顶点集
{
    if (s == NULL)
    {
        head = NULL;
        tail = NULL;
        cout << "create a empty VexLinkList!" << endl;
    }
    else
    {
        head = (vex*)malloc(sizeof(vex));
        vex*ptr = head;
        while (*s!='\0')
        {
            lenth++;
            ptr->date = *s++;
            ptr->next = (vex*)malloc(sizeof(vex));
            ptr = ptr->next;
        }
        ptr->date = '#';
        ptr->next = NULL;
        tail = ptr;
    }
}
vex* VexLinkList::add_one(char s)
{
    vex*curr;
    if (lenth == 0)
    {
        head = (vex*)malloc(sizeof(vex));
        head->date = s;
        head->next = (vex*)malloc(sizeof(vex));
        tail = head->next;
        tail->date = '#';
        tail->next = NULL;
        lenth++;
        return head;
    }
    else
    {
        tail->date = s;
        curr = tail;
        tail->next = (vex*)malloc(sizeof(vex));
        tail = tail->next;
        tail->date = '#';
        tail->next = NULL;
        lenth++;
        return curr;
    }
}

其实链表结构就那样,所以这两个链表其实差不多只是节点类型上有区别;add_one()方法依然自动添加一个节点。


图类型结构

class Graph
{
public:
    VexLinkList *t;//顶点集
    int sum;//顶点总数
    Graph();
};
Graph::Graph()
{
    char temp;
    t = (VexLinkList*)malloc(sizeof(VexLinkList));
    t->lenth = 0;
    while (1)
    {
        cout << "input the vex # means none" << endl;
        cin >> temp;
        fflush(stdin);
        if (temp == '#')break;
        vex*cur=t->add_one(temp);
        cout << "now input the date in the vex" << endl;
        cur->current = (LinkList*)malloc(sizeof(LinkList));
        cur->current->lenth = 0;
        while (1)
        {
            cin >> temp;
            if (temp == '#')break;
            cur->current->add_one(temp);
        }
    }
}

这里设定了一个默认的终止字符’#’碰到’#’字符就认为当前的顶点集链表或者边集链表输入完毕。
数据结构图:

这里写图片描述

最后

相对于树的建立,感觉上图的建立还算比较简单,只是相关的概念非常多,遍历(深度,广度)相较二叉树稍显复杂,这里立一个flag,深度遍历,广度遍历,十字链表和多重邻接表下周来写,本来以为写这些应该很快,结果发现。。。好慢啊= =。最后吐槽一下markdown编辑器,真是帮人学习HTML CSS。

数据结构--图的创建(邻接表) 数据结构–图的创建(邻接表) 邻接表结构: #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #define MAXVEX 20 typedef char VertexType; //边表结点 typedef struct EdgeNode{ int adjvex; struct EdgeNo... 阅读详情

相关推荐

数据结构之图(邻接矩阵创建)

邻接矩阵 邻接矩阵的存储方式是用两个数组表示图。一个一维数组存储图中顶点信息。一个二维数组(邻接矩阵)存储图中的边或弧的信息。 无向图的邻接矩阵 特点: 1、很容易判断任意两个顶点是否有边无边。 2、想要知道某个顶点的度,其实就是这个点点 Vi 在邻接矩阵中第 i 行(或第 i 列)的元素之和。 3、求顶点 V...

爱科比的博客 4161

【数据结构】图的创建和深度(DFS)广度(BFS)优先遍历

图的创建和遍历方法

m0_72532428的博客 2571

数据结构 - 图 - 邻接矩阵和邻接表的创建 - C语言

//邻接矩阵 #include<stdio.h> #include<stdlib.h> #define Status int #define OVERFLOW -2 #define OK 1 #define ERROR -1 //邻阶矩阵 #define MaxInt 32767 #define MVNum 100 typedef char VerTexType;//顶点...

weixin_44062451的博客 1504

数据结构——图的创建以及遍历

​ 图是一种数据结构,其中节点可以具有零个或多个相邻元素。两个节点之间的连接称为边。节点也可以称为顶点为什么要有图图的常用概念图的表示方式​ 图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)邻接矩阵​ 邻接矩阵是表示图形中顶点之间相邻关系的矩阵邻接表代码演示 12.3 图的遍历 图遍历的介绍​ 所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种访问策略:图的深度优先遍历(Depth First Search)深度优先遍历算法步骤核心代码 12.3

crisp077的博客 5745

【数据结构】-图-邻接表创建图

边表节点:一个int类型数据来存储顶点的下标,一个边表节点类型的指针指向下一个边表节点 顶点表节点:一个char类型存储顶点的值,一个边表类型的指针指向第一个边表节点 图:一个顶点表数组(线性存储),两个int类型的数据标识顶点数量和表的数量 注意:若是有向图,一天边直插入一次即可,若是无向图,一条边要插入两次 /*边表节点*/ typedef char vertexType ; typedef struct ArcNode{ int adjvex; struct ArcNode *ne...

vector的博客 1895

Windows正在配置Xftp6在下面的框输入包含安装程序包“Xftp 6.msi“的文件夹的路径

Windows正在配置Xftp6在下面的框输入包含安装程序包“Xftp 6.msi"的文件夹的路径

m0_56588258的博客 2470

数据结构-----图(graph)的储存和创建

邻接矩阵是图的矩阵表示,借助它可以方便地存储图的结构,用线性代数的方法研究图的问题。 如果一个图有 n 个顶点,其邻接矩阵 W 为 ntimes n 的矩阵,矩阵元素 w_ {ij} 表示边 (i,j) 的权重。 如果两个顶点之间没有边连接,则在邻接矩阵中对应的元素为0。

m0_73633088的博客 3826

粒子群算法实战:用Matlab解决旅行商问题(TSP)的完整代码解析

本文提供了使用粒子群算法解决旅行商问题的完整Matlab实战指南。通过将连续空间的粒子群算法进行离散化改造,采用基于交换序的策略来更新粒子位置与速度,并给出了从问题定义、数据结构设计、核心函数实现到主迭代循环的详细代码解析。文章还探讨了参数调优、性能优化及处理复杂TSP变体的进阶思路,为物流规划、路径优化等领域的工程应用提供了可直接复用的解决方案。

m2n3o4p5的博客 350

数据结构学习记录——如何建立图(邻接矩阵、邻接表-图节点的结构、创建并初始化、插入变、完整图的建立)

二维数组表示图的邻接矩阵。它的大小是MaxVertexNum × MaxVertexNum,用于存储顶点之间边的权重或者存在的情况。(无权重且存在边用1表示,无权重且不存在边则用0表示;有权重且存在边用其权重表示,有权重且不存在边则用一个极大值表示。其中,DataType Data[MaxVertexNum],可以用来存储与每个顶点相关的其他数据。例如:如果图表示一个社交网络,则可以存储每个顶点的个人资料信息(姓名、性别、年龄等),故而它的类型可以是整型,也可以是结构体类型。

li13437542099的博客 2115

同济大学824复试全攻略:从笔试到面试的实战解析

本文详细解析同济大学824复试全流程,包括专业课笔试、外语听力与口语、专业外语笔试和专业综合面试的备考策略。重点分享数字信号处理、计算机网络等专业课的高效学习方法,以及专业外语速成和口语面试技巧,助力考生全面提升复试表现。

qq_27496129的博客 1054

自动驾驶技术路线之争:纯视觉与多模态融合的成本与性能博弈

本文深入剖析了自动驾驶领域两大主流技术路线——纯视觉与多模态融合的本质差异。文章从成本结构、性能博弈与商业逻辑等多维度展开,揭示了纯视觉方案在硬件成本与数据算力投入上的权衡,以及多模态融合方案在安全冗余与感知稳定性方面的优势。这场技术路线之争,实则是车企在性能、成本与商业化落地之间寻求平衡的综合博弈。

weixin_29038303的博客 390

数据结构-图的创建-c++

数据结构-图的创建-c++ 在网上找了很多没有找到一个用类c语言写图的,所以这里自己来总结一下。 邻接矩阵创建 /* #include <bits/stdc++.h> #define maxint 10000 #define maxnum 100 using namespace std;*/ typedef struct { int vexs[maxnum];//顶点表 int edges[maxnum][maxnum];//邻接矩阵 int vexnum,arcn

lu__ren的博客 3481

升级最新IDEA版本(2022.1.1)

升级最新IDEA版本(2022.1.1)

软件老王 3万+

数据结构实验十一 图的创建与存储

在代码中,首先定义了图的结构体MatrixGraph和ListGraph,分别表示邻接矩阵和邻接表。然后通过Initiate函数和AdjInitiate函数对图进行初始化,包括顶点和边的初始化。接着通过InsertVertex和InsertEdge函数,分别实现了向图中插入顶点和边的操作。最后,通过CreatGraph和CreatGraph2函数,将顶点和边的信息传入,创建了两个不同存储结构的图。提示:首先构建图的逻辑模型,得出该图的顶点集和边集,调用相应的函数生成图的邻接矩阵,并打印出邻接矩阵。

2301_76979886的博客 591

华为od 面试八股文_操作系统_01_含答案

华为od 面试八股文_操作系统_01_含答案

MISAYAONE的博客 3274

科研级实战】YOLOv11 pose部署至RK3588全流程:让姿态估计模型在边缘端毫秒级运行,我来帮你突破人体行为分析落地壁垒

在智慧安防人体行为分析场景中,基于YOLOv11 pose的模型在云端推理单帧耗时150ms,硬件成本超15000元;经本方案部署到RK3588后,单帧推理耗时降至30ms,硬件成本仅4000元,且关键点检测准确率高达93%以上。在运动姿态评估场景,同款技术路径使模型边缘端推理速度提升6倍,姿态分类精度达95%。这意味着,你也能让自己的姿态估计模型在边缘设备上实现的工业化落地,接下来让我们开启从模型训练到端侧部署的实战征程。

m0_71589036的博客 223

数据结构实验-图的创建和遍历

数据结构-图的创建和遍历

Kethy__的博客 244

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

GDPU 数据结构 天码行空11 图的创建和存储

图的创建和存储 邻接表 邻接矩阵

人言束负兑生|完美是完蛋的开始 852

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

数据结构与算法——图的两道习题(创建,求度,遍历)

数据结构-图的两道上机题 不好或者多余的地方大佬请多指教 有向图的创建,求度和遍历: 题目和要求: 从键盘接收有向图的顶点集,弧集,创建有向图,并完成下列任务: (1)计算结点的出度、入度以及度; (2) 从第一个顶点出发,求一个深度优先遍历序列; (3) 从第一个顶点顶点出发,求一个广度优先遍历序列。 注意:以用户输入各个顶点的顺序为顶点的序号。 在深度和广度优先遍历中,优先选择序号小的顶点。 ...

Hhhhh 682

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

数据结构之图的创建(邻接表法创建)

邻接表是图的一种链式存储结构。在邻接表中,对图的每个顶点建立一个单链表,第I个单链表的结点依附于顶点V的边。 邻接表的存储结构 个人感觉邻接表的难点在于创建三种结构体,并将他们三个联系起来,过程中多了很多名词,需要大家细心去领会,还有就是在创建边表的时候需要进行头插法,以保证最大的在最前面 。 邻接表中三个结构体的创建 typedef struct EdgeNode{ int...

爱科比的博客 7271

数据结构笔记_40 图的创建

如题,上例子: 思路分析: 存储顶点String 使用Array List 保存矩阵 使用 int [][] edges 代码: package com.huey.graph; import java.util.ArrayList; import java.util.Arrays; public class Graph { private ArrayList<String> vertexList;// 存储顶点的集合 private int[][] edges;// 存储图对应的

行者常至,为者常成 230

数据结构-图的创建

package com.graph; import java.util.ArrayList; public class Graph { private ArrayList<String> vertexList;//放顶点的集合 private int[][] edges;//存放边 private int numOfEdges;//表示边的数目 public static void main(String[] args) { int n .

qq_45100361的博客 608

【数据结构】图的创建与遍历

【数据结构】图的存储方式和遍历方法介绍,以及C语言代码编写例程。 存储方式包括邻接矩阵、邻接表、十字链表、邻接多重表、边集数组;遍历方法包括深度优先遍历和广度优先遍历算法。

qq_41563510的博客 7438

数据结构--图的创建之邻接表

思绪不断阻挡着回忆播放,盲目的追寻仍然空空荡荡,灰蒙蒙的夜晚睡意又不知躲到哪去,一转身孤单已躺在身旁。 算法中也写过一篇关于建图的方法的博客,点这里。 邻接矩阵比较好理解,这里就不记录了,主要是邻接表,比较难理解, 邻接表存储类型定义: typedef struct ANode { int adjvex; //该边的终点编号 struct ANod...

0k-ok 1477
上一篇: Python异常总结
下一篇: Python3.x调用阿里云短信api
shu_8708
博客等级 码龄10年 45粉丝 40原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值