“沿真实最小度剥离记录每份非空剩余图,选边数/顶点数最大的那份。只保存最佳前缀位置,结束后取排列的相应后缀,不每次复制整份剩余集合。删v时,剩余边数减去v的当前度,每条边恰好扣一次。”
形式陈述
一次次删掉支撑不足的顶点
在有限简单无向图G=(V,E)中,只留下S及其内部全部边,得到诱导子图G[S]。如果希望每个保留顶点都至少有k个保留邻居,就不能只在原图上筛一次度数:某个邻点被删之后,原本够数的顶点可能也不够了。
对非负整数k,k-core的顶点集Cₖ是满足
的按包含关系最大的集合。允许Cₖ为空。这样的最大集合确实唯一:两个满足条件的集合取并后,每个原有顶点的邻居只会增加,仍满足条件;把有限多个候选取并即可。这里不是任选一个包含极大候选。[1,§2]
C₀=V,且Cₖ₊₁⊆Cₖ。顶点v的核数c(v)是使v∈Cₖ的最大k。非空图的退化度定义为
它等于maxᵥc(v)。空图没有非空S,本页约定退化度为0,核数数组和删除序都为空;孤立点则仍存在,核数是0。k-core可以不连通,也不要求任意两点直接相邻。
本页算法输出每个原顶点的c(v)、一个排列π=(v₀,…,vₙ₋₁)、删除时真实度数dₜ,以及δ。π满足每个顶点至多有δ个更晚邻居,称为退化序。输入用邻接表保存,保留孤点,拒绝自环、重边和域外端点。附件标号固定为0,…,n−1;并列取桶首,不承诺每次都选原标号最小者。
直觉
删除安全性解释为什么可以反复剥离
先固定k。若当前剩余图里v的度数小于k,那么任何仍包含在当前图中的k-core都不能包含v,因为继续缩小顶点集只会使它邻居更少。因此删掉v不会删错;重复直到没有这种顶点时,剩余集合本身满足最小度至少k,又包含每个可能的k-core,故恰是Cₖ。
这也证明删除次序无关:每次可以删任意一个当前低度顶点,最后仍得到同一个Cₖ。不同的是删除日志,不是k-core本身。只筛原度数会漏掉连锁反应,例如三点路径的原中心度数为2,但两个端点剥掉后,它不能留在2-core中。
一个删除序同时回答所有k
不为每个k重新运行。始终删除当前真实度数最小的顶点vₜ,记其度为dₜ,并维护前缀最大值
真实度数dₜ可能下降;核数Dₜ不会下降。为何前缀最大值是正确的?对固定k,在第一次出现dₜ≥k之前,所有被删顶点都不足k,依前段安全性不属于Cₖ。如果第一次出现,则当前最小度已经至少k,剩余图就是Cₖ。以后即使某点删到只剩一个邻居,它原来仍在这个k-core里,所以核数不能跟着降回1。若整轮没有dₜ≥k,则Cₖ为空。
于是Cₖ恰是核数至少k的顶点集,所有核数一次得到。退化度δ也等于maxₜdₜ:出现最大值的那份剩余图给出下界;任意非空诱导子图S中,取π里最早的顶点,它在S中的所有邻居此时都还没删,度数至多δ,给出上界。
核数不是一份残余度快照
对四点完全图,删除度数依次为3、2、1、0,但四个点核数都为3。若直接写c(vₜ)=dₜ,会把后三点误标为2、1、0。某些线性核分解实现改用钳位键,仅在邻点键大于当前键时递减;它存的是不同不变量。[1,§§3–4] 本页保留真度数再取前缀最大值,使同一轨迹还可交给需要实际最小度的密度算法。
例子与边界
四种层次在同一张图中出现
取四团A={0,1,2,3},另取完全二部图B,左侧{4,5}、右侧{6,…,13};再加叶边0–14和孤点15。全图16点、23边。先删15不损失边;再删14,0的度数从4降为3。二部部分右点当前度为2,比四团的度3小,因而先被剥离。
附件给出下面的真实轨迹,表内边数均在本次删除之前:
| 删除顶点 | 当前度dₜ | 剩余顶点数 | 剩余边数 | 核数Dₜ |
|---|---|---|---|---|
| 15 | 0 | 16 | 23 | 0 |
| 14 | 1 | 15 | 23 | 1 |
| 6,7,8,9,10,11 | 各2 | 14至9 | 22,20,18,16,14,12 | 各2 |
| 5 | 2 | 8 | 10 | 2 |
| 13 | 1 | 7 | 8 | 2 |
| 4 | 1 | 6 | 7 | 2 |
| 12 | 0 | 5 | 6 | 2 |
| 0,3,2,1 | 3,2,1,0 | 4,3,2,1 | 6,3,1,0 | 各3 |
所以C₁={0,…,14},C₂={0,…,13},C₃=A,C₄为空。C₂不连通:四团和二部部分都能各自提供至少两个邻居,没有理由强行把它们合成一个连通块。
更晚邻居有界,不代表它们成团
退化序只限制|N⁺(v)|≤δ。完美消去序还要求N⁺(v)两两相邻,强得多。四圈退化度为2,也有退化序,却没有完美消去序。不能用核分解替代弦图识别。
完全二部图K₃,₃的全部顶点核数为3,却没有任何三角形:三个顶点必有两个在同一侧,它们之间无边。相反,四团也有核数3,含四个三角形。核数描述持续的邻居支撑,不直接统计小团。
一次增加边可能让许多核数改变。长度至少3的路径中每点核数都是1;把两个端点连起来后形成环,每点核数都变成2。本页是静态全量算法,没有声称动态修改只需更新两个端点。
推论与应用
真度数的桶如何保持线性
所有度数在0,…,n−1。建立head[d]指向度为d的顶点链表,每点保存prev、next;已知顶点位置后,可在常数时间从旧桶摘除并插入新桶。这里用两个方向的位置数组实现双链,不在线性表里搜索顶点。
初始化 degree[v]、各度数桶、alive[v]
D = 0;p = 0
重复n次:
把p向上移动,直到head[p]非空
从该桶取v;记录d=degree[v]
D = max(D,d);core[v]=D;把v标成已删除
对每个仍存活的邻点u:
从degree[u]桶摘除u
degree[u]减1,插入新桶
p = min(p,degree[u])
每条无向边恰在较早端点删除时使较晚端点度数减1,迁移总数为m;扫描邻接记录总数2m。寻找非空桶也没有隐藏的n²:删当前最小度d后,每个邻点至多减1,其新度至少d−1,因此每轮p最多向下退1,全部下退至多n。p始终在0,…,n−1,累计上移至多初末差加累计下退,也是O(n)。图准备、桶初始化、全部日志合计O(1+n+m)时间、O(1+n+m)空间。
附件从边表准备邻接表时,逐顶点用一份长度n的时间戳数组检查重复邻居,同样线性。它没有要求哈希平均常数访问,也没有偷偷按顶点对排序。固定字长标号和O(log(n+1))位计数按RAM口径计费。
不相信桶实现,也能检查核数
一份证书只含π和整数标签c(v)。检查排列无重复、c沿π不降,并对每点核两项:
- v至少有c(v)个邻点u满足c(u)≥c(v)
- v至多有c(v)个在π中更晚的邻点
第一项证明每个集合{v:c(v)≥k}的最小度至少k,因此标签不会超过真实核数。反过来,假设某个标签≤k的点仍属于一个最小度至少k+1的子图。在这个子图取π中最早点v;标签不降使c(v)≤k,而其所有子图邻居都比它晚。第二项说它最多有k个这样的邻居,矛盾。故标签也不会低估,证书充分。
检查用位置数组及两次邻居计数,O(1+n+m),不用重跑桶队列。只交“各Cₖ最小度够大”仅证下界,会接受遗漏合法顶点的过小核心;删除方向的上界同样需要。
同一排列可交给不同任务
按π反向作贪心着色,每点已有颜色的邻居至多δ个,因此δ+1色足够。这只是可行上界,K₃,₃实际只需两色。使用颜色时间戳,寻找最小空颜色至多检查当前邻色数加1,整体仍可线性。
三角形列举沿π给边定向,让每点出度≤δ;最稠密子图算法则读取每个删除前缀的剩余边数和顶点数。两者依赖的是不同记录,不能把核数直接当每轮真实度数。完整三份输出见综合练习。
参考资料
- Vladimir Batagelj、Matjaž Zaveršnik,An O(m) Algorithm for Cores Decomposition of Networks,2003,§§2–4.1,PDF pp.2–6:核心嵌套、阈值删除和桶实现。原文实际复杂度保留O(max(m,n)),连通时才简写O(m)。本页真度数桶和上下证书分别给出自己的不变量证明。
- Moses Charikar,Greedy Approximation Algorithms for Finding Dense Components in a Graph,APPROX2000,§3,PDF pp.4–6:真实最小度删除及整数度数桶的线性费用。本文16点输入与全部轨迹由附件复算。