全连接层的作用_python构建计算图2——全连接层

(好久不更~)前文中,参照tensorflow的方式实现了简单的自动求导。接下来要在自动求导的基底(模板)上搭建简单的bp神经网络。

计算图

前文曾多次提到计算图,关于什么是计算图,有很多种说法。既然它被称为图,便具有图的基本元素:点和线。如下图:

09d62bc859089b90b54753c97a38bacc.png

点:节点,用来储存变量。比如输入X,隐含层h,输出y

线(箭头):操作(算符),用来确定两个节点之间的联系,或者说由前一个节点经过这个操作后可以得到后面的节点。

可以利用上一篇构造复合函数的方式来理解它。构造函数f(x),需要自变量x和一个映射f,这里的x是节点,映射f是操作。如果另y=f(x),那么y就是新的节点,映射f的箭头是从x指向y。多个不同的映射可以组成一个大网络,储存更复杂的信息。

计算图的好处在于,它是微分链式法则的直观体现,每个节点的梯度都可以看做上一个节点的梯度与本层导数的乘积。因此,计算图网络结构建立的同时,每个节点的梯度也是确定了的。

全连接层

说到全连接层,就不得不提一下BP神经网络。神经网络是模方大脑神经元的连接方式,通过建立神经元之间的相互联系来对某个问题进行建模的方法。BP神经网络是在众多神经网络中一枝独秀,利用梯度下降方法,可以最快最准的接近局部最优值(缺点当然是容易陷入局部最优,因此也出现了很多改进算法)。

从最简单的线性回归说起。我们有两组数据,自变量:x,目标:t。对目标t的估计值为:

2bface898803b306533a3d28abe92414.png

估计值和目标之间的均方误差为:

e0c77599dbbdcf659e4195a7011b23c5.png

可以做出loss关于a0和a1的三维曲面:

040b46debe9f664e6e8aec8a85b7afde.png

可以看到他是一个二次函数形式,必然存在最小值。我们对a0和a1分别求偏导:

3b1d40b329540f5024257844c5ac5e8b.png

7e629474d61280d09c643870fc272f38.png

最小二乘法是利用这两个偏导数等于0求出取到最值时的a0和a1:

72fdb2fd909dd91641ab53c0fe2cb602.png

而梯度下降法则是将a0和a1按照上面算出的导数,以某个速率向最值点靠近(以他们的导数乘某个常数为速率,以梯度的负数为方向,做爬坡运动)

对于线性回归问题来说,loss是个抛物线,必然存在最值点:

ecdd32a9559c0e9c86a906a212067935.png

但是对于更复杂的问题来说,就不一定了,loss不一定是抛物线,可能存在多个极值点,这样的话最小二乘法便不再好用,但是梯度下降却可以尽最大可能搜索最优值(虽然不容易跳出局部最优,但还是比最小二乘法要好吧)

但是随着问题复杂度的提升,自变量和因变量之间也不再是简单的线性关系,这时就要加入一个激活函数,但是光加入激活函数只能表示一些简单的非线性模型,对于更加复杂的非线性模型也无能为力。

所以现在的问题是如何利用简单的方程表示出复杂的方程。这一点在高等数学中其实已经学到了。对于一个复杂的函数,我们总可以把他展开成级数的形式,而且我们还可以证明,展开的级数就是泰勒级数,这个展开也叫做泰勒展开。

我们可以利用最简单的幂函数的叠加来趋近一个极其复杂的函数。那在这个问题上,也可以利用无数个简单的非线性函数的叠加来拟合一个极其复杂的非线性函数,所以就有了下图:

2a0a60140ca4909b3b145063c6036a1a.png

把n个线性关系叠加起来再通过激活函数计算得到最终的估计值:

ee430cd59bc9ed0dd90899405a6de1f4.png

ad9256017f707ef068f0ea7a317b3dc7.png

损失值loss(均方差)为:

300a33e0ac9e5d2c8e64a130fca8e89f.png

要继续利用梯度下降法,就需要计算loss关于每个w的导数:

698c2ae750b2252751c88b94bbb5dcfa.png

这样就建立了梯度下降与链式法则之间联系,和上一文《简单实现自动求导》一模一样。

这里可以体现出计算图的好处。我们不需要再手动计算这些复杂的梯度值到底是多少,在计算图建立的同时,它就已经帮我们算好了。我们只需要给他一个学习的指令,他就可以按照我们要求的训练方式学习。

全连接层,顾名思义,重在“全连接”,他将所有的输入都和输出相连,如下图的两层神经网络,一个输入,一个隐含层,一个输出。

在黑框中可以看到,所有的输入X都和所有隐含层的节点相连,所有隐含层的节点都和输出y相连。

92b45d13025568b37708b0e30a6afe80.png

或许会问,难道还有不全连接的神经网络吗。当然有,先不说一些复杂的结果,最基本的卷积神经网络CNN就不是全连接的,它利用卷积核扫描图像,而卷积核一般都是比图像小的多的方形如3×3,5×5。

两层的神经网络理论上可以拟合任意的非线性函数。在梯度计算方面与之前稍有不同:先看第一层,第j个输出为:

0ff8d1c492b54561bef8435143481339.png

要计算w的该变量,就需要计算前面那个链式表达式,它其中的一项:

b4c96b8073f774edd8d74522aa2d2bc7.png

所以:

82d26b3c99d531580489362d496f2565.png

对于很多层的网络:

853e916923f144f680f2b94f384653b3.png

我们给定一个变量δ,它实际上是每一层神经网络的梯度,下式为输出层的梯度:

61e45049d2496fa9e8b17877b0c2b396.png

那么权重改变量:

e5b21f648c0bfd41525ba95746ea4f74.png

而上一层的梯度:

b9ee8b0dd45eb1e85f15b1b30115884b.png

权重改变量:

57160f4bd3415283f0bda8f1872bfee3.png

因此,在网络训练过程中,先计算每一层的梯度和权重改变量,算完之后再对每一层的权重梯度下降。值得注意的是:不可以每计算一层的权重改变量,就对该层的权重做出改变。这样会影响后面的计算。

写到这儿,需要的理论知识已经有了。接下来就是如何搭建静态图:

上一文有提到,我搭建的计算图中只有两个基本变量:Variable和placeholder。

placeholder作为需要传入数据的变量,Variable则作为需要训练的变量(这里用不到不需要训练的变量,不然应该再给一个Constant更完整,我这里其实简化了很多操作^_^)

与之前相同的是,Variable包括value和grad两个变量。

不同的是,Variable包含了last,next,root和target四个指针(可以这么叫吧)。last指向前一个节点,next指向后一个节点,root指向输入的placeholder(就是起始节点),target指向目标的placeholder(要计算loss,就必须要计算输出和目标之间的差距),一条路径上的每个节点的root和target都相同(这是为了方便对每个节点求值的时候都能从placeholder开始)。

placeholder在图中只起到占位的作用,它用来确定计算内存与复杂度,需要在后续求值的时候传入数据。每个节点都有root指针,可以确保在求该节点值的时候,从它的root开始,先传入数据,然后利用next指针指向下一个节点,计算下一个节点的值和导数。

值得一提的是,这里我没有使用一个全局变量来储存整个图结构,而是用上述的四个指针将整个计算图建立起来。类似于{root,next1(last1),next2(last2)。。。target}。

如果不使用root指针,还有两个方法:

1.储存整个网络的图结构,这也是一般计算图的方案,这样就可以从图的起始节点开始算起。

2.要求一个节点的值,就要先知道上一个节点的值,然后带入上一个节点的激活函数才能得到这个节点的值。同理要知道前一个节点的值,就要求上上个节点的值,以此类推。而当上上一个节点是placeholder时,上上个节点值就是传入的数据,然后再计算上个节点的值。这不正是递归算法嘛,先往回走,走到初值时,再往前走。那用一个root指针岂不是取代了往回走的过程,我直接告诉它该从哪里开始往前走即可。

下面放入代码:

先说明一下整个代码的结构:

mytensor文件夹中包含五个py文件,__init__用于从tensor文件夹外部调用内部的文件。mytensor(这里不是指文件夹,而是mytensor文件夹内的py文件)用来定义基类Varibale,placeholder,一些基本函数,还有不同的Loss。nn用于定义不同的神经网络。train用于定义不同的训练方式。cnn_func包含卷积中的一些操作(这里不会提到)。

49b7696ecec24a7242b6069a2ae31c52.png

代码文件mytensor.py

# -*- coding: utf-8 -*-
import numpy as np
#Variable基类
class Variable:def __init__(self, value=None):self.value = valueself.grad = Noneself.next = Noneself.last = Noneself.root = None self.target = Noneself.eval_func = Lineif isinstance(value, np.ndarray):self.size = value.shapeelse:self.size = None      def __add__(self, other):res = Variable()res.root = self.rootself.next, other.next = res, resres.last = selfres.func = lambda x: x + other.valueres.func_grad = lambda x: 1return resdef func(self, X):return 1def func_grad(self, X):return 1def run(self, feed_dict, need_grad=False):#喂入数据root = self.root#找到rootroot.value = feed_dict[root]#给root喂入数据target = self.target#找到targetif target is not None:target.value = feed_dict[target]#给target喂入数据#求值过程while root.next is not self.next:   root.next.value = root.next.func(root.value)if need_grad:#如果需要求导root.next.grad = root.grad * root.next.func_grad(root.value)root = root.nextreturn root.value

__add__函数用来定义两个Variable的相加算法。这里Variable多出了eval_func变量,虽然这里用不到,但后续有类继承它时才会用到。

run方法便是在求该节点值得时候会用到,与之前所说相同,先找到节点的root,然后从root开始一步一步往前传,如果需要自动求导的话,need_grad传入True即可。

定义完基类,接下来就是继承基类的子类了,首先是placeholder:

###############占位#####################
class placeholder(Variable):def __init__(self, size):super().__init__(self)self.size = sizeself.root = selfself.grad = 1

然后定义一些全连接层中可能用到的激活函数:

class relu(Variable):def __init__(self, X):super().__init__()X.next = selfself.last = Xself.root = X.rootdef func(self, X):return np.maximum(0, X)def func_grad(self, X):res = np.zeros(X.shape)res[X >= 0] = 1return resclass Line(Variable):def __init__(self, X):super().__init__(self)self.last = Xself.root = X.rootdef func(self, X):return Xdef func_grad(self, X):return np.ones(X.shape)class softmax(Variable):def __init__(self, X):super().__init__(self)X.next = selfself.last = Xself.root = X.rootdef func(self, X):return np.exp(X) / np.sum(np.exp(X), axis = 1).reshape(X.shape[0], 1)def func_grad(self, X):return np.ones(X.shape)      class sigmoid(Variable):def __init__(self, X):super().__init__(self)X.next = selfself.last = Xself.root = X.rootdef func(self, X):return 1 / (1 + np.exp(-X))def func_grad(self, X):return self.func(X) * (1 - self.func(X))  
class square(Variable):def __init__(self, X):super().__init__(self)X.next = selfself.last = Xself.root = X.rootdef func(self, X):return np.square(X)def func_grad(self, X):return 2 * X

写法与上一文自动求导中定义初等函数的方法完全一致(多了一个next指针)。

然后定义损失函数:

class MeanSquareLoss(Variable):def __init__(self, yhat, y):super().__init__(self)self.target = yself.last = yhatself.root = yhat.rootyhat.next = selfdef func(self, yhat):return np.mean(np.square(yhat - self.target.value)) / 2def func_grad(self, yhat, grad):return (self.target.value - yhat) * gradclass SoftmaxCrossEntropy(Variable):def __init__(self, yhat, y):super().__init__(self)self.target = yself.last = yhatself.root = yhat.rootyhat.next = selfdef func(self, yhat):return np.mean(-np.log(yhat) * self.target.value)def func_grad(self, yhat, grad):     return (self.target.value - yhat)

这里不定义损失函数也是可以的。但是还需要用定义初等函数的方法写一下mean函数(square函数我倒是写了)。然后在训练的时候,可以把loss = MeanSquareLoss(yhat,y)写为loss = mean(square(yhat - y))

然后是Session。其实我这里写Session只是为了形式上好看点,失去了tensorflow中Session的意义。。

###############Session####################
class Session:def run(self, operator, feed_dict, need_grad = False):return operator.run(feed_dict, need_grad)

上述代码全部包含在mytensor.py中。

在nn.py文件中,就开始构建真正的全连接层了:

# -*- coding: utf-8 -*-
#导入一些要用到的函数
from mytensor.mytensor import Variable
import mytensor.mytensor as mt
import numpy as np
#全连接层
class FullConnection(Variable):def __init__(self, X, W, b=None, eval_func=None, need_trans=False):super().__init__(self)X.next = selfself.last = Xself.root = X.rootself.W = Wif b == None:self.b = Variable(np.zeros(W.size[1]))else:self.b = bself.eval_func = eval_funcself.need_trans = need_transdef func(self, X):if self.need_trans:N = X.shape[0]D = np.prod(X.shape[1:])X = np.reshape(X, (N, D))h = X.dot(self.W.value) + self.b.valueif self.eval_func is None:self.eval_func = mt.Lineh = self.eval_func(self.W).func(h)self.value = hreturn hdef func_grad(self, dout, first=False):if first:grad = self.eval_func(self.W).func_grad(self.value)return gradelse:  dw = self.last.value.T.dot(dout)db = np.sum(dout, axis = 0)grad = self.last.eval_func(self.W).func_grad(self.last.value)dout = np.reshape(dout.dot(self.W.value.T), self.last.value.shape) * grad          return dout, dw, db

可以看到全连接层的构造和之前的基本函数大的框架是一致的。构造函数中要有父类的构造函数,然后重写func和func_grad。

不同之处在于,全连接层的变量更多,有权重W,偏置b,激活函数eval_func。need_trans是针对卷积操作时判断是否需要把输入的矩阵转化为一个长链的布尔值。

func函数用来计算节点的值,就是基本的f(Xw+b)。

而func_grad输入上一层的梯度值,计算本层的梯度值以及权重和偏置的改变量,并返回。

不管是全连接层还是CNN,RNN。网络构造都是这个模式。构造函数中储存所有的变量。func中是前传操作,func_grad中利用上一层的梯度,计算本层的权重,偏置该变量和本层的梯度。

这样便可以将不同的网络结构统一起来,让后续工作简单化。

现在可以说是万事俱备只欠东风了。该定义的都定义了,该搭建的也都搭建好了,我们已经可以搭建出任意层数的神经网络,并且定义它的loss值。可以认为:前传过程已经没有任何问题了。但是现在需要个一个东西让他们跑起来——训练。

train.py中只定义了GradientDecent训练方式:

# -*- coding: utf-8 -*-
#训练方式
from mytensor.mytensor import Variable
#梯度下降法
class GradientDescentOptimizer(Variable):def __init__(self, alpha, loss):super().__init__()self.alpha = alphaself.loss = lossdef run(self, feed_dict, end=False):now = self.lossnow.run(feed_dict)dnow = now.last       now.grad = [now.func_grad(dnow.value, dnow.func_grad(None, True))]while dnow is not now.root:dnow.grad = dnow.func_grad(now.grad[0])now, dnow = dnow, dnow.last            root = self.loss.rootwhile root.next is not self.loss:try:root.next.W.value += self.alpha * root.next.grad[1]root.next.b.value += self.alpha * root.next.grad[2]except:passroot = root.next

它和别的类不同,没有func和func_grad。但它却重写了run方法。毕竟它是优化器,与之前的节点都不同(其实这里不需要继承父类)。

这里首先要计算完每一层的梯度,每一层权重和偏置的改变量,然后才可以对权重和偏置做出改变,否则会影响每一层梯度的计算。本质上这些计算得是并行的,但是由于本层的梯度必须要利用前一层的梯度,拥有串行的性质。这就导致了我们必须得写两个循环。

使用try-except是因为,卷积中池化层没有权重和偏置,为了程序的统一才用这个方法。

这样所有的方法都已经写好,如果从mytensor文件夹外调用的就需要__init__.py了。

__init__.py中定义了接口的调用方式

# -*- coding: utf-8 -*-
from .nn import FullConnection
from .nn import Conv2D
from .nn import MaxPool
from .train import GradientDescentOptimizer
from .mytensor import Variable, placeholder
from .mytensor import matmul
from .mytensor import exp, sin, cos, log
from .mytensor import square, relu, softmax, sigmoid, Line
from .mytensor import MeanSquareLoss, SoftmaxCrossEntropy
from .mytensor import Session

用mnist数据集测试:

# -*- coding: utf-8 -*-
'''
mnist测试
'''
import numpy as np
import mytensor as mt
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import LabelBinarizer
from sklearn import metricsdata = np.load("mnist.npz")
def DataStandard(X):return StandardScaler().fit_transform(X)
def DataTrans(y):return LabelBinarizer().fit_transform(y)X_train, y_train, X_val, y_val, X_test, y_test = data['X'], data['y'], data['X_val'], data['y_val'], data['X_test'], data['y_test']
X_train, X_val, X_test = DataStandard(X_train), DataStandard(X_val), DataStandard(X_test)
y_train, y_val, y_test = DataTrans(y_train), DataTrans(y_val), DataTrans(y_test)
BATCH_SIZE = 128
#权重和偏置
W1 = mt.Variable(np.random.uniform(-0.01, 0.01, (784, 128)))
b1 = mt.Variable(np.random.uniform(-0.01, 0.01, (128)))
W2 = mt.Variable(np.random.uniform(-0.01, 0.01, (128, 10)))
b2 = mt.Variable(np.random.uniform(-0.01, 0.01, (10)))
#占位符
xs = mt.placeholder((None, 784))
ys = mt.placeholder((None, 10))
#两层神经网络
h1 = mt.nn.FullConnection(xs, W1, b1, mt.relu)
h2 = mt.nn.FullConnection(h1, W2, b2, mt.softmax)
#定义loss和train
loss = mt.SoftmaxCrossEntropy(h2, ys)
train = mt.train.GradientDescentOptimizer(1e-4, loss)sess = mt.Session()start = 0
for i in range(10000):    end = start + BATCH_SIZEif  end >= X_train.shape[0]:end = X_train.shape[0] - 1X_batch = X_train[start: end]y_batch = y_train[start: end]start = endif start == X_train.shape[0] - 1:start = 0sess.run(train, {xs: X_batch, ys: y_batch})if (i % 100 == 0):los = sess.run(loss, {xs: X_val, ys: y_val})output = sess.run(h2, {xs: X_val})y_pred = np.argmax(output, axis = 1)acc = metrics.accuracy_score(y_pred, np.argmax(y_val, axis = 1))print("times : {}, loss : {}, accuracy : {}".format(i, los, acc))los = sess.run(loss, {xs: X_test, ys: y_test})
output = sess.run(h2, {xs: X_test})
y_pred = np.argmax(output, axis = 1)
acc = metrics.accuracy_score(y_pred, np.argmax(y_test, axis = 1))
print("test data: loss : {}, accuracy : {}".format(los, acc))

f83a09c15823a22ef966cf60e35ea337.png

。。。

212556beae7993b4c229e122f9415f97.png

最后得到93%正确率。其实这在全连接层还算是可以接受的结果。如果利用卷积池化来处理的话,准确率必然会大大提高。

后记:数模又双叒叕参与奖了,怀着悲愤的心情才抽出时间写下此文。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/562540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DateFormat类

DateFormat是一个抽象类,一般使用它的子类SimpleDateFormat类来实现。主要作用就是把时间队形转化成指定格式的字符串 反之,把指定格式的字符串转化成时间对象。 package demo10;import java.text.DateFormat; import java.text.ParseException; impor…

免费CDN:jsDeliver+Github使用方法

免费CDN:jsDeliverGithub使用方法 CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户…

教你如何使用github+jsDelivr搭建免费图床

前言 之前写了一篇文章,教你如何使用TyporaPicGo实现图片自动上传到图床 。 这里我用的是七牛图床,七牛图床有一定的免费使用量(没记错的话应该是10个G),如果你的存储量超过这个大小就需要付费使用了。除此之外&…

hexo-Fluid主题使用手册

hexo-Fluid主题使用手册 [官网] https://fluid-dev.github.io/hexo-fluid-docs/ 前言 Fluid 是一款很十分优雅的主题,那么写一篇优雅的文章搭配它呢?以下会从几个方面来简述,主要还是做几个推荐。 文章内容 熟悉 Markdown 语法 对于使…

Hexo-fluid主题设置统计博客阅读量

Hexo-fluid主题设置统计博客阅读量 开始小插曲: 我使用的是sublime文本编辑器: [官网] https://www.sublimetext.com/ 正戏开始 查找关键字:web_analytics (快捷键ctrlF) 这里我使用一个第三方服务Leancloud来统计文章的阅读量。 首先…

使用Hexo写博客

尽管 Hexo 支持 MarkDown,但是我们却不能像写单独的 MarkDown 文档时那样肆无忌惮。由于我们所写的文档是需要被解析为静态网页文件的,所以我们必须严格遵从 Hexo 的规范,这样才能解析出条理清晰的静态网页文件。新建文档 假设我们的文章名为…

mysql过滤效率和java过滤效率_如何合理选择初中高效过滤器的效率?

利菲尔特环保科技点击蓝字 关注我们 各种型号的空气过滤器有不同的标准和使用效率,今天利菲尔特为您介绍各种类型的空气过滤器在不同地方的应用。一般情况下,最末一级过滤器决定空气净化的程度,上游的各级过滤器只起保护作用&…

宝塔面板搭建autoPicCdn:一款基于jsdelivr-Github的免费CDN图床

autoPicCdn是白嫖Github的存储空间,通过jsdelivr全球加速(含有国内节点)。实现图床加速的目的。加速效果非常不错,用站长工具检测,也是一片绿油油,所以用来存储一些静态文件是最合适不过了。 相关文章:GithubjsDelivrP…

物流设计大赛优秀作品_中国外运杯第七届全国大学生物流设计大赛案例专家评审会在京召开...

2020年9月10日,“中国外运杯”第七届全国大学生物流设计大赛案例专家评审会在京召开。中国物流与采购联合会副会长任豪祥、中国物流与采购联合会原副会长、中国物流与采购联合会专家委员会主任戴定一、中国外运股份有限公司首席数字官高翔等有关领导及来自行业企业、…

细思极恐---十年生死两茫茫,通信人,意欲亡。

每一位通信人,都可能面对过来自亲友的“灵魂三问”。 “通信究竟是什么?” “通信从哪里来?” “通信要往哪里去?” 讲真的,我不知道。。。。本篇博文是模仿codesheep羊哥写的,因为我们都学的通信&#x…

归并排序--Java

归并排序: 排序原理: 1、尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,知道拆分后的每个子组的元素个数是1为止。 2、将相邻的两个子组进行合并成一个有序的大组 3、不断重复步骤2,直到最终只…

希尔排序--Java

希尔排序 排序原理: 1、选定一个增量h,按照增长量h作为数据分组的依据,对数据进行分组 2、对分好组的每一组数据完成插入排序 3、减小增长量,最小减为1,重复第二步操作 其中,希尔排序确定增长量h的规则…

插入排序--Java

插入排序: 原理: 1、把所有的元素分为两组,已经排序的和未排序的 2、找到未排序的组中的第一个元素,向已经排序的组中进行插入 3、倒叙遍历已经排序的元素,依次和待插叙的元素进行比较,直到找到一个元素…

redis 缓存预热_Redis:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级

一、缓存雪崩缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而…

用接口写冒泡排序

用接口写冒泡排序&#xff1a; package demo02.maopaoapi.Bubble; public class Bubble {/***对数组a中的元素进行排序*/public static void sort(Comparable[] a){for (int i a.length-1; i >0; i--) {for (int j 0; j < i; j) {//比较索引j和索引j1处的值if (greate…

选择排序--Java

选择排序&#xff1a;合适的元素放在合适的位置 1、每一次遍历的过程中&#xff0c;都假定第一个索引处的元素是最小值&#xff0c;和其他索引处的值依次进行比较&#xff0c;如果当前索引处的值大于其他某个索引处的值&#xff0c;则假定其他某个索引处的只为最小值&#xff…

Comparable接口的使用:(知识回顾)

Comparable接口的使用&#xff1a;&#xff08;知识回顾&#xff09; 1、定义一个学生类&#xff0c;具有年龄age和姓名username两个属性&#xff0c;并通过Comparable接口提供比较规则。 package demo02.sort; public class Student implements Comparable<Student>{p…

binary search(二分法)

binary search&#xff08;二分法&#xff09;&#xff1a; 代码&#xff1a; import java.util.Arrays;/*** 二分法查找元素*/ public class BinarySearch {public static void main(String[] args) {int[] arr {30,20,50,10,80,9,7,12,100,40,8};int searchWord 20;//要查…

冒泡排序--Java

1、冒泡排序 import java.util.Arrays; /*** 冒泡排序*/ public class Test01 {public static void main(String[] args) {int[] values {3,1,6,2,9,0,7,4,8,5};System.out.println("排序前数组&#xff1a;" Arrays.toString(values));int temp;for (int i 0; i …

Java_FileInputStream_读一个文件

Java_FileInputStream_读一个文件 代码: package demo01;import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException;public class FileInputStreamTest01 {public static void main(String[] args) {FileInputStream fis null;tr…