算法 {删除树的叶节点}
删除树的叶节点
算法
通过度数来删除
代码
{ // 删除树的所有*叶节点*
auto const& __Tree = Graph;
int N = __Tree.PointsCount;
ASSERT_MSG_( "tree是*无向树*, 且没有*重复边*");
vector<int> __Degree; // `Degree[x]`表示`x`的邻接点的个数; (如果等于`-1` 说明该点被删除了已经);
//< 只有`Degree[x] != -1`的点 是存在的点(否则是已经删除的点); 对于边`a-b`(如果`a,b`点都存在 则该边才存在); 因为`Tree`我们不会修改他 因此借用`Degree[x]` 来表示*删除节点*这个操作;
// . 获取当前的新树的所有点: `FOR_( i,0,N-1){ if(__Degree[i]!=-1){ DE_(i);}}`; (注意*孤立点*这种情况, 其`Degree[]==0` 没有临界边 但他是存在的 而不是已删除);
// . 获取当前的新树的所有边: `FOR_( i, 0, N-1){ if(__Degree[i]==-1){continue;} GRAPH_ITERATE_( __Tree,i,nex,e){ if(__Degree[nex]==-1){continue;} DE_(i,nex);}}`;
__Degree.resize( N);
std::memset( __Degree.data(), 0, sizeof(__Degree[0])*N);
for( int i = 0; i < N; ++i){ GRAPH_ITERATE_( __Tree, i, nex, e){ __Degree[nex] ++;}}
auto __Delete = [&](){ // 每次调用该函数 就会删除*一层叶节点*;
static std::queue<int> __Que;
while( !__Que.empty()){ __Que.pop();}
for( int i = 0; i < N; ++i){
if( __Degree[i] == 0){ // 孤立点(他也属于*叶节点*)
__Degree[i] = -1; // 直接删除
}
else if( __Degree[i] == 1){ // 叶节点(且不是孤立点)
__Que.push( i);
}
}
while( 0 == __Que.empty()){
auto leaf = __Que.front(); __Que.pop(); // `leaf`一定是叶节点
__Degree[leaf] = -1; // 表示删除了`leaf`这个节点;
GRAPH_ITERATE_( __Tree, leaf, nex, e){
if( __Degree[nex] == -1){ continue;} // 表示`nex`已经被删除了;
-- __Degree[nex]; // 这表示删除了`leaf-nex`这条边
{ // 递归删除 (如果产生了新的叶节点, 就继续删除)
@TODO;
if( __Degree[nex] == 0){ // 孤立点(他也属于*叶节点*)
__Degree[nex] = -1; // 直接删除
}
else if( __Degree[nex] == 1){ // 叶节点(且不是孤立点)
__Que.push( nex); // 新的叶子节点
}
}
}
}
};
@TODO: __Delete();
} // 删除树的所有*叶节点*
应用
@LINK: https://editor.csdn.net/md/?articleId=129839971
;
递归的删除(即如果删除新叶节点 继续删除), 且只有满足某种条件的叶节点 才考虑删除;
错误
删除所有的叶节点和其父节点, 与, 执行两次(删除叶节点), 他俩的效果一样吗?
不一样, 比如X-a-b-c-Y, b-Z
, 执行两次(删除叶节点) 得到b
; 而删除所有叶节点和其父节点 得到空
;
因为, 你认为叶节点的父节点 就是 删除叶节点后的叶节点, 这是错误的, 你即便把叶节点给删除了, 他的父节点 不一定就是新树的叶节点;