第五章 图论

一、预备知识

1.表示图的2种数据结构:邻接矩阵、邻接链表。

①邻接矩阵:用一个二维数组来表示图的相关信息,表示的图为稠密图,且频繁用于判断某个特点的节点对是否相邻时,使用

邻接矩阵较合适。若遍历某节点相邻的所有节点时,则比较麻烦。

②邻接链表:为图中的每个节点建立一个单链表,第i个链表保存与结点vi相邻的所有链表。所以用于大量遍历某个结点的所有

邻接结点时,使用邻接链表较合适。

2.如何快速使用邻接链表?推荐使用STL中的标准模板std::vector。

①定义一个结构体用来表示一条边。

struct Edge {
int nextNode; //下一个结点编号
int cost; //边的权值
};

②为每个结点都建立一个单链表用来保存与其相邻的结点及权值。

vector<Edge> edge[N]

建立了一个大小为N的数组,数组中的每个元素保存的是vector对象。为每个结点都建立了一个vector对象。

③对单链表进行操作

为了使用vector需要在头部加入相应的头文件:

#include <vector>
using namespace std;

对单链表进行初始化,即 利用vector::clear()操作清空单链表

for(int i = 0;i < N;i++)
      edge[i].clear();

利用vector::push_back(Edge)添加信息:

Edge tmp;
tmp.nextNode = 3;
tmp.cost = 38;
edge[i].push_back(tmp);

需要查询某个结点的所有邻接结点时,对vector进行遍历:

for(int i=0;i<edge[2].size();i++) {
      int nextNode = edge[2][i].nextNode;
      int cost = edge[2][i].cost;
}

删除结点1的单链表中edge[1][i]所对应的边信息时:

edge[1].erase(edge[1].begin()+i,edge[1].begin+i+1);

需要记住以上vector的基本用法,对单链表进行清空、添加、删除、遍历等操作。


二、并查集

1.图论中经常要用到的数据结构----集合,还有它的一个相关操作----并查集。

这种数据结构用来表示集合信息,用以实现如确定某个集合中是否有哪些元素、判断某两个元素是否在同一个集合中、求集合中元素数量等。

2.可以通过不断的求双亲结点来找到该结点所在树的根结点,若2个结点的根节点相同,则可以判定它们在同一棵树上,它们属于一个结合。

3.合并两树的过程中,若仅仅简单的将两树合并在一起,则树高可能会逐渐增加,极端情况下会变成一个单链表,这样查找的耗时就增加了。

为了避免这种情况,我们可以在查找某个结点的根节点的时候,同时将其与根节点之间所有的结点都直接指向根节点,这个过程称为路径压缩。

4.代码实现。

定义一个数组,用双亲法表示树,tree[i]表示i的双亲结点,若tree[i] = -1表示该结点为根节点。

int tree[N];


查找结点x所在树的根结点:

递归版本:

int findRoot(int x) {
     if(tree[x] == -1)
           return x;
     else return(tree[x]);
}

非递归版本:

int findRoot(int x) {
int ret;
while(tree[x] != -1)
    x = tree[x];
ret = x;
return ret;
}

加上路径压缩的优化:

int findRoot(int x) {
      if(tree[x] == -1) return x;
      else {
                int tmp = findRoot(tree[x]);
                tree[x] = tmp;
                return tmp;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值