树、简单图的存储方法——邻接矩阵 邻接表 和 链式前向星 学习笔记

ps:树是一种特殊的图,树有自己特殊的存储方式,图的存储方式都能应用于树。

对于图、树来讲,一般给出一个n表是有n个节点(标号1~n)m个二元组(a,b)表示ab之间有一条边。这样就能确定一个图。

对于树来讲没有环,所以m=n-1

part one、邻接矩阵

邻接矩阵的优点是可以O(1)查出两点之间有没有边,缺点是无法高效的查找某个点的所有边,且对于稀疏图来讲浪费了大量的空间(存了很多0)。

    使用mp[maxn][maxn]二维数组存储,mp[i][j]=0表示节点i,j之间不直接相连,为1表示有一条边相连(当然对于简单图来说只能为1和0)。

int a,b,n,m;
cin>>n>>m;
memset(mp,0,sizeof(mp));//清0 
for(int i=0;i<n;i++){
    scanf("%d%d",&a,&b);//a和b之间有边
    mp[a][b]=mp[b][a]=1;//无向图两个都要赋值 
}

这样图就存好并可以使用了。

part two、邻接表

邻接表可以最高效率地查找某个点的所有边,但是无法高效地查询两个点之间是否有边。

使用链表存储(实际应用时为了方便用vector):只记录与点i有边的点,这样相当于记录边。相当于弱化的十字链表(多用了空间)

vector<int>mp[maxn];
cin>>n>>m;
for(int i=1;i<=m;i++){
    scanf("%d%d",&a,&b);
    mp[a].push_back(b);
    mp[b].push_back(a);

part three、链式前向星

前向星也是存储边。个人认为前向星只是邻接表的另一种写法,数组模拟链表空间分配(内存池)的一种写法。

好像单纯学前向星没有什么创新的知识,但由于看网上代码尤其是树链剖分和lca很多都用链式前向星的写法,还是老老实实理解一下前向星书写套路。

其实照着邻接表的思路理解链式前向星就很容易了(吐槽一下为什么起一个这么貌似高大上的名字,老老实实叫邻接表不好吗

const int maxn = 10005;
const int maxm = 1000005;//edge
using namespace std;
int n;
struct node {//存储边的数据结构,to是点,next是指针。 
    int to, next;    
//    int value ,from,  
};
node edge[maxm];//存储边的数组,兼任内存池。 
int box[maxn];//记录节点i邻接表第一个成员指针,使用头插法。 
int ecnt;//边的个数
inline void _make_map(int from, int to) {  //建立从from到to的一条单向边,若无向图则正反建立两条。 头插法 
    edge[ecnt].to = to;//to  节点
    edge[ecnt].next = box[from];//同节点下该边下一条边
    box[from] = ecnt++;// 节点from的第一条边
}
inline void make_map(int from, int to)//双向边
{
    _make_map(from, to);//正反向两次双向边 
    _make_map(to, from);
}
int main() {
    while (scanf("%d", &n) != EOF) {
        ecnt = 0;
        int i;
        int u[100], v[100];
        // 储存边
        for (i = 0; i < n; i++) {
            scanf("%d%d", &u[i], &v[i]);
            make_map(u[i], v[i]);
        }            
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值