广义表head tail 运算_算法之链表与邻接表千字总结

YOU CAN DRINK ALL YOU LIKE, BUT IN THE MORNING YOU GET HEADACHE WITH THE SAME PROBLEMS.


0x13链表与邻接表

链表

为了避免双向链表在左右两端或者空链表中访问越界,我们通常建立额外的两个节点headtail代表链表头尾,把实际数据节点存储在headtail之间,来减少链表边界处的判断,降低编程复杂度

ACWING136.邻值查找

题目描述在文章末尾的原文链接中

解法一:链表

读入数据后串成链表,再对数组排序,此时找第N个数的前驱和后继,比较N与前驱、后继的差的绝对值,得到目标值后,再删除N,继续找N-1的前驱、后继,时间复杂度为O(NlogN)

#include 
using namespace std;

#define int long long
typedef pair<int, int> PII;
const int N = 1e5 + 10;

int n;
int l[N], r[N];
int p[N];
PII a[N], ans[N];

int32_t main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].first;
        a[i].second = i;
    }
    
    sort(a + 1, a + 1 + n);
    
    for (int i = 1; i <= n; i++) {
        l[i] = i - 1, r[i] = i + 1;
        p[a[i].second] = i;
    }
    a[0].first = 0xffffffff;
    a[n + 1].first = 0xffffffff;
    for (int i = n; i > 1; i--) {
        int j = p[i], left = l[j], right = r[j];
        int lv = abs(a[left].first - a[j].first);
        int rv = abs(a[right].first - a[j].first);
        if (lv <= rv) ans[i] = {lv, a[left].second};
        else ans[i] = {rv, a[right].second};
        l[right] = left, r[left] = right;
        
    }
    
    for (int i = 2; i <= n; i++) cout <" " <endl;   
}

解法二:平衡树

A1 A2 A3 ... An依次插入一个集合,则在插入Ai之前,集合中保存的就是满足1<=J的所有Aj。根据题意,我们只需在集合中查找与Ai最接近的值

若能维护一个有序集合,则集合中与Ai最接近的值一定在Ai的前驱与后继当中,比较前驱与后继与Ai的差即可

而平衡二叉树就是一个支持动态插入、查询前驱以及查询后继的数据结构。在C++中,STLset也为我们提供了这些功能

邻接表

邻接表是树与图的一般化存储方式,还能用于实现开散列Hash表。实际上,邻接表可以看成“带有索引数组的多个数据链表”构成的结构集合。在这样的结构中存储的数据会被分成若干类,每一类的数据构成一个链表,每一类还有一个代表元素,称为该类对应链表的表头。所有表头构成一个表头数组,作为一个可以随机访问的索引,从而可以通过表头数组定位到每一类数据对应的链表

在一个具有N个点M条边的有向图结构中,我们可以把每条边所属的“类别”定义为该边的起点标号。这样所有边被分为N类,其中第X类就由“从X出发的所有边”组成。通过表头head[X],我们很容易定位到第X类对应的链表,从而访问从点X出发的所有边

对于无向图,我们把每条无向边看作两条有向边插入即可。有一个小技巧是,结合成对变换的位运算性质,我们可以在程序最开始时,把第一条边存储在2 3位置上,这样每条边都会存储在2 3 4 5这样的位置上。通过对下标进行XOR 1的运算,就可以直接定位到与当前边反向的边。换句话说,如果ver[i]时第i条边的终点,那么ver[i xor 1]时第i条边的起点

9e85b48233f4bf8f18d5c33b31c5add7.png
9545eef1fcda033d4017711c195ef2d8.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值