超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

这篇具有很好参考价值的文章主要介绍了超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一,什么是线段树?

  • 线段树是怎样的树形结构?

  线段树是一种二叉搜索树,而二叉搜索树,首先满足二叉树,即每个结点最多有两颗子树,并且是一颗搜索树,我们要知道,线段树的每个结点都存储了一个区间,也可以理解成一个线段,而搜索,就是在这些线段上进行搜索操作得到你想要的答案

  • 线段树能够解决什么样的问题?

  线段树的适用范围很广,可以在线维护修改以及查询区间上的最值求和。对于线段树来说,每次更新以及查询的时间复杂度为O(logN)

  • 线段树和其他RMQ算法的区别

  常用的解决RMQ问题ST算法,二者预处理时间都是O(NlogN)

(详见ST算法解决BMQ问题详解),而且ST算法的单次查询操作是O(1),看起来比线段树好多了,但二者的区别在于线段树支持在线更新值,而ST算法不支持在线操作

1. 静态的区间询问:ST表

2. 动态的区间询问:线段树/树状数组

静态指的是,数字 不会发生 改变
动态指的是,在 查询过程中,数字可能会发生一定程度的 修改

二,线段树的基本操作

建树

思路

首先,我们得先明白几件事情:

 每个结点存什么

结点下标是什么

如何建树

下面我以一个简单的求一段区间的最大值来描述上面的三个概念。

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

  对于a[1~6] = {1,8,6,4,3,5}来说,线段树如上所示,红色代表每个结点存储的区间蓝色代表该区间最值

  可以发现,每个叶子结点的值就是数组的值,每个非叶子结点的度都为二,且左右两个孩子分别存储父亲一半的区间。每个父亲的存储的值也就是两个孩子存储的值的最大值。

  那么结点到底是如何存储区间的呢,以及如何快速找到非叶子结点的孩子以及非根节点的父亲呢,这里也就是理解线段树的重点以及难点所在,线段树你只要理解了结点与结点之间的关系便能很快理解线段树的基本知识。

  对于一个区间[l,r]来说,最重要的数据当然就是区间的左右端点l和r,但是大部分的情况我们并不会存储两个数值,而是通过递归传参方式进行传递。这种方式可以直接用数组存树,那这里怎么快速使用下标找到左右子树呢?

  对于上述线段树,我们增加绿色数字为每个结点的下标

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

  则每个结点下标如上所示,这里你可能会问,为什么最下一排的下标直接从9跳到了12,因为中间其实是有两个空间的呀!!

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

虽然没有使用,但是他已经开了两个空间,这也是为什么线段树建树需要2*2k(2k-1 < n < 2k)空间,一般会开到4*n的空间防止RE。

  仔细观察每个父节点和子节点下标的关系,不难发现以下规律

l = fa*2 (左子树下标为父节点下标的两倍)
r = fa*2+1(右子树下标为父节点下标的两倍+1)

那么明白了数组如何存线段树,结点间的关系,

建树时每次递归就要先判断l是否等于r,等于就说明是叶子节点,也就是区间是[l,l],直接赋值a[l]/a[r],再返回

否则就递归构造左儿子结点和递归构造右儿子结点,最后更新父节点

是不是觉得其实很简单。

详细代码


void bui(int id,int l,int r)//创建线段树,id表示存储下标,区间[L,r]
{
  if(l == r)//左端点等于右端点,即为叶子节点(区间长度为1),直接赋值即可
  {
    tr[id] = a[l];
    return ;
  }
// 否则将当前区间中间拆开成两个区间
  int mid = (l + r) / 2;//mid则为中间点,左儿子的结点区间为[l,mid],右儿子的结点区间为[mid + 1,r]
  bui(id * 2,l,mid); //递归构造左儿子结点
  bui(id * 2 + 1,mid + 1,r); //递归构造右儿子结点
// 左右两个区间计算完成以后
// 合并到当前区间
  tr[id] = min(tr[id * 2],tr[id * 2 + 1]);//更新父节点
}

看完代码是不是很清晰,这里也建议自己再次手动实现一遍理解递归的思路。

区间查询

思路

我们知道线段树的每个结点存储的都是一段区间的信息 ,如果我们刚好要查询这个区间,那么则直接返回这个结点的信息即可,比如对于上面线段树,如果我直接查询[1,6]这个区间的最值,那么直接返回根节点信息返回13即可,但是一般我们不会凑巧刚好查询那些区间,比如现在我要查询[2,5]区间的最值,这时候该怎么办呢,我们来看看哪些区间被[2,5]包含了。

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

  一共有5个区间,而且我们可以发现[4,5]这个区间已经包含了两个子树的信息([4,4],[5,5]),所以我们需要查询的区间只有三个,分别是[2,2],[3,3],[4,5],到这里你能通过更新的思路想出来查询的思路吗? 我们还是从根节点开始往下递归,如果当前结点是被要查询的区间包含了的,则返回这个结点的信息,这样从根节点往下递归,时间复杂度也是O(logN)

详细代码


//id 表示树节点编号,l r 表示这个节点所对应的区间
//x y表示查询的区间
int find(int id,int l,int r,int x,int y)
{
  //需要查询的区间[x,y]将当前区间[l,r]包含的时候
  if(x <= l && r <= y) return tr[id];
  int mid = (l + r) / 2,ans = -INT_MAX;
   // 如果需要查询左半区间
  if(x <= mid) ans = min(ans,find(id * 2,l,mid,x,y));   
  // 如果需要查询右半区间
  if(y > mid) ans = min(ans,find(id * 2 + 1,mid + 1,r,x,y));
  return ans;
}

  如果你能理解建树的过程,那么这里的区间查询也不会太难理解。还是建议再次手动实现。

单点更新

思路

很简单,就是从根节点递归去找a[x],找到了就返回,并再返回的一路上断更新其父节点的max值。

详细代码


// id 表示树节点编号,l r 表示这个节点所对应的区间
// 将 a[x] 修改为 v
// 线段树单点更新
void gexi(int id, int l, int r, int x, int v)
{
// 找到长度为 1 的区间才返回
  if (l == r)
  {
    tr[id] = v;
    return;
  }
//否则找到 x 在左区间或者右区间去更新
  int mid = (l + r) / 2;
  if (x <= mid) gexi(id * 2, l, mid, x, v);// 需要修改的值在左区间
  else gexi(id * 2 + 1, mid + 1, r, x, v);// 需要修改的值在右区间
  tr[id] = max(tr[id * 2], tr[id * 2 + 1]);
}

区间更新

意思

在线段树中会遇到区间更新的情况,例如 在区间求和问题中,令[a,b]区间内的值全部加c,若此时再采用单点更新的方法,就会耗费大量时间,这个时候就要用到懒标记(lazy标记)来进行区间更新了。

建树

这个操作根普通的一模一样

思路(更新)

懒标记(lazy-tag),又叫做延迟标记

当前结点对应区间[l, r]待更新区间[a, b]

 当 a ≤ l ≤ r ≤ b,即 [l, r]∈[a,b]时,不再向下更新,仅更新当前结点,并在该结点加上懒标记,当必须更新/查询该结点的左右子结点时,再利用懒标记的记录向下更新(pushdown)——懒标记也要向下传递,然后移除该结点的懒标记

这样就不用每次更新到叶子结点,减少了大量非必要操作,从而优化时间复杂度。

具体举个栗子:

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

就比如发压岁钱,一次操作是太爷爷要发给[1,3]1块压岁钱,那么先发到爷爷手里,但是爷爷很懒

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)
超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

想着:反正这Q是我们家族的(要发Q的区间包含了爷爷管的区间),我就暂时收这了! ψ(`∇´)ψ 暂时不想下放,于是将lazy标记+1(太爷爷发的Q数),并且因为爷爷节点储存的是以他根的树的子节点的Q总数,所以他自己的sumv自然要+1*3(太爷爷发的Q数*爷爷代表的区间长度r-l+1);

然后不要忘记递归回去时还要将太爷爷的sumv更新。

那么此时这棵树就变成了这样:

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

然后太爷爷一天突然心情大好,于是又发了一些钱,也就是给[2,3]2块压岁钱,那么先会发到爷爷手里。但是爷爷发现这笔Q要发放的区间不是由他管理,而是由他的儿孙中的一个管理,所以爷爷只能先将手中的压岁Q下放,在递归左右孩子(因为如果不先把压岁Q下放的话后面更新的值会错)。 >﹏<

在这里插一句嘴QwQ:下放操作是这样的,首先将id的左孩子的lazy+他的lazy,再将id左孩子的Q+它、他下放的Q*左孩子区间长度(右孩子的这2步操作同理)(可以看做这个家族的所有人都很懒

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

),最后不要忘了还要把lazy[id]清空(详见代码)

下放后:

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

我们继续。当到了叔叔的区间时会发现:叔叔的左区间<太爷爷要发压岁Q的左区间,也就是说叔叔即他的儿孙并不会被太爷爷发压岁Q。所以继续递归到爸爸的区间,此时爸爸发现这Q是我们家族的(要发Q的区间包含了爸爸管的区间),而他传承了爷爷的"优良"传统,也很懒 o(* ̄▽ ̄*)ブ 暂时不想下放,于是将lazy标记+2(太爷爷发的Q数),并且因为爸爸节点储存的是以他根的树的子节点的Q总数,所以他自己的sumv自然要+1*2(太爷爷发的Q数*爸爸代表的区间长度r-l+1);

然后不要忘记递归回去时还要将,爷爷,太爷爷的sumv更新。

那么此时这棵树变成了这样:

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

代码(更新)


void push_up(int id)
{
  sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void push_down(int id,int l,int r)
{
  if(lazy[id])//如果id有lazy标记
  {
    int mid = (l + r) / 2;
    lazy[id * 2] += lazy[id];//将它的左孩子的lazy加上它的lazy
    lazy[id * 2 + 1] += lazy[id];//将它的右孩子的lazy加上它的lazy
    sumv[id * 2] += lazy[id] * (mid - l + 1);//左孩子的Q+它下放的Q*区间长度
    sumv[id * 2 + 1] += lazy[id] * (r - mid);
    lazy[id] = 0;//清空lazy标记
  }
}
void qjgx(int id,int l,int r,int x,int y,int v)//id:目前查到的节点编号  目前区间为[l,r]  目标是讲[x,y]的所有数+v
{
  if(l >= x && r <= y)//[l,r]被[x,y]包含了
  {
    lazy[id] += v;//暂时不下放Q,加进lazy标记中
    sumv[id] += v * (r - l + 1);//将Q收入囊中
    return ;
  }
  push_down(id,l,r);//要来更新下面节点了,赶紧下放Q
  int mid = (l + r) / 2;
  if(x <= mid) qjgx(id * 2,l,mid,x,y,v);//因为只有x<=mid(即[l,mid]有一部分是被[x,y]覆盖了的)才需要去更新[l,mid]
  if(y > mid) qjgx(id * 2 + 1,mid + 1,r,x,y,v);
  push_up(id);//子节点更新完之后父节点当然也要更新(上升操作)
}

思路(查询)

书接上回。一次太爷爷去别人家做客时发现大人们总是把过年的压岁Q"帮"孩子们收着,美名曰"保管"(其实就是强占),于是太爷爷决定去查询一下孩子们的压岁Q有没有发放到位 ̄へ ̄

比如他要查询的是[1,2]那么首先要查询的是爷爷,然后发现爷爷的区间[1,3]并没有被包含在[1,2]中,所以先下放lazy(因为此时爷爷lazy为0,所以相当与没下放 ╮(╯-╰)╭ )然后爷爷就继续查询到叔叔,发现叔叔的去见被完全包含在了[1,3]中,所以返回叔叔的值4,然后从爷爷继续递归到了爸爸,发现爸爸的区间[2,3]并没有被包含在[1,2]中,所以还是下放lazy(不然查到子节点时自己私拿孩子压岁Q的事就露陷了!

(っ °Д °;)っ

于是爸爸赶紧下放lazy,于是这棵树就变成了这样:

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

然后递归左孩子,发现被包含在了[1,2]中,返回4,右孩子没被包含,返回,然后爸爸返回4,爷爷返回4+4=8,所以最后太爷爷收到了8,大功告成!(●ˇ∀ˇ●)

代码(查询)


int find(int id,int l,int r,int x,int y)//id:目前查到的节点编号  目前区间为[l,r]  目标是求出[x,y]的和
{
  if(x <= l && r <= y) return sumv[id];//[l,r]被[x,y]包含了
  push_down(id,l,r);//要查到id的子节点了,赶紧下放
  int mid = (l + r) / 2,ans = 0;
  if(x <= mid) ans += find(id * 2,l,mid,x,y);//ans+=左孩子和
  if(y > mid) ans += find(id * 2 + 1,mid + 1,r,x,y);//ans+=右孩子和
  return ans;
}

三,例题

题目1(单点更新)

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

思路

输入a数组,再创建线段树,最后每次输入时判断p是否为1,是则输出find(1,1,m,x,y);否则gexi(1,x,1,m,y)。

代码


#include <bits/stdc++.h>
using namespace std;
int tr[10000001];
int a[10000001];
void bui(int id,int l,int r)//创建线段树,id表示存储下标,区间[L,r]
{
  if(l == r)
  {
    //叶子
    tr[id] = a[l];
    return ;
  }
  int mid = (l + r) / 2;
  bui(id * 2,l,mid);
  bui(id * 2 + 1,mid + 1,r);
  tr[id] = min(tr[id * 2],tr[id * 2 + 1]);
}
//id 表示树节点编号,l r 表示这个节点所对应的区间
//x y表示查询的区间
int find(int id,int l,int r,int x,int y)
{
  //需要查询的区间[x,y]将当前区间[l,r]包含的时候
  if(x <= l && r <= y) return tr[id];
  int mid = (l + r) / 2,ans = INT_MAX;
  if(x <= mid) ans = min(ans,find(id * 2,l,mid,x,y));
  if(y > mid) ans = min(ans,find(id * 2 + 1,mid + 1,r,x,y));
  return ans;
}
void gexi(int k,int id,int l,int r,int num)
{
  if(l == r)
  {
    tr[k] = num;
    return ;
  }
  int mid = (l + r) / 2;
  if(id <= mid)
    gexi(k * 2,id,l,mid,num);
  else
    gexi(k * 2 + 1,id,mid + 1,r,num);
  tr[k] = min(tr[k * 2],tr[k * 2 + 1]);
}
signed main()
{
  int n,m;
  cin>>m>>n;
  for(int i = 1; i <= m; i++) cin>>a[i];
  bui(1,1,m);
  while(n--)
  {
    int x,y,p;
    cin>>p>>x>>y;
    if(p == 1) cout<<find(1,1,m,x,y)<<' ';
    else gexi(1,x,1,m,y);
  }
  return 0;
}

例题2(区间更新)

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

思路

套模板即可。

代码


#include <bits/stdc++.h>
#define int long long
using namespace std;
int sumv[10000001],n,m,a[10000001],lazy[10000001];
void push_up(int id)
{
  sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];
}
void push_down(int id,int l,int r)
{
  if(lazy[id])//如果id有lazy标记
  {
    int mid = (l + r) / 2;
    lazy[id * 2] += lazy[id];//将它的左孩子的lazy加上它的lazy
    lazy[id * 2 + 1] += lazy[id];//将它的右孩子的lazy加上它的lazy
    sumv[id * 2] += lazy[id] * (mid - l + 1);//左孩子的Q+它下放的Q*区间长度
    sumv[id * 2 + 1] += lazy[id] * (r - mid);
    lazy[id] = 0;//清空lazy标记
  }
}
void bui(int id,int l,int r)
{
  if(l == r)//叶子节点
  {
    sumv[id] = a[l];
    return ;
  }
  int mid = (l + r) / 2;
  bui(id * 2,l,mid);//递归创建左子树
  bui(id * 2 + 1,mid + 1,r);//递归创建右子树
  sumv[id] = sumv[id * 2] + sumv[id * 2 + 1];//左子树和+右子树和
}
void qjgx(int id,int l,int r,int x,int y,int v)//id:目前查到的节点编号  目前区间为[l,r]  目标是讲[x,y]的所有数+v
{
  if(l >= x && r <= y)//[l,r]被[x,y]包含了
  {
    lazy[id] += v;//暂时不下放Q,加进lazy标记中
    sumv[id] += v * (r - l + 1);//将Q收入囊中
    return ;
  }
  push_down(id,l,r);//要来更新下面节点了,赶紧下放Q
  int mid = (l + r) / 2;
  if(x <= mid) qjgx(id * 2,l,mid,x,y,v);//因为只有x<=mid(即[l,mid]有一部分是被[x,y]覆盖了的)才需要去更新[l,mid]
  if(y > mid) qjgx(id * 2 + 1,mid + 1,r,x,y,v);
  push_up(id);//子节点更新完之后父节点当然也要更新(上升操作)
}
int find(int id,int l,int r,int x,int y)//id:目前查到的节点编号  目前区间为[l,r]  目标是求出[x,y]的和
{
  if(x <= l && r <= y) return sumv[id];//[l,r]被[x,y]包含了
  push_down(id,l,r);//要查到id的子节点了,赶紧下放
  int mid = (l + r) / 2,ans = 0;
  if(x <= mid) ans += find(id * 2,l,mid,x,y);//ans+=左孩子和
  if(y > mid) ans += find(id * 2 + 1,mid + 1,r,x,y);//ans+=右孩子和
  return ans;
}
signed main()
{
  cin>>n>>m;
  for(int i = 1; i <= n; i++) cin>>a[i];
  bui(1,1,n);
  while(m--)
  {
    int k,x,y,p;
    cin>>p>>x>>y;
    if(p == 1)
    {
      cin>>k;
      qjgx(1,1,n,x,y,k);
    }
    else cout<<find(1,1,n,x,y)<<'\n';
  }
  return 0;
}

四,结语

怎么样?看懂了吗?看懂了的话请留个赞吖!文章来源地址https://www.toymoban.com/news/detail-446419.html

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

到了这里,关于超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT入门看这一篇就够了——超详细讲解(40000多字详细讲解,涵盖qt大量知识)

    目录 一、Qt概述 1.1 什么是Qt 1.2 Qt的发展史 1.3 Qt的优势 1.4 Qt版本 1.5 成功案例 二、创建Qt项目 2.1 使用向导创建 2.2 一个最简单的Qt应用程序 2.2.1 main函数中 2.2.2 类头文件 2.3 .pro文件 2.4 命名规范  2.5 QtCreator常用快捷键 三、Qt按钮小程序 3.1按钮的创建和父子关系 3.2 Qt窗口坐标

    2024年02月09日
    浏览(50)
  • 打开Adobe Premiere Pro提示“由于找不到msvcp110.dll,无法继续执行代码。重新安装程序可能会解决此问题”。【方法适用于几乎所有dll文件丢失时】

    打开Adobe Premiere Pro提示“由于找不到msvcp110.dll,无法继续执行代码。重新安装程序可能会解决此问题”。网上之前找了一堆解决办法,都没用,最后终于使用工具解决了,分享给大家参考。 简单来讲就是系统C:WindowsSystem32路径下的msvcp110.dll文件丢失了,找回来这个文件并且

    2024年02月05日
    浏览(141)
  • 【图论经典题目讲解】CF786B - Legacy 一道线段树优化建图的经典题目

    D e s c r i p t i o n mathrm{Description} Description 给定 1 1 1 张 n n n 个点的有向图,初始没有边,接下来有 q q q 次操作,形式如下: 1 u v w 表示从 u u u 向 v v v 连接 1 1 1 条长度为 w w w 的有向边 2 u l r w 表示从 u u u 向 i i i ( i ∈ [ l , r ] iin [l,r] i ∈ [ l , r ] )连接 1 1 1 条长度为 w w w

    2024年02月20日
    浏览(89)
  • 最通俗易懂的讲解HTTPS的加密原理【多图、易懂】

    目录 前言 HTTPS加密原理概述 HTTP 为什么不安全 安全通信的四大原则 HTTPS 通信原理 对称加密:HTTPS 的最终加密形式 非对称加密:解决单向的对称密钥的传输问题 数字证书:解决公钥传输信任问题 证书一整个被掉包怎么办? 总结 其它 HTTPS 相关问题 什么是双向认证? 什么是

    2024年02月05日
    浏览(61)
  • 线段树详解——影子宽度

    OK,今天来讲一讲线段树~~ 线段树( S e g m e n t Segment S e g m e n t    T r e e ~~Tree     T ree )是一种二叉树,用于区间查询。线段树的每个节点表示一个区间,根节点表示整个区间,子节点表示区间的一半。线段树的典型应用是解决区间查询问题,例如区间最大值、区间最小值

    2024年02月12日
    浏览(33)
  • 通俗易懂讲解CPU、GPU、FPGA的特点

      大家可以简单的将CPU理解为学识渊博的教授,什么都精通;而GPU则是一堆小学生,只会简单的算数运算。可即使教授再神通广大,也不能一秒钟内计算出500次加减法。因此,对简单重复的计算来说,单单一个教授敌不过数量众多的小学生。在进行简单的算数运算这件事上

    2024年02月11日
    浏览(46)
  • C语言 - 最简单,最易懂的指针、引用讲解

    输出结果如下: 先看这一行 都知道 是取址符是吧,好,h 是取h结构体的地址,结果没问题,参照上图。 接着,hp,hp是一个指针,指向了h所在的地址(hp = h),注意:hp是取hp变量的地址,而不是h的地址,所以打印出来的是 6290920。(printf %d是打印数字,这里输出的是10进制

    2024年02月02日
    浏览(44)
  • 易懂的方式讲解ARM中断原理以及中断嵌套方法

    ARM有七种模式,我们这里只讨论SVC、IRQ和FIQ模式。  我们可以假设ARM核心有两根中断引脚(实际上是看不见的),一根叫 irq pin, 一根叫fiq pin。在ARM的cpsr中,有一个I位和一个F位,分别用来禁止IRQ和FIQ。  先不说中断控制器,只说ARM核心。正常情况下,ARM核都只是机械地随着

    2024年01月21日
    浏览(37)
  • 用通俗易懂的方式讲解:CatBoost 算法原理及案例

    前面已讲了7节,为方便大家学习,我总结在一起,无论是日常实践还是面试使用,都非常方便,喜欢记得收藏 用通俗易懂的方式讲解:逻辑回归模型及案例(Python 代码) 用通俗易懂的方式讲解:决策树模型及案例(Python 代码) 用通俗易懂的方式讲解: 随机森林及案例(

    2024年04月12日
    浏览(44)
  • C++实现单链表【每一步详细深入讲解,代码清晰、简单、易懂】

    0、overview 链表元素由数据和指针构成,因此链表的节点可以由一个包含这两种元素的结构体代表: 链表包含插入、删除操作,而插入、删除又必须先查找元素是否存在,因此查找方法也必不可少。 1、插入操作 例如:我们需要在伪头节点(不包含数据)和含有1的节点之间插

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包