线段树详解

线段树详解 (原理,实现与应用) 线段树详解 By 岩之痕 一:综述 线段树是一种可以快速进行区间修改和区间查询的数据结构。点修改,区间修改和区间查询的复杂度都是O(log2(n)) 并且,线段树可以维护很多种类的信息。说到线段树就不得不提一下树状数组,树状数组维护的信息必须满足区间减法,因为树状数组只是维护1到X的信息,通过相减来得到区间信息,代码简单而且速度快,占用空间又少于线段树,所以一般情况下可以用树状数组的地方就 阅读详情

致歉:嗯... 由于数学竞赛原因,本人很久没有更新了,望洛谷的粉丝朋友们多多谅解。这一期就不做漫画了,我们出个博文讲讲线段树。感谢粉丝们对我长期以往的支持与鼓励,谢谢!

OK,我们言归正传,来讲一讲线段树吧!

首先,看一道例题,洛谷的 P3372,【线段树1】。主要看一下精华部分。

如题,已知一个数列,你需要维护下面两种操作:

  1.  将某区间每一个数加上 k 。
  2.  求出某区间每一个数的和 。

题目要求我们维护这两种操作。我们首先可以用暴力的思路解决。

暴力解法:

      解决操作1,很简单,开一个数组,对于给出的区间,for 一下,直接加上 k 就完事了。              解决操作2,更简单,要么暴力累加,要么来个前缀和,稍微优化一下。

所以,用暴力解决很简单,下面看一下代码。

//P3372 【模板】线段树1  暴力解法
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m;
int number[MAXN];

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0); //以上两行是关闭同步,让速度更快,大家要是不知道,不用没关系

	cin >> n >> m;
	for (int i = 1;i <= n; ++i) 
		cin >> number[i];
	for (int i = 1;i <= m; ++i) {
		int opt; cin >> opt; //这里的 opt 指的是操作前的提示符 (1, 2)
		if (opt == 1) {
			int x, y, k; cin >> x >> y >> k;
			for (int j = x;j <= y; ++j) {
				number[j] += k; //实现1操作
			}
		}
		else if (opt == 2) {
			int x, y; cin >> x >> y;
			int sum = 0;
			for (int j = x;j <= y; ++j) {
				sum += number[j]; //实现2操作
			}
			cout << sum << '\n'; //使用关闭同步,就不能用 endl 了
		}
	}
	return 0;
}

洛谷测评机:您老真是勇气可嘉 (回去挨打吧你)

TLE 的原因就不用说了。 O(n^2) 的时间复杂度,配上 1e5 的数据,100% 超时。 

重点来了,线段树的基本想法:

        我们刚刚已经公开处刑了这位用暴力求解的孩子,没错,爆时间了。那有没有一种方法,能够在短时间内维护这两种操作?有,线段树!

        线段树本身不难理解。正所谓 “线段树”,它是一颗树。而树上的节点呢,都是一段区间。就以这道题为例,构建一个“线段树”。我们假设原数组num有八个格,数值分别为[5, 9, 4, 1, 8, 8, 8, 8] 。 观察上面的树。图中绿色的中括号,是它的节点所代表的区间。图中节点上的数字,就是它所代表的的区间的和。这么说我怕有些人会看不懂,那么举个例子。看到图中左上角的节点,它节点上写的数字是19,这个19 表达的就是从数组 num[1]  到  num[4] 的和 (5 + 9 + 4 + 1 = 19)。

线段树的应用:

我们现在清楚了线段树的每个部分都在表达什么,进一步,我们去探究线段树如何去应用在这道题目上。

首先看第 2 种操作,注意是第二种 :比如说我们想知道 [1, 5] 这个区间的和,那我们无需用 for 循环一遍一遍地做,直接把代表区间 [1, 4] 和 [5] 的节点加起来,结果就是 19 + 8 = 27 。这样,就可以把时间复杂度直接减到 O (log~n),岂不美哉!

接着看第 1 种操作:看到上图。比如,我们想把 [1, 4] 这个区间的数值都加上 1,我们先把图中的 [1], [2], [3], [4] 都加上1,紧接着,[1], [2], [3], [4] 再分别把自己的父节点加上1:[1, 2] 加上2 ;    [3 ,4] 加上2 ;然后,[1, 4] 加上4,[1, 8] 加上4。这就完整地完成了一次 1 操作。大家如果不太理解,可以联系线段树的基本想法部分手绘理解一下。

重头戏——线段树的实现:


我们首先看到操作 2 的实现。

         注意是操作 2!我们要实现的是一个区间求和操作。但是,我们在线段树里,就可以理解为一个“查询”操作。为啥呢?还是上文那个例子,我们要求区间 [1, 5] 的和。就要先知道 [1, 5] 是由 [1, 4] 和 [5] 组合而成的,才能把两个区间加起来得到答案。那,怎么知道 [1, 5] 是谁和谁组合而成的呢?请看下图。

 图片中的字有些小,请各位放大使用。上图所示,便是操作 2 的流程。我们注意到,图中有两种行走方式:向左下走和向右下走。那么,我们为了方便说明,就定义往左下走,就是去往 left_son ,往右下走,就是去往 right_son 。我们宏定义一下:

#define mid ( (l + r) / 2 )
#define left_son u * 2, l, mid
#define right_son u * 2 + 1, mid + 1, r

有些同学可能会抱怨:唉,又开始看不懂了。没关系,这段代码现在看不懂没事,待会放到代码里,你就知道起什么作用了。 


我们再看到操作 1 的实现。

        操作 1 放到后面讲可能好一点,并不是它难。我们实现的是修改操作。根据上文“线段树的应用”,我们得知,操作 1 其实就像条链子一样,一直不断往上加。如果不太理解,我们看图。

        同上文,假设我们要把区间 [1, 4] 加上 1。

字比较小,咱还是放大食用一下。


好,我们现在就到了代码实现的部分了。

我们先实现两个函数,叫做 push_down 和 push_up 。

push_down:这个函数可以理解为是向左儿子和右儿子去走,并且在走完的地方打上标记。

push_up:这个函数可以理解为向上回溯,那么有些代码和思路中是不需要他的。但是我们这个思路就需要。

我们先把它们实现了再说!

/*                            push_down 的模板代码                        */
void push_down (int u, int l, int r) { //u是本节点的下标。l和r分别是查询的左区间和右区间
    tree[u] += vis[u] * (r - l + 1);
    vis[u * 2] += vis[u]; //向左儿子走
    vis[u * 2 + 1] += vis[u]; //向右儿子走
    vis[u] = 0; //清空标记
}
/*                            push_up 的模板代码                        */
void push_up (int u, int l, int r) {
    push_down (u, l, r);
    push_down (left_son); //去往左儿子
    push_down (right_son); //去往右儿子
    tree[u] = tree[u * 2] + tree[u * 2 + 1]; //一步步往上更新加和
}

我们看到代码,应该不难理解。tree 是构建树的数组这些都好理解。但是我相信大家一定对这个叫做 vis 的数组抱有疑问。下面,我们就来讲讲 vis 数组。

       vis 数组的作用:我们的 vis 数组是一个懒标记  (Lazy~ Tag) 数组,也有的地方翻译成“延迟标记”(听起来高端,实际上啥也不是)。好了,回顾一下整个过程:区间更新时,我们递归查找目标区间的子区间,过程中不断维护当前节点的区间和,每找到一个目标区间的子区间(有可能只有1个点)被完全覆盖到时停止往下递归。最妙的地方在于我们每次不必要把懒标记下传到底,只需传到管理目标区间的子区间的节点就行,下次再有更新的时候,我们再随着更新递归传递标记就好了。这样,时间复杂度会大大提升有了上文这些准备,主要的代码来了!

对于操作 2,区间查询。 实现一个 query查找函数。我们需要几个参数。分别是 u,~ l,~ r,~ L,~ R ,分别表示本节点的下标、当前节点的左区间、当前节点的右区间、查询的左区间、查询的右区间。

query Code

long long query (int u, int l, int r, int L, int R) { //上文所提到的参数
	push_down (u, l, r); //向下查询
	if (L <= l and r <= R) { //如果本区间完全属于要查询的区间
		return tree[u]; //直接返回答案
	}
	long long answer = 0; //定义输出答案
	if (L <= mid) { //判断左区间是否合法
		answer += query (left_son, L, R); //去右儿子
	}
	if (R > mid) { //判断右区间是否合法
		answer += query (right_son, L, R); //去左儿子 
	}
	return answer; //返回最终的答案
}

以上的代码应该很好理解,我们主要来看下面的 update 函数。

update 函数主要实现的就是加一个数字 k。我们需要的参数有 u,~l,~r,~L,~,R~,~value ,其中的 value 就是输入的 k 。其他的上文说过不过多解释,详见代码注释。

void update (int u, int l, int r, int L, int R, int value) { //上文所述的一些系数
    push_down (u, l, r); //往下走
    if (L <= l and r <= R) { //跟上个函数一样,先判断是否全部属于
        vis[u] += value; //更新懒标记
        return ;
    }
    if (L <= mid) {
        update (left_son, L, R, value);
    }
    if (R > mid) {
        update (right_son, L, R, value);
    } //同上
    push_up (u, l, r); //可以理解为回溯
    return ;
}

我们实现了这两个函数之后,就把他们融入我们的大程序吧!

我觉得我的代码还算好懂吧...

#include <iostream>
#include <cstdio>
#define MAXN 100010
#define mid ((l + r) / 2)
#define left_son u * 2, l, mid //宏定义我们的左儿子和右儿子
#define right_son u * 2 + 1, mid + 1, r
using namespace std;
int n, m;
long long tree[MAXN * 8], vis[MAXN * 8];


void push_down (int u, int l, int r) { //u是本节点的下标。l和r分别是查询的左区间和右区间
    tree[u] += vis[u] * (r - l + 1);
    vis[u * 2] += vis[u]; //向左儿子走
    vis[u * 2 + 1] += vis[u]; //向右儿子走
    vis[u] = 0; //清空标记
}

void push_up (int u, int l, int r) {
    push_down (u, l, r);
    push_down (left_son); //去往左儿子
    push_down (right_son); //去往右儿子
    tree[u] = tree[u * 2] + tree[u * 2 + 1]; //一步步往上更新加和
}

long long query (int u, int l, int r, int L, int R) { //上文所提到的参数
	push_down (u, l, r); //向下查询
	if (L <= l and r <= R) { //如果本区间完全属于要查询的区间
		return tree[u]; //直接返回答案
	}
	long long answer = 0; //定义输出答案
	if (L <= mid) { //判断左区间是否合法
		answer += query (left_son, L, R); //去右儿子
	}
	if (R > mid) { //判断右区间是否合法
		answer += query (right_son, L, R); //去左儿子 
	}
	return answer; //返回最终的答案
}

void update (int u, int l, int r, int L, int R, int vlaue) { //上文所述的一些系数
    push_down (u, l, r); //往下走
    if (L <= l and r <= R) { //跟上个函数一样,先判断是否全部属于
        vis[u] += value; //更新懒标记
        return ;
    }
    if (L <= mid) {
        update (left_son, L, R, value);
    }
    if (R > mid) {
        update (right_son, L, R, value);
    } //同上
    push_up (u, l, r); //可以理解为回溯
    return ;
}

int main () {
	cin >> n >> m;
	for (int i = 1;i <= n; ++i) {
		long long number;
		cin >> number;
		update (1, 1, n, i, i, number); //最初输入数据的时候,也相当于在更新。我们就用更新函数建一下树。
	}
	for (int i = 1;i <= m; ++i) {
		int a; cin >> a;
		if (a == 1) {
			long long x, y, k;
			cin >> x >> y >> k;
			update (1, 1, n ,x, y, k); //对于操作1,调用update。
		}
		else {
			int x, y;
			cin >> x >> y;
			cout << query (1, 1, n, x, y) << endl; //对于操作2,调用query,并输出。
		}
	}
	return 0;
}

贴一下题目【模板】线段树1https://www.luogu.com.cn/problem/P3372嗯...这次讲解差不多就到这了。goodbye~

大家对我文章的意见可以直接在下方留言,或者在洛谷的帖子上说。

我还发起一个投票:下期是继续讲线段树的深入还是画漫画?大家可以投个票哈~

感谢观看~

线段树--概念+模板+入门题 引子 子问题–1 给出n个数,m次问询,每次问询给出一个范围l、r,求区间l–r的总和 很容易想到用前缀和可以解决 O(n) 子问题–2 给出n个数,m次修改,每次给出一个范围l、r和一个值k,将区间l—r的数全部+k,m次修改后,再问询1次求区间l–r的总和 也可以想到这用差分就能解决 O(n) 最后将这两个问题结合起来,给出n个数,m次操作,操作有两种一个是将区间l–r的值+k,一个是询问区间l–r的总和。 这个问题与之前不同的地方是,之前想要求一个范围只需处理一次数据算前缀和,然后数据不变,可以一 阅读详情

相关推荐

线段树详解(包含加法线段树、乘法线段树及区间根号线段树,简单易懂)

线段树及简单应用。

qi_programmer的博客 2582

【学习笔记】详解线段树(浅显易懂,匠心之作,图文并茂)

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

weq2011的博客 3万+

线段树合并与线段树分裂

线段树合并是指建立一棵新的线段树,这棵线段树的每个节点都是两棵原线段树对应节点合并后的结果。线段树分裂实质上是线段树合并的逆过程。线段树分裂只适用于有序的序列,无序的序列是没有意义的,常用在动态开点的权值线段树。线段树分裂与线段树合并密不可分,一般来说没有只分裂不合并的题。的救灾粮,问所有操作结束后每个节点类型最多的救灾粮是那种。一棵树,点有点权,问每个节点的子树内有多少节点点权比它大。从这棵树的根节点开始递归分裂,当节点不存在时,递归结束。显然,对于两颗满的线段树,合并操作的复杂度是。

conti123的博客 934

算法数据结构——线段树(Segment Tree)精讲及python实现

线段树(Segment Tree):一种基于分治思想的二叉树,用于在区间上进行信息统计。它的每一个节点都对应一个区间leftright通常是整数。每一个叶子节点表示了一个单位区间(长度为1),叶子节点对应区间上。每一个非叶子节点的左子节点表示的区间都为,右子节点表示的的区间都为。线段树是一棵平衡二叉树,树上的每个节点维护一个区间。根节点维护的是整个区间,每个节点维护的是父亲节点的区间二等分之后的其中一个子区间。当有n。

白话机器学习 5170

YOLOv11 改进策略 | HWD:引入 Haar 小波变换,减少信息丢失

在卷积神经网络(CNN)中,下采样(Downsampling)是降低特征图分辨率、扩大感受野的关键操作,通常通过最大池化(MaxPool)或步长为 2 的卷积(Strided Convolution)实现。然而,这些方法在降低分辨率的同时,往往会丢失图像中的高频细节信息(如边缘、纹理)和精确的空间位置信息,这可能对后续特征提取和目标检测精度产生不利影响,尤其是对于小目标和需要精细定位的任务。

走向CTO的路上... 1788

Dify如何实现自主学习

摘要:Dify通过构建感知-决策-执行-反馈的闭环实现"自主学习",本质是打造能自动获取信息、更新知识库并调整策略的Agent工作流。核心包括:1)建立知识库作为记忆体;2)搭建感知与执行工具获取实时信息;3)通过工作流编排决策"大脑",包含LLM决策节点、行动执行节点和反馈反思节点。典型应用如根据用户反馈优化回答风格,通过存储反思日志到知识库实现持续优化。这种机制使智能体能基于新数据和经验不断自我改进。

专注于技术研发行业技术主要有AI人工智能视觉识别、物联网技术、电商平台、app原生技术、微信小程序、鸿蒙语言开发、办公企业oa、ERP等,致力于做东半球最优秀的程序员 725

数据结构 线段树--权值线段树 详解

一、权值线段树 简介 1.线段树 线段树是一种用于维护区间信息的高效数据结构,可以在 O(log⁡N)O(\log N)O(logN) 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。 线段树维护的信息必须满足可加性,即能以可以接受的速度合并信息和修改信息,包括在使用Lazy标记时,标记也要满足可加性 具体有关线段树的的讲解请参考博客:线段树 详解与模板

HeartFireY的博客 1万+

Shopee动态参数x-sap-Ri与x-sap-Sec逆向解析实战

现代电商前端反爬普遍采用动态参数校验机制,其核心是将设备指纹、DOM状态与时间上下文耦合生成不可复用的请求凭证。x-sap-Ri本质是渲染上下文唯一标识,依赖真实浏览器环境中的DOM树结构、Canvas像素指纹及毫秒级时间扰动;x-sap-Sec则是基于该标识与服务端同步密钥生成的HMAC-SHA256签名,具备强时效性与密钥轮换特性。这类机制显著提升了自动化采集门槛,广泛应用于Shopee商品详情页等高价值数据接口。本文聚焦于从Chrome DevTools调试出发,系统还原参数生成逻辑,覆盖DOM一致性

weixin_30603633的博客 894

详解线段树

但是在做题的时候还是会对模板进行修改,修改的点主要在区间val的意义上,我们这里模板里面val代表的是区间和,但后面题目里面可能是 区间最大值 、区间最小值…,但是万变不离其宗,线段树的结构是不会变的。

潜心钻研技术 1353

Vcenter安全加固-防火墙-只允许特定的IP地址访问Vcenter

3、此时除了被允许的IP地址可以访问之外,其余地址均被防火墙阻挡。2、再进行0.0.0.0/0匹配所有其他IP地址进行拒绝访问。1、只需要关注接受和拒绝即可。2、其余选择不是这个场景使用的。1.只允许特定的IP地址访问Vcenter。1、登录Vcenter管理界面。2、点击防火墙-添加。

博然的宝藏库 7279

robomimic实验复现全流程:从数据集下载到训练视频生成

本文详细介绍了机器人模仿学习项目RoboMimic的完整实验复现流程。内容涵盖从使用Conda创建Python 3.8隔离环境、安装RoboSuite仿真器和MuJoCo物理引擎,到下载并探索数据集、配置与启动模型训练,最后进行模型评估和生成策略执行视频。该指南旨在帮助研究者和开发者高效搭建实战环境,规避常见问题,快速验证算法或应用于实际场景。

weixin_29089057的博客 517

二维线段树详解

如题

INF_512的博客 2098

华为od 面试八股文_Python_02_含答案

华为od 面试八股文_Python_02_含答案

MISAYAONE的博客 4532

线段树 详解

线段树

wuyixiang___的博客 1941

利用ADS建立MIPI D-PHY链路仿真流程

由于MIPI D-PHY的速率并不算高,因此,PCB设计难度通常不大,主要做好差分线的等长、阻抗的连续性、端口处的阻抗优化以及控制好走线的长度,拿到满意的结果还是较为轻松的,最后,建立流程化的仿真工程文件,可以保存为模板,方便日后的设计复用,非常方便。

一只豌豆象的博客 3571

AI大模型探索之路-实战篇4:深入DB-GPT数据应用开发框架调研

在当今的人工智能时代,大模型技术的迅猛发展为各行各业带来了前所未有的变革。这些大模型,以其强大的语言理解和生成能力,正在逐步成为智能化应用的核心。然而,如何高效地利用这些大模型,构建出满足各种需求的应用,仍然是一个具有挑战性的问题。DB-GPT,作为一个开源的AI原生数据应用开发框架,应运而生,旨在简化大模型应用的开发过程,让构建智能化应用变得触手可及。本文将深入介绍DB-GPT的核心功能、关键特性,并通过实战操作,展示如何利用DB-GPT进行数据应用开发。DB-GPT是一个开源的AI原生数据应用开发框架。

寻道AI,探索AI无限可能! 1万+

详解动态开点线段树

本文介绍了动态开点线段树及其在解决CF915E问题中的应用。由于数据范围过大(n≤1e9),传统线段树无法直接使用。动态开点线段树的核心思想是只创建操作中实际需要的节点,而非预先构建完整结构。文章通过图解展示了动态开点的过程,并提供了关键代码实现,包括修改操作和pushdown处理。最后给出了完整代码,并指出动态开点技术在可持久化线段树中的重要性。这种方法有效解决了大区间范围下的线段树实现问题。

Benny_250的博客 936

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

线段树及线段树模板

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为Olog⁡NO(\log N)OlogN。而未优化的空间复杂度为2N2N2N,实际应用时一般还要开空间为4N4N4N的数组以免越界,因此有时需要离散化让空间压缩。线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

AllenAC的博客 1234

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

线段树入门详解

目录 线段树入门详解 本文适用人群 线段树大致思路 本人代码习惯 单点修改 单点查询 区间查询 区间加减 Last 线段树入门详解 本文适用人群 不算特别入门啦...

dieloupi0136的博客 321

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: 洛谷题目全解(P1000 超级玛丽游戏)
下一篇: 数据结构——vector 清晰讲解
VINTAGE_vector
博客等级 码龄5年 213粉丝 8原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值