刷题模板:单链表+邻接表(数组模拟)+ 图的搜索

通过学习y总视频中的数据结构部分,学习笔试中常用的 数组 模拟单链表 和 邻接表。

一、数据的存储

1、单链表

#include<bits/stdc++.h>
const int N = 100010;

/*
    head表示指向头节点的指针
    e[N] 存储每个节点的val
    ne[N] 存储每个节点的next指针 对应于e 和 ne 数组中的index
    idx表示当前可以从哪个节点开始使用
    空节点用idx=-1 表示


    换一种方式进行表述:
    idx可以理解为"一个链表节点在内存中的地址"。
    e[idx]就是获取地址为idx的所对应的val。
    ne[idx]就是获取地址为idx所对应节点的下一个节点的地址。

    typedef struct ListNode{
        int val;
        ListNode* next;
    };
    
    idx        等价于  ListNode* node = new ListNode()中的node
    e[idx]     等价于  node->val;
    ne[idx]    等价于  node->next;
*/
int head, e[N], ne[N], idx;

void init(){
    // 头节点指向空
    head = -1;
    // 可从idx为0开始申请新的节点
    idx = 0;
}

// 在index为k所对应的节点后面插入一个节点
void add(int k, int x){
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx++; 
}

void remove(int k){
    ne[k] = ne[ne[k]];
}

2、邻接表

邻接表主要用于图的存储(树是一种特殊的无向连通图),相比于单链表,它的头节点转化为了一个数组。

#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int h[N], e[N], ne[N], idx++;

// 给序号为a的点 插入一条指向 序号为b的点的 边
int add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

二、图的搜索

图的搜索主要是 深度优先搜索 和 宽度优先搜索,深度优先搜索使用,宽度优先搜索使用队列

1、宽度优先搜索

宽度优先以Acwing中:847. 图中点的层次 这题为例:代码如下所示:

#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int h[N], e[N], ne[N], idx;
int d[N];
int n, m;
queue<int> que;

void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void bfs(){
    // 1.初始化 容易忘记对d数组进行赋值
    memset(d, -1, sizeof(d));
    d[1] = 0;
    que.push(1);

    // 只要队列不为空
    while(!que.empty()){
        // 2.队头出队
        int u = que.front();
        que.pop();
        
        // 3、尝试添加新元素到队列
        for(int i = h[u]; i!=-1; i = ne[i]){
            int j = e[i];
            if(d[j] == -1){
                d[j] = d[u] + 1;
                que.push(j);
            }
        }// end for
    }// end while
    cout<<d[n]<<endl;
}

int main(){
    cin>>n>>m;
    // 头节点的初始化 (这个地方很容易忘记)
    memset(h, -1, sizeof(h));
    for(int i=0; i<m; i++){
        int a, b;
        cin>>a>>b;
        add(a, b);
    }// end for
    
    bfs();
}

2、深度优先搜索

关键是使用递归的思路,在进行递归遍历过程中,进行一些其他类似统计数目的一些工作。以Acwing中题为例:846. 树的重心

#include<bits/stdc++.h>
using namespace std;

const int N = 100010, M = 2*N;
int h[N], e[M], ne[M], idx;
bool st[N];
int n;
int ans = INT_MAX;


void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

/*
    思路就是在进行树或者图的遍历过程之中,
    顺便进行一些统计数目的操作
*/
int dfs(int u){
    // 1、设置该点被遍历过
    st[u] = true;
    int sum = 1, res = 0;
    for(int i=h[u]; i!=-1; i = ne[i]){
        // 获取该点的子节点
        int j = e[i];
        if(!st[j]){
            // 获取该子节点的所有节点数目
            int tmp = dfs(j);
            sum += tmp;
            // 统计哪一个子节点中包含的数目最多
            res = max(tmp, res);
        }
    }// end for
    
    ans = min(ans, max(res, n - sum));
    return sum;
}

int main(){
    cin>>n;
    memset(h, -1, sizeof(h));
    for(int i=0; i<n; i++){
        int a,b;
        cin>>a>>b;
        add(a, b), add(b, a);
    }// end for
    
    dfs(1);
    cout<<ans<<endl;
}

总结一下:

1、理解如何进行图的存储(邻接表)。

2、然后就是背模板。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值