自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(48)
  • 收藏
  • 关注

原创 【Java ee初阶】网络原理

缺点:可读性很差。以前这种方案比较流行,现在越来越少了。

2025-05-10 23:02:46 206

原创 【Java ee初阶】网络编程 TCP

两个核心的类。

2025-05-10 16:33:46 349

原创 【Java ee初阶】网络编程 UDP socket

DatagramSocket是UDP Socket,用于发送和接收UDP数据报。DatagramSocket构造方法:UDP数据报套接字方法表方法签名方法说明创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)DatagramSocket方法数据报套接字方法表方法签名方法说明从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)

2025-05-10 13:04:21 604

原创 【Java ee初阶】初始网络

IP地址主要用于标识网络主机、其他网络设备(如路由器)的网络地址。简单说,IP地址用于定位主机的网络地址。就像我们发送快递一样,需要知道对方的收货地址,快递员才能将包裹送到目的地。IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节),如:01100100.00000100.00000101.00000110。通常用“点分十进制”的方式来表示,即 a.b.c.d 的形式(a,b,c,d都是0~255之间的十进制整数)。如:100.4.5.6。在网络通信中,IP地址用于标识主机网络

2025-05-08 20:14:38 1258

原创 【Java ee 初阶】文件IO和操作(下)

书接上文。

2025-05-08 14:53:08 925

原创 【Java ee 初阶】文件操作和IO(上)

文件在计算机中,是保存到“硬盘”上的。操作系统,把硬盘操作进行了抽象封装,使得编程的时候,是不会直接操作硬盘的,而是通过“文件”的概念来进行间接操作。文件有哪些操作?——>打开文件,关闭文件,读文件,写文件......通过前面的学习我们可以知道,cpu包括存储器、输入设备、输出设备,其中存储器包含内存和硬盘,软盘、光盘、U盘也属于存储器。磁盘上的盘片是存储数据的介质,可以快速旋转,磁盘上还有磁头,磁头可以读取文件。通过文件资源管理器来管理所有文件。

2025-05-08 10:52:33 971

原创 【Java ee 初阶】多线程(9)上

本质上就是一个计数器,描述了一种“可用资源”的个数申请资源(P操作):使得计数器-1释放资源(V操作):使得计数器+1如果计数器为0了,继续申请资源,就会触发阻塞上述+1 -1 这些操作,都是原子的Java把操作系统提供的信号量进行封装输出:输出:信号量,相当于“锁”概念的进一步延申。锁,可以视为是“初始值为1”的特殊信号量。小结:编写线程安全代码的时候:1.加锁(最主要)2.CAS/原子类3.信号量。

2025-05-07 21:29:55 535

原创 【Java ee 初阶】多线程(8)

锁升级时一个自适应的过程,自适应的过程如下:在Java编程中,有一部分的人不一定能正确地使用锁,因此,Java的设计者为了让大家使用锁的门槛更低,就在synchronized中引入了很多优化策略。*首先,根据前面的学习,我们已经初步了解了自旋锁和重量级锁,那么图中的偏向锁是什么?偏向锁,不是真正加锁,而只是做个标记,如果整个过程中,没有其他线程来竞争这个锁,偏向锁状态就始终保持,直到最终解锁。但是,如果在过程中,遇到其他线程也尝试来竞争这个锁,就可以在其他线程拿到锁之前,抢先获取这个锁。

2025-05-07 19:47:59 1024

原创 【Java ee初阶】锁策略

注意,synchronized是自适应的,当锁竞争不激烈的时候,就会采取自旋锁的策略;挂起等待锁,就是“悲观锁”/“重量级锁”的典型实现,这种锁遇到锁冲突,就会让线程挂起来等待(调度出cpu,等待被cpu唤醒)自旋锁,就是“乐观锁”/“轻量级锁”的典型实现,遇到锁冲突,不会放弃cpu,而是会通过“忙等”的方式,再次尝试获取锁。synchronized,属于非公平锁,实现公平锁,需要引入队列,记录加锁线程的顺序。轻量级锁,加锁的开销比较小,等待锁的线程,等待时间相对来说更短。重量级锁,加锁的开销比较大。

2025-05-07 14:44:14 226

原创 【Java ee初阶】多线程(7)

比如想把线程池中的线程,按照一定的规则,设置name,或者想把线程池的线程全都设置成后台线程,或者都设置xxx为优先级。线程池在使用的时候,首先会创建一些线程,然后需要调用者给线程池放一些任务,这些线程就会从队列中取出任务,并且执行里面的代码。因此直接让添加任务的线程阻塞,其实是不太好的,不太好就意味着要有其他的方法——因此标准库的线程池就引入了“拒绝策略”正常情况下,是线程池里面的线程执行任务的,但是现在线程池里面的线程忙不过来了,就只能由调用者自己找个线程来执行任务。为什么需要定时器呢?

2025-05-05 22:28:46 1145

原创 【Java ee初阶】多线程(6)

队列的原则:“先进先出”,队列分为普通队列,优先级队列等等。在数据结构中,堆是特殊的完全二叉树,一定不要把堆和二叉搜索树混淆。阻塞队列是一种特殊的队列,也遵循“先进先出”的原则。阻塞队列的特点:1.线程安全2.带有阻塞功能(1)如果队列为空,尝试出队列,就会触发阻塞,直到队列不空(2)如果队列满了,尝试入队列,也会触发阻塞,直到队列不满*生产者消费模型引入生产者消费模型,主要目的是为了减少“锁竞争”,生产者和消费者的步调,不一定完全一致。出现不一样的时候阻塞队列可以起到"协调"的作用。

2025-05-05 17:31:19 1213

原创 【Java ee初阶】多线程(5)

wait notify 是两个用来协调线程执行顺序的关键字,用来避免“线程饿死”的情况。wait 和 notify 其实都是 Object 这个类的方法,而 Object这个类是所有类的“祖宗类”,也就是说明,任何一个类,都可以调用wait 和notify这两个方法。Java标准库中,涉及到阻塞的方法,都可能抛出InterruptedException让我们来观察一下这个异常的名字。Illegal:非法的,不正确的,不合理的(而不是违反法律的)、

2025-05-05 15:00:13 840

原创 【Java ee初阶】多线程(4)

同时,反复执行的过程中,每次拿到的flag的值还都是一样的,上述的load操作相比cmp,耗时会多很多,读取内存,比读取寄存器,效率会慢很多(几百倍,几千倍)*解决线程安全问题,我们使用加锁的方式。虽然有的程序员水平不高,写的代码效率比较低,编译器在编译执行的时候,分析理解现有代码的意图和效果,然后自动对这个代码进行调整和优化,在确保程序执行逻辑不变的前提下,提高程序的效率。线程饿死,没那么严重,在线程1反复获取几次锁之后,其他线程也是有机会拿到锁的,但是其他线程拿到锁的时间会延长,降低了程序的效率。

2025-04-28 22:13:56 948

原创 【JAVA ee初阶】多线程(3)

(这个类有哪些成员,都叫啥名字,都是啥类型,都是private/public,有啥方法,都叫啥名,参数列表是啥,是private/public,这个类继承的父类是谁,上实现了哪些interface.......)(注意,死锁有很多种体现形式,可重入只是能解决一个线程一把锁,加锁两次的情况,解决不了其他情况)同一个线程,针对同一把锁,连续加锁多次,不会触发死锁,此时这个锁就可以称为“可重入锁”。SQL中,事务就是把多个SQL打包成一个整体,执行的时候,要么全都执行完,要么一个都不执行。

2025-04-28 17:52:29 1196

原创 【Java EE初阶】多线程(二)

join前面是哪个引用,对应的线程就是“被等的一方”(此处就是t)。count++这样的操作,如果站在cpu指令的角度来说,其实是三个指令(指令就是机器语言,cpu执行的任务的具体细节,cpu会一条一条的读取指令,解析指令,执行指令)对于cpu来说,每个指令都是执行的最基本的单位。如果采取强制终止的手段,很可能t线程的某个逻辑没有执行完,可能就会造成一些“脏数据”的输出,e.g.t执行过程中针对数据库的数据进行多次增删改查操作,结果由于上述强制中断,导致对数据库的数据修改操作只进行了一半,留下了脏数据。

2025-04-28 11:34:13 860

原创 【数据结构_12】优先级队列

通过以上例子我们可以看出,优先级队列是一个“特殊”的队列,正常的队列的顺序是“先进先出”,优先级队列,出队列的顺序和入队列的是不一样的,是把队列中的每个元素,都约定了“优先级”,出队列的时候把优先级最高的元素先出队列。*向下调整/下沉式调整:进行向下调整的前提是除了根节点之外,其他的节点,都已经符合堆的要求,随便给个数组,直接向下调整一次,是不足以构建出整个堆的。2.所谓的向下调整,找出子树中的最小值,和根节点比较,如果根节点大,就和刚才的子树节点交换,持续往下进行直到根节点比子树小,或者没有子树的时候。

2025-04-21 13:53:56 1068

原创 【数据结构_11】二叉树(5)

一上来不能访问根节点,需要先向左递归,必须得再左子树整个都完成了之后才能去访问根节点,根节点入栈,继续往左找,左子树的根节点也不能访问,也得入栈,继续往左找,一直重复上述过程直到遇到左子树为null的情况,然后去访问根节点(也就是把他添加到list),访问完栈顶元素,还不能继续出栈,要把栈顶元素的右子树再进行入栈,不能直接访问右子树根节点,先入栈,再找右子树的左子树,一路入栈,一路找,直到找到左子树为null的时候才能出栈访问。1.从根节点出发,一路入栈,直到遇到左子树为空的节点。1.创建栈,根节点入栈。

2025-04-21 10:57:16 311

原创 【JAVA EE初阶】多线程(1)

除非是接口提供了一组方法,这一组方法中存在一些“公共的逻辑”,就可以在接口中搞default方法,使得这个方法表示公共逻辑,后面就可以在重写其他抽象方法的时候去调用了。这个新的线程会以run作为入口方法(执行run)的逻辑,run方法,不需要在代码中显式调用。剩下的线程,都是JVM自带的,这些线程进行了一些背后的操作,比如负责垃圾回收,记录统计信息,记录一些调试信息。第二种写法,任务是写到Runnable中的,几乎不涉及到任何和“线程”相关的概念,任务内容和Thread概念的耦合是很小的,几乎没有。

2025-04-20 17:09:34 1111

原创 【数据结构_12】二叉树(4)

思路:可以按照先序的方式来遍历这个树,递归的时候,给递归方法,加上辅助的参数,level表示当前层数,递归过程中,根据level的值,决定当前整个节点要放到哪个list中。这个题目中,是通过二维list表示结果的,list中的[0]的元素就是根节点,如果把根节点视为第 0 层,此时的level就是和下标对应上了,如果把根节点视为第一层,就需要把level-1再作为下标。

2025-04-20 13:20:55 1055

原创 【数据结构_11】二叉树(3)

思路:对树进行层序遍历1.要求每个节点必须有两个子树(a)没有子树,进入二阶段(b)只有左子树,进入二阶段(c)只有右子树,判定为false2.要求每个节点必须没有子树。

2025-04-19 12:41:43 652

原创 【数据结构_10】二叉树(2)

思路:如果我们想要获得第k层节点的个数,如果k<1,这是非法的输入,如果k=1,也就是求第一层节点的个数,而非空的树第一层的节点个数也就是1。2.拿着根节点在中序中进行查找,查找规则:在中序遍历中,左子树就在根节点左侧,右子树就在根节点右侧,拿着根节点E,在中序结果中进行查找。3.先序中,如果明确了根节点和子树范围,此时,子树范围对应的内容就是子树的先序结果(后序也是类似,子树对应的内容就是子树的后序结果)2.在中序遍历中,左子树就在根节点左侧,右子树就在根节点右侧,拿着根节点E,在中序结果中进行查找。

2025-04-18 23:49:33 810

原创 【数据结构_10】二叉树(1)

树是一种非线性的数据结构,是由n个有限节点组成一个具有层次关系的集合。树的每个节点能够延伸出多个子节点,但每个子节点只能由一个父节点。树形结构中,子树之间不能有交集,否则就不是树形结构。

2025-04-17 20:57:56 1148

原创 【数据结构_9】栈和队列

队列 Queue 一个方向进,一个方向出Queue队列提供的核心方法:入队列:offer add出队列:poll remove取队首元素: peek element前面一列发生错误是返回null 后面一列发生错误时抛出异常Queue是否能够使用isEmpty()/size 等这样的方法呢?答案:是可以的,因为Queue接口继承自Collection接口,而Collection接口实现了这一系列方法。

2025-04-16 17:19:00 1108

原创 【数据结构_7】栈和队列(队列上篇)

队列这样的数据结构,往往是针对“耗时比较长”的操作提供辅助操作,有些操作没办法一口气全部完成,所以需要将他们按照顺序,一个一个处理。队列的表示:Queue 是一个接口(interface) 接口不能创建实例,只能创建其他类来实现该接口,再通过整个类来实现接口中的抽象方法。出入队列的操作都可能抛出异常,但是原则上来说,入队列一般不会失败,除非是插入的元素类型不匹配,传入null值之类的...队列,也是针对线性表进行进行进一步的封装和限制,提供的操作有三个:入队列、出队列、取队首元素。

2025-04-14 14:01:48 350

原创 【数据结构_8】栈和队列

4.pushA遍历完毕之后,如果栈为空,说明当前的结果就是true,如果栈不为空,说明结果就是false。3.如果发现当前字符是右括号,取出刚才的栈顶元素,用当前的右括号和栈顶左括号去判定匹配。d)如果不符合上述要求,回到2.继续遍历下一个pushA元素。b)如果栈不为空,判定栈顶元素是不是等于popA的当前元素。3.在每次入栈一个元素之后,都拿着popA进行判定。2.如果发现当前字符是左括号,就直接入栈。2.遍历pushA,把每个元素,依次出栈。Ⅱ利用栈进行链表元素的反向输出。解题思路:1.先有一个栈。

2025-04-14 11:03:18 395

原创 【数据结构_7】栈和队列(上)

顺序表链表这样的结构,功能太丰富了,容易出错;栈/队列针对特定的场景,对顺序表链表做出了限制,从而大大降低了出错的概率。此处所见到的栈,本质上就是一个顺序表/链表,但是,实在顺序表/链表的基础上做出了限制。对栈来说禁止了顺序表/链表的各种增删改查,只支持三个操作:入栈、出栈、取栈顶元素。栈虽然在功能上做出了限制,但是他却是能在特定场景下,解决特定问题的特定手段。因此我们可以认为,栈就是只支持尾插、尾删、获取尾部元素的顺序表/链表。栈是一种特殊的线性表,其只允许在固定的一段进行插入和删除元素操作。

2025-04-13 20:58:30 313

原创 【数据结构_6】双向链表的实现

一、实现MyDLinkedList(双向链表)

2025-04-13 20:08:21 389

原创 【数据结构_6下篇】有关链表的oj题

空间复杂度为O(1),时间复杂度为O(N)(*考虑极端情况,比如环的长度就是整个链表长度N,fast和slow最开始上环的时候,差距是N,此时意味着,每循环一次,差距就措施小N,最多经过N次就重合了)创建cur1从交汇位置出发,创建cur2从链表的头部出发,每次循环走一步的方式,同时往后走,当cur1与cur2重合,此时相遇的位置,就相当于环的入口。反例:fast一次走3步,slow一次走1步,环的长度为2,这样的情况下,fast和slow是永远也重合不了的,这和环的长度是有关系的。

2025-04-12 10:51:46 976

原创 【数据结构_6上篇】有关链表的oj题

空间复杂度为O(N)的解法。空间复杂度为O(1)的写法。

2025-04-11 23:26:57 285

原创 【数据结构_5】链表(模拟实现以及leetcode上链表相关的题目)

3.比较这两个引用的值,谁小,就把哪个节点取出来,插入到新链表的末尾,如果这两个引用,有任何一个指向了null,说明该链表就结束了,就把另一个链表剩余的元素都添加到新链表的末尾即可。在链表中,本身是没有下标这样的概念的,不像顺序表,顺序表根据下标访问元素,O(1)复杂度。1.这道题的要点就在于头节点的删除,如果head=[7,7,7,7],我们就先不管头节点,先把后面值等于val的节点删除,然后循环出来再去考虑头节点。使三者遍历整个链表,按照如下图所示的操作完成链表的翻转。书接上文,继续编写链表的功能。

2025-04-10 21:01:40 521

原创 【数据结构_4下篇】链表

链表,不要求在连续的内存空间,链表是一个离散的结构。链表的元素和元素之间,内存是不连续的,而且这些元素的空间之间也没有什么规律:1.顺序上没有规律 2.内存空间上也没有规律*如何知道链表中包含元素以及如何遍历链表中的所有元素呢?链表中的每一个节点都包含两个部分,一个是他自身的引用变量,另一个是next(下一个节点的引用变量),因此只要我们拥有第一个节点的引用变量,我们就可以完成上述操作了链表的两个特点:1.链表的元素是在离散的内存空间上的2.每个元素都记录下一个元素的地址(引用)

2025-04-09 17:15:39 436

原创 【数据结构_4】顺序表

顺序表的”尾插“操作和”根据下标获取/修改元素”操作的时间复杂度都是O(1),说明顺序表比较擅长这两方面的事务。其余操作的时间复杂度均为O(N)。顺序表是基于数组来实现的,所以当我们创建了一个顺序表的时候,是先去申请了一大块空间去创建数组。因此,顺序表具有局限性:1.空间利用率低2.中间位置的插入和删除操作,都需要进行搬运。

2025-04-09 15:36:08 376

原创 【数据结构_3】顺序表

1.创建一个顺序表//第一种,通过下标来实现遍历i++) {//第二种,通过forecah来遍历//特别的,顺序表还可以通过迭代器来进行遍历迭代器是什么?对于所有的线性表都有一个接口Iterable,迭代器就是用来迭代“可迭代的”对象的。迭代表示“一小步一小步地前进,直至接近结果”。<>尖括号里面的泛型类型应该与顺序表的泛型参数一样,从这个创建的式子中我们可见迭代器是顺序表内部内置的东西。创建的迭代器是由哪个集合类生成的,接下来的遍历就是针对这个集合类。

2025-04-08 21:23:59 390

原创 【数据结构2】包装类等_作业复盘

2. 遍历数组,如果nums[i]与nums[count-1]不等,就将nums[i]搬移。到nums[count]位置,不同元素多了一个,给count++由于不同的元素需要往前搬移,那count-1就是前面不同元素。搬移之后,最后一个元素的位置,下一次在遇到不同元素就应该。1. 设置一个计数,记录从前往后遍历时遇到的不同元素的个数。3. 循环结束后,返回count。搬移到count位置。

2025-04-08 17:39:16 153

原创 【数据结构2】包装类&泛型

1.类型分为:(1)基础数据类型(内置数据类型)(2)引用类型这里所有的类都是直接或者间接引用自Object类二者并不一样,举个例子就是int,byte等等不能使用equals,clone等方法如何将二者进行转化?——>包装类java标准库中创建了一组类,能够将内置类型的变量包装一下变成引用类型,这也就是我们所说的包装类!虽然包装类也是类,但是在进行算术运算的时候,需要将包装类转换成基本内置类型,再进行运算!因此就衍生出两个概念:装箱:内置类型—>包装类型拆箱:包装类型—>内置类型。

2025-04-08 16:48:12 555

原创 数据结构作业复盘

首先我们要明确,这道题中被重复操作的函数应该是while(i<=n)整个操作,只要当满足条件i<=n的时候他就会一直重复操作,所以时间复杂度应该是(log N)这是一个递归,递归是在栈上进行的,由于迭代了N次,所以T(N)也就被重复调用了n次,时间复杂度也就是O(N)。由题意可知最终创建的数组应该如图所示,所以空间复杂度也就是n+n-1+n-2+...+1=O(n)在这道题中,左右指针最多把整个数组都遍历一遍,也就是N次,所以,他最终的时间复杂度为O(N)。与N无关,故空间复杂度为常数也就是O(1)

2025-04-07 21:31:55 214 1

原创 数据结构和集合类

此处需要注意的点:这里说的是“临时”占用,也就是说我们在考虑空间复杂度的时候,我们是不考虑问题规模N本身的占用空间大小的,比方说,参数传入了长度为N的数组,在考虑这里的空间复杂度的时候,我们无法把数组占据的空间大小记入空间复杂度。for()循环里面的重复操作我们并不计算他的时间复杂度//原因:这些操作消耗的时间非常短,一般在皮秒级别(1s = 10^(-12)s)多个参数:第一个循环中循环了M次,第二个循环中循环了N次,故时间复杂度为O(M+N)斐波那契递归数列 的空间复杂度:O(N)(是看具体的层数)

2025-04-07 20:38:49 224

原创 C语言程序设计//文件//期末复习专用思维导图

2024-01-11 09:41:16 389 1

原创 C语言复习//期末复习//思维导图//数据类型与结构

2024-01-11 09:32:03 374 1

原创 C语言程序设计//模块三:函数//思维导图复习大纲

2024-01-10 20:52:39 375 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除