存储图的方式

参考:
vector的使用 https://blog.csdn.net/tpriwwq/article/details/80609371
图分为有向图 无向图

存图的几种方法

较好的存图能满足的要求

1)能表示图中的结点相连的情况
2)获得能表示图中的结点相连边的权重
3)考虑空间 像邻接矩阵的空间复杂度为O(n^2)
4)能知道一个结点 所连的所有结点的边的情况

1、邻接矩阵

使用二维数组map[][]存储两个边的连接情况

可以map[i][j] = 1表示 i和j是有边的 是连接的

也可以map[i][j] = w(权重) 表示i和j之间边的权重

空间复杂度为O(n^2) 复杂度过高 不满足第3条

2、边的数组 Edge[maxn]

我们可以使用Edge类,它表示两个int实例变量。这种表示方法很简单
但是不能知道一个结点 所连的所有结点的边的情况 不满足第4条

3、邻接表数组(效果最好) 本节未给出该实现代码

我们可以使用一个以顶点为索引的列表数组,其中的每个元素都是和该顶点相邻的顶点列表
都能满足

4、链式前向星(中规中矩)

w是起点序号 cnt表示边的序号 edges[maxn] 表示边的数组 边的序号其实就是edges数组的下标
head[w] 存放的是最新一条边的序号 边里面的属性包含to w和next(起点的上一条边序号)
所以 head[w]放了最新一条边的序号 这条边记录这上一条边序号 这个迭代过程的边都是以w为起点的边
循环起点的所有边时
从i=head[w]最新的边序号开始 遍历edges数组 然后i=边里储存的next(上一条边序号) 直到i = 0了(因为head[w]起初默认为0) 也就是上一条没边了 即刚刚循环到的边就是w连接的第一条边
head[w]起初默认为0
用数组模拟链表

struct Edge{
    int to, w, next;
}edges[MAXM];
int head[MAXN], cnt; // cnt为当前边的编号
void add(int from, int to, int w){
    edges[++cnt].w = w;    //新增一条编号为cnt+1的边,边权为w
    edges[cnt].to = to;    //该边的终点为to
    edges[cnt].next = head[from];  //以form为起点的这条边的next指向上一条from为起点的最新一条的边
    head[from] = cnt;  //该边成为当前起点最新的第一条边
}

设一个edges数组 用来表示边 用cnt 表示边的符号
head[maxn] 表示当前顶点为起点的最新的一条边
edge 中的to表示终点 w表示权重 next表示以from为起点的上一条最新的一条边

比如

加入顺序为 1-2、1-3、1-4

1、刚开始 head[maxn]初始化为0 边的序号cnt为0

2、那么 加入边1-2 cnt=1 to为2 next为0 head[from] = 1;

//next是起点上一条最新的边 加入边1-2 自然更新1起点最新边为边1-2

3、加入边1-3 cnt=2 to为3 原先head[1]=1 所以next = 1 然后更新head[from] = 2 为该边

4、加入边1-4 cnt=3 to为4 原先head[1]=2 所以next = 2 然后更新head[from] = 3 为该边

遍历的时候

先从起点x最新的边搜起 然后找到 边的next 一直找下去 直到next=0 说明起点x连接的边遍历完成

顺序 是从最晚添加的边慢慢到最早添加的边

//打印2号顶点能到达的所有点

for (int e = head[2]; e != 0; e = edges[e].next)
    printf("%d ", edges[e].to);

总结来说 用最新的边来记录起点连接的上一条边 用head来记录起点最新的边 边的next=head[起点]也就是上一条最新的边 然后head[起点] = 最新的边

head[]记录的是边的序号 边的next记录的也是边的序号

//链式前向星边
class lianshiEdge{
    public:
        int from;
        int to; //表示终点
        int w; //表示权重
        int next; //表示起点的上一条最新边
    public:
        lianshiEdge(){
            
        }    
        lianshiEdge(int from, int to, int w){
            this->from = from;
            this->to = to;
            this->w = w;
        }
};
//链式前向星
class lianshiqxx{
    public:
        lianshiEdge edges[maxn];  //边的集合
        std::vector<lianshiEdge> adj[maxn];  //起点连接的边的集合
        int head[maxn];  //表示起点的最新一条边
        int cnt; // cnt为当前边的编号
    public:    
        lianshiqxx(){
            this->cnt = 0;
            memset(head, 0, sizeof(head));
        }
        void init(){
            this->cnt = 0;
            memset(head, 0, sizeof(head));
            lianshiEdge e;
            for(int i = 0; i < maxn; i++){
                edges[i] = e;
            }
        }
        //添加边
        void addEdge(lianshiEdge e){
            int from = e.from;
            int to = e.to;
            int w = e.w;
            edges[++cnt].w = w;    //新增一条编号为cnt+1的边,边权为w
            edges[cnt].to = to;    //该边的终点为to
            edges[cnt].next = head[from];  //以form为起点的这条边的next指向上一条from为起点的最新一条的边
            head[from] = cnt;  //该边成为当前起点最新的第一条边
        }
        //获取某个点的连接的边集合 返回集合
        std::vector<lianshiEdge> getAdj(int s){
            if(adj[s].size()){    //避免重复添加
                adj[s].clear();
            }
            for (int e = head[s]; e != 0; e = edges[e].next){
                adj[s].push_back(edges[e]);             //添加边
            }
            return adj[s];       //返回边 集合
        }
        //获取某个点的连接的边集合 无返回值
        void getAdjNotReturn(int s){
            if(adj[s].size()){     //避免重复添加
                adj[s].clear();
            }
            for (int e = head[s]; e != 0; e = edges[e].next){
                adj[s].push_back(edges[e]);
            }
        }
        //打印
        void printAdj(int s){
            getAdjNotReturn(s);
            for (std::vector<lianshiEdge>::iterator e = adj[s].begin(); e != adj[s].end(); e++)
                {
                    cout<<(*e).from<<(*e).to<<(*e).w<<(*e).next<<endl;
                }
        }
};
int main(){  
    //链式前向星测试
    lianshiqxx lsqxx;
    lianshiEdge e1(1, 2, 1);
    lianshiEdge e2(1, 3, 2);
    lianshiEdge e3(1, 4, 3);
    lsqxx.addEdge(e1);
    lsqxx.addEdge(e2);
    lsqxx.addEdge(e3);
    lsqxx.printAdj(1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值