数据结构与算法基础(王卓)(25):用邻接表表示图

目录

首先,我们把整个邻接表的结构所有的框架梳理出来:​编辑

顶点结点:

 弧/边的结点:

图的结构定义:

前置条件:

创建无向网:

LocateVex(G, v)函数:

函数体:

我写的第一个版本:

问题:

另外:

感悟:主要还是得靠自己研究思路以后自己写一遍代码,Tmd每天一遍遍吭哧吭哧看这标准答案然后搞得把他转化成中文最后还是get不到他什么意思,搞得...#%$&太tm费劲了

最终结果(成果):

完整环境加函数算法:

十字链表:(用于有向图)

 邻接多重表:(用于无向图)


首先,我们把整个邻接表的结构所有的框架梳理出来:


顶点结点:

typedef struct VertexNode
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum];
//例如:VNode v[MVNum] 相当于 AdjList vv

我觉得也可以改成这样写(我写的):(存疑)

//顶点的结点结构
struct VNode
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
};
typedef VNode AdjList[MVNum];
//例如:VNode v[MVNum] 相当于 AdjList v

主要的问题/歧义出在 AdjList 之上,虽然不知道我上面的写法对不对,但是可以肯定的是,对于 AdjList,我们可以这么理解:

为了方便理解 AdjList ,我们看:

VNode v[MVNum] 相当于 AdjList v     

就像看:我们定义一个
int a [ 5 ] 等价于一个什么 Alist a;

实际上:
AdjList 就表示:【数组类型为VNode类型的一维数组】的一个类型

但是如何在代码里实现它这样的一个效果是一个难题,Anyway,反正就是这么一回事

TMD而且我后面看了一下,也可以不去用这个 AdjList 的程序,只要把后面的图的程序改成:

//图的结构定义
struct ALG
{
    //AdjList vertices;  
    VNode vex[MVNum];//顶点表
    int vexnum, arcnum;  //顶点数和边数
}; //Adjacency List Graph

如果这样的话,我们定义直接可以写成:

struct VertexNode
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
};

就行,这玩意并不重要,我是真nm无语...


 弧/边的结点:

//弧/边的结点结构
typedef int OtherInfo;
struct ArcNode
{
    int adjvex;//Adjacency
    //该边所指向的(相邻)顶点的位置
    struct ArcNode* nextarc;  //指向下一条边的指针
    OtherInfo info;  //和边相关的信息
};

图的结构定义:

//图的结构定义
struct ALG
{
    //AdjList vertices;  
    VertexNode vex[MVNum];//顶点表
    int vexnum, arcnum;  //顶点数和边数
}; //Adjacency List Graph

汇总:

前置条件:

#include<iostream>
using namespace std;

typedef int Status;

#define MVNum 100  //最大顶点数
//MAX Vertex Number
typedef char VertexType;  //设顶点类型:字符型

//弧/边的结点结构
typedef int OtherInfo;
struct ArcNode
{
    int adjvex;//Adjacency
    //该边所指向的(相邻)顶点的位置
    struct ArcNode* nextarc;  //指向下一条边的指针
    OtherInfo info;  //和边相关的信息
};

struct VertexNode
    //顶点的结点结构
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
};

//图的结构定义
struct ALG
{
    //AdjList vertices;  
    VertexNode vex[MVNum];//顶点表
    int vexnum, arcnum;  //顶点数和边数
}; //Adjacency List Graph

创建无向网:

LocateVex(G, v)函数:

Status LocateVexNumber(ALG G, VertexType v1)
{
    for (int i = 0; i <= G.vexnum; i++)
    {
        if (G.vex->data == v1)
            return i;
    }
    return -1;
}

函数体:

我写的第一个版本:

Status CreateUDG(ALG& G)//无向网
{
    int i, j, k;
    

    cin >> G.vexnum >> G.arcnum;  //输入顶点数和边数
    for (i = 0; i < G.vexnum; i++)
    {
        cin >> G.vex[i].data;  //输入顶点值
        G.vex[i].firstarc = NULL;  //初始化表头结点的指针域
    }

    for (int m = 0; m <= G.vexnum; m++)
    {
        VertexType c1, c2;
        cout << "input vexs" << endl;
        //输入一条边邻接的其他边所对应的其他的结点,也可以不止两个
        cin >> c1 >> c2;
        int a = LocateVexNumber(G, c1);
        int b = LocateVexNumber(G, c2);//两结点各自所对应的位置序号

        //开辟边结点空间
        ArcNode*p1 = new ArcNode;
        p1->adjvex = a;
        //p1->adjvex = LocateVexNumber(G, c1);
        p1->nextarc = ???;
        //啊?这时候我们还没有创建我们下一个边结点,这怎么搞啊
        G.vex[m].firstarc = p1;
        
        ...
    }

}

问题:

(1):

我们这里很明显的一个问题就是关于该算法输入边结点的机制的理解出现了问题:

我们觉得输入的两个节点

表示的是这个节点邻接的所有其他的节点

而实际上这里它就像表示的意思只是说

我们这里有一条边,它依附于(C1,C2)我们给出的这两个节点

(2):

根据(1):我们正常根据邻接表的图所画出的程序流程就应该是:

  1. a结点作为边结点p的邻接节点
  2. 然后b结点指向边结点p
  3. 最后,边结点p再指向下一个依附于b节点的边结点

但是,这里是如果这样的话,我们就碰到了一个我们前面写的程序一样也碰到的问题:

我们还不知道下一个节点,实际上这个时候下一个节点根本都还不存在,结果这个时候我们只能让它指向空

但是我们写的是一个for循环,如果要像这样,用尾插法实现该算法的话:

除非你再写一个for循环,然后第二个for循环里面,最后再加上一个指向前面上一个节点的语句操作

但是这样也太麻烦了,所以我们这里就使用头插法,那么程序正常的 流程就应该是:

  1. a结点作为边结点p的邻接节点
  2. 把边结点p插在顶点b和第一个边结点中间:
  1. 边结点p的next边结点=first结点
  2. b指向p

注意,必须要先赋值,如果b先指向p,那么我们就丢掉了first结点的地址,找不到他,没办法把他赋给next了

另外:

在这里我们不用担心一开始我们把first结点置空怎么办:

因为就算这个节点再怎么是空的,他总归(这个节点)还是会有一个地址来存储的

总不可能这个地址都不存在了吧,那就(是)根本不存在这个节点,而不是这个结点为空了


感悟:主要还是得靠自己研究思路以后自己写一遍代码,Tmd每天一遍遍吭哧吭哧看这标准答案然后搞得把他转化成中文最后还是get不到他什么意思,搞得...#%$&太tm费劲了


最终结果(成果):

Status CreateUDG(ALG& G)//无向网
{
    int i, j, k;
    

    cin >> G.vexnum >> G.arcnum;  //输入顶点数和边数
    for (i = 0; i < G.vexnum; i++)
    {
        cin >> G.vex[i].data;  //输入顶点值
        G.vex[i].firstarc = NULL;  //初始化表头结点的指针域
    }

    for (int m = 0; m <= G.vexnum; m++)
    {
        VertexType c1, c2;
        int weight;
        cout << "input vexs" << endl;
        //输入每条边依附的两个顶点及其权重
        cin >> c1 >> c2>>weight;
        int a = LocateVexNumber(G, c1);
        int b = LocateVexNumber(G, c2);
        //两个顶点各自所对应的位置序号

        //开辟边结点
        ArcNode*p1 = new ArcNode;
        p1->adjvex = a;
        //p1->adjvex = LocateVexNumber(G, c1);
        p1->nextarc = G.vex[b].firstarc;
        //边结点p的next边结点 = first结点       
        G.vex[b].firstarc = p1;//b指向p

        //无向图连线都(是)双向
        ArcNode* p2 = new ArcNode;
        p2->adjvex = b;
        //p1->adjvex = LocateVexNumber(G, c2);
        p2->nextarc = G.vex[a].firstarc;
        G.vex[a].firstarc = p1;
    }
    return true;
}

完整环境加函数算法:

#include<iostream>
using namespace std;

typedef int Status;

#define MVNum 100  //最大顶点数
//MAX Vertex Number
typedef char VertexType;  //设顶点类型:字符型

//弧/边的结点结构
typedef int OtherInfo;
struct ArcNode
{
    int adjvex;//Adjacency
    //该边所指向的(相邻)顶点的位置
    struct ArcNode* nextarc;  //指向下一条边的指针
    OtherInfo info;  //和边相关的信息
};

struct VertexNode
    //顶点的结点结构
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
};

//图的结构定义
struct ALG
{
    //AdjList vertices;  
    VertexNode vex[MVNum];//顶点表
    int vexnum, arcnum;  //顶点数和边数
}; //Adjacency List Graph

Status LocateVexNumber(ALG G, VertexType v1)
{
    for (int i = 0; i <= G.vexnum; i++)
    {
        if (G.vex->data == v1)
            return i;
    }
    return -1;
}

Status CreateUDG(ALG& G)//无向网
{
    int i, j, k;
    

    cin >> G.vexnum >> G.arcnum;  //输入顶点数和边数
    for (i = 0; i < G.vexnum; i++)
    {
        cin >> G.vex[i].data;  //输入顶点值
        G.vex[i].firstarc = NULL;  //初始化表头结点的指针域
    }

    for (int m = 0; m <= G.vexnum; m++)
    {
        VertexType c1, c2;
        int weight;
        cout << "input vexs" << endl;
        //输入每条边依附的两个顶点及其权重
        cin >> c1 >> c2>>weight;
        int a = LocateVexNumber(G, c1);
        int b = LocateVexNumber(G, c2);
        //两个顶点各自所对应的位置序号

        //开辟边结点
        ArcNode*p1 = new ArcNode;
        p1->adjvex = a;
        //p1->adjvex = LocateVexNumber(G, c1);
        p1->nextarc = G.vex[b].firstarc;
        //边结点p的next边结点 = first结点       
        G.vex[b].firstarc = p1;//b指向p

        //无向图连线都(是)双向
        ArcNode* p2 = new ArcNode;
        p2->adjvex = b;
        //p1->adjvex = LocateVexNumber(G, c2);
        p2->nextarc = G.vex[a].firstarc;
        G.vex[a].firstarc = p1;
    }
    return true;
}

int main()
{

}

十字链表:(用于有向图)

 邻接多重表:(用于无向图)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值