【数据结构与算法】JavaScript实现单向链表

文章目录

      • 一、单向链表简介
      • 二、封装单向链表类
        • 2.0.创建单向链表类
        • 2.1.append(element)
        • 2.2.toString()
        • 2.3.insert(position,element)
        • 2.4.get(position)
        • 2.5.indexOf(element)
        • 2.6.update(position,element)
        • 2.7.removeAt(position)
        • 2.8.其他方法
        • 2.9.完整实现

一、单向链表简介

链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有的语言称为指针或连接)组成。类似于火车头,一节车厢载着乘客(数据),通过节点连接另一节车厢。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • head属性指向链表的第一个节点;
  • 链表中的最后一个节点指向null;
  • 当链表中一个节点也没有的时候,head直接指向null;

数组存在的缺点:

  • 数组的创建通常需要申请一段连续的内存空间(一整块内存),并且大小是固定的。所以当原数组不能满足容量需求时,需要扩容(一般情况下是申请一个更大的数组,比如2倍,然后将原数组中的元素复制过去)。
  • 在数组的开头或中间位置插入数据的成本很高,需要进行大量元素的位移。

链表的优势:

  • 链表中的元素在内存中不必是连续的空间,可以充分利用计算机的内存,实现灵活的内存动态管理
  • 链表不必在创建时就确定大小,并且大小可以无限地延伸下去。
  • 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多。

链表的缺点:

  • 链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。
  • 无法通过下标值直接访问元素,需要从头开始一个个访问,直到找到对应的元素。
  • 虽然可以轻松地到达下一个节点,但是回到前一个节点是很难的。

链表中的常见操作:

  • append(element):向链表尾部添加一个新的项;
  • insert(position,element):向链表的特定位置插入一个新的项;
  • get(position):获取对应位置的元素;
  • indexOf(element):返回元素在链表中的索引。如果链表中没有该元素就返回-1;
  • update(position,element):修改某个位置的元素;
  • removeAt(position):从链表的特定位置移除一项;
  • remove(element):从链表中移除一项;
  • isEmpty():如果链表中不包含任何元素,返回trun,如果链表长度大于0则返回false;
  • size():返回链表包含的元素个数,与数组的length属性类似;
  • toString():由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值;

首先需要弄清楚:下文中的position指的是两个节点之间,并且与index的关系如下图所示:

在这里插入图片描述

position的值一般表示position所指位置的下一个节点。当position的值与index的值相等时,比如position = index = 1,那么它们都表示Node2。

二、封装单向链表类

2.0.创建单向链表类

先创建单向链表类Linklist,并添加基本属性,再实现单向链表的常用方法:

    // 封装单向链表类function LinkList(){// 封装一个内部类:节点类function Node(data){this.data = data;this.next = null;}// 属性// 属性head指向链表的第一个节点this.head = null;this.length = 0;}
2.1.append(element)

代码实现:

      // 一.实现append方法LinkList.prototype.append = data => {//1.创建新节点let newNode = new Node(data)//2.添加新节点//情况1:只有一个节点时候if(this.length == 0){this.head = newNode//情况2:节点数大于1,在链表的最后添加新节点  }else {              //让变量current指向第一个节点let current = this.head//当current.next(下一个节点不为空)不为空时,一直循环,直到current指向最后一个节点while (current.next){current = current.next}// 最后节点的next指向新的节点current.next = newNode}//3.添加完新结点之后length+1this.length += 1}

过程详解:

  • 首先让current指向第一个节点:

在这里插入图片描述

  • 通过while循环使current指向最后一个节点,最后通过current.next = newNode,让最后一个节点指向新节点newNode:

在这里插入图片描述

测试代码:

    //测试代码//1.创建LinkListlet list = new LinkList()//2.测试append方法list.append('aaa')list.append('bbb')list.append('ccc')console.log(list);  

测试结果:

在这里插入图片描述

2.2.toString()

代码实现:

      // 实现toString方法LinkList.prototype.toString = () => {// 1.定义变量let current = this.headlet listString = ""// 2.循环获取一个个的节点while(current){ listString += current.data + " "current = current.next//千万不要忘了拼接完一个节点数据之后,让current指向下一个节点}return  listString}

测试代码:

    //测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')//3.测试toString方法console.log(list.toString());

测试结果:

在这里插入图片描述

2.3.insert(position,element)

代码实现:

      // 实现insert方法LinkList.prototype.insert = (position, data) => {//理解positon的含义:position=0表示新界点插入后要成为第1个节点,position=2表示新界点插入后要成为第3个节点//1.对position进行越界判断:要求传入的position不能是负数且不能超过LinkList的lengthif(position < 0 || position > this.length){return false}//2.根据data创建newNodelet newNode = new Node(data)//3.插入新节点//情况1:插入位置position=0if(position == 0){// 让新节点指向第一个节点newNode.next = this.head// 让head指向新节点this.head = newNode//情况2:插入位置position>0(该情况包含position=length)} else{let index = 0let previous = nulllet current = this.head//步骤1:通过while循环使变量current指向position位置的后一个节点(注意while循环的写法)while(index++ < position){//步骤2:在current指向下一个节点之前,让previous指向current当前指向的节点previous = currentcurrent = current.next}// 步骤3:通过变量current(此时current已经指向position位置的后一个节点),使newNode指向position位置的后一个节点newNode.next = current//步骤4:通过变量previous,使position位置的前一个节点指向newNodeprevious.next = newNode/*启示:1.我们无法直接操作链表中的节点,但是可以通过变量指向这些节点,以此间接地操作节点(替身使者);比如current指向节点3,想要节点3指向节点4只需要:current.next = 4即可。2.两个节点间是双向的,想要节点2的前一个节点为节点1,可以通过:1.next=2,来实现;*/}//4.新节点插入后要length+1this.length += 1;return true}

过程详解:

inset方法实现的过程:根据插入节点位置的不同可分为多种情况:

  • 情况1:position = 0

通过: newNode.next = this.head,建立连接1;

通过: this.head = newNode,建立连接2;(不能先建立连接2,否则this.head不再指向Node1)

在这里插入图片描述

  • 情况2:position > 0

首先定义两个变量previous和curent分别指向需要插入位置pos = X的前一个节点和后一个节点;

然后,通过:newNode.next = current,改变指向3;

最后,通过:previous.next = newNode,改变指向4;

在这里插入图片描述

  • 情况2的特殊情形:position = length

情况2也包含了pos = length的情况,该情况下current和newNode.next都指向null;建立连接3和连接4的方式与情况2相同。

在这里插入图片描述

测试代码:

    //测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')//3.测试insert方法list.insert(0, '在链表最前面插入节点');list.insert(2, '在链表中第二个节点后插入节点');list.insert(5, '在链表最后插入节点');alert(list);console.log(list);

测试结果:
在这里插入图片描述

在这里插入图片描述

2.4.get(position)

代码实现:

      //实现get方法LinkList.prototype.get = (position) => {//1.越界判断// 当position = length时,取到的是null所以0 =< position < lengthif(position < 0 || position >= this.length){return null}//2.获取指定的positon位置的后一个节点的data//同样使用一个变量间接操作节点let current = this.headlet index = 0while(index++ < position){current = current.next}return current.data}

过程详解:

get方法的实现过程:以获取position = 2为例,如下图所示:

  • 首先使current指向第一个节点,此时index=0;

在这里插入图片描述

  • 通过while循环使current循环指向下一个节点,注意循环终止的条件index++ < position,即当index=position时停止循环,此时循环了1次,current指向第二个节点(Node2),最后通过current.data返回Node2节点的数据;

在这里插入图片描述

测试代码:

	//测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')	//3.测试get方法console.log(list.get(0));console.log(list.get(1));

测试结果:

在这里插入图片描述

2.5.indexOf(element)

代码实现:

      //实现indexOf方法LinkList.prototype.indexOf = data => {//1.定义变量let current = this.headlet index = 0//2.开始查找:只要current不指向null就一直循环while(current){if(current.data == data){return index}current = current.nextindex += 1} //3.遍历完链表没有找到,返回-1return -1}

过程详解:

indexOf方法的实现过程:

  • 使用变量current记录当前指向的节点,使用变量index记录当前节点的索引值(注意index = node数-1):

在这里插入图片描述

测试代码:

	//测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')	//3.测试indexOf方法console.log(list.indexOf('aaa'));console.log(list.indexOf('ccc'));

测试结果:

在这里插入图片描述

2.6.update(position,element)

代码实现:

      //实现update方法LinkList.prototype.update = (position, newData) => {//1.越界判断//因为被修改的节点不能为null,所以position不能等于lengthif(position < 0 || position >= this.length){return false}//2.查找正确的节点let current = this.headlet index = 0while(index++ < position){current = current.next}//3.将position位置的后一个节点的data修改成newDatacurrent.data = newData//返回true表示修改成功return true}

测试代码:

	//测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')	//3.测试update方法list.update(0, '修改第一个节点')list.update(1, '修改第二个节点')console.log(list);console.log(list.update(3, '能修改么'));

测试结果:

在这里插入图片描述

2.7.removeAt(position)

代码实现:

      //实现removeAt方法LinkList.prototype.removeAt = position => {//1.越界判断if (position < 0 || position >= this.length) {//position不能为lengthreturn null}//2.删除元素//情况1:position = 0时(删除第一个节点)let current = this.headif (position ==0 ) {//情况2:position > 0时this.head = this.head.next}else{let index = 0let previous = nullwhile (index++ < position) {previous = currentcurrent = current.next}//循环结束后,current指向position后一个节点,previous指向current前一个节点//再使前一个节点的next指向current的next即可previous.next = current.next}//3,length-1this.length -= 1//返回被删除节点的data,为此current定义在最上面return current.data}

过程详解:

removeAt方法的实现过程:删除节点时存在多种情况:

  • 情况1:position = 0,即移除第一个节点(Node1)。

通过:this.head = this.head.next,改变指向1即可;

虽然Node1的next仍指向Node2,但是没有引用指向Node1,则Node1会被垃圾回收器自动回收,所以不用处理Node1指向Node2的引用next。

在这里插入图片描述

  • 情况2:positon > 0,比如pos = 2即移除第三个节点(Node3)。

**注意:**position = length时position后一个节点为null不能删除,因此position != length;

首先,定义两个变量previous和curent分别指向需要删除位置pos = x的前一个节点和后一个节点;

然后,通过:previous.next = current.next,改变指向1即可;

随后,没有引用指向Node3,Node3就会被自动回收,至此成功删除Node3 。

在这里插入图片描述

测试代码:

    //测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')//3.测试removeAt方法console.log(list.removeAt(0));console.log(list.removeAt(0));console.log(list);

测试结果:

在这里插入图片描述

2.8.其他方法

其他方法包括:remove(element)、isEmpty()、size()

代码实现:

/*-------------其他方法的实现--------------*///一.实现remove方法LinkList.prototype.remove = (data) => {//1.获取data在列表中的位置let position = this.indexOf(data)//2.根据位置信息,删除结点return this.removeAt(position)}//二.实现isEmpty方法LinkList.prototype.isEmpty = () => {return this.length == 0}//三.实现size方法LinkList.prototype.size = () => {return this.length}

测试代码:

    //测试代码//1.创建LinkListlet list = new LinkList()//2.插入数据list.append('aaa')list.append('bbb')list.append('ccc')/*---------------其他方法测试----------------*///remove方法console.log(list.remove('aaa'));console.log(list);//isEmpty方法console.log(list.isEmpty());//size方法console.log(list.size());

测试结果:

在这里插入图片描述

2.9.完整实现
    // 封装链表类function LinkList(){// 封装一个内部类:节点类function Node(data){this.data = data;this.next = null;}// 属性// 属性head指向链表的第一个节点this.head = null;this.length = 0;// 一.实现append方法LinkList.prototype.append = data => {//1.创建新节点let newNode = new Node(data)//2.添加新节点//情况1:只有一个节点时候if(this.length == 0){this.head = newNode//情况2:节点数大于1,在链表的最后添加新节点  }else {              //让变量current指向第一个节点let current = this.head//当current.next(下一个节点不为空)不为空时,一直循环,直到current指向最后一个节点while (current.next){current = current.next}// 最后节点的next指向新的节点current.next = newNode}//3.添加完新结点之后length+1this.length += 1}// 二.实现toString方法LinkList.prototype.toString = () => {// 1.定义变量let current = this.headlet listString = ""// 2.循环获取一个个的节点while(current){ listString += current.data + " "current = current.next//千万不要忘了拼接完一个节点数据之后,让current指向下一个节点}return  listString}// 三.实现insert方法LinkList.prototype.insert = (position, data) => {//理解positon的含义:position=0表示新界点插入后要成为第1个节点,position=2表示新界点插入后要成为第3个节点//1.对position进行越界判断:要求传入的position不能是负数且不能超过LinkList的lengthif(position < 0 || position > this.length){return false}//2.根据data创建newNodelet newNode = new Node(data)//3.插入新节点//情况1:插入位置position=0if(position == 0){// 让新节点指向第一个节点newNode.next = this.head// 让head指向新节点this.head = newNode//情况2:插入位置position>0(该情况包含position=length)} else{let index = 0let previous = nulllet current = this.head//步骤1:通过while循环使变量current指向position位置的后一个节点(注意while循环的写法)while(index++ < position){//步骤2:在current指向下一个节点之前,让previous指向current当前指向的节点previous = currentcurrent = current.next}// 步骤3:通过变量current(此时current已经指向position位置的后一个节点),使newNode指向position位置的后一个节点newNode.next = current//步骤4:通过变量previous,使position位置的前一个节点指向newNodeprevious.next = newNode//我们无法直接操作链表中的节点,但是可以通过变量指向这些节点,以此间接地操作节点;}//4.新节点插入后要length+1this.length += 1;return true}//四.实现get方法LinkList.prototype.get = (position) => {//1.越界判断// 当position = length时,取到的是null所以0 =< position < lengthif(position < 0 || position >= this.length){return null}//2.获取指定的positon位置的后一个节点的data//同样使用一个变量间接操作节点let current = this.headlet index = 0while(index++ < position){current = current.next}return current.data}//五.实现indexOf方法LinkList.prototype.indexOf = data => {//1.定义变量let current = this.headlet index = 0//2.开始查找:只要current不指向null就一直循环while(current){if(current.data == data){return index}current = current.nextindex += 1} //3.遍历完链表没有找到,返回-1return -1}//六.实现update方法LinkList.prototype.update = (position, newData) => {//1.越界判断//因为被修改的节点不能为null,所以position不能等于lengthif(position < 0 || position >= this.length){return false}//2.查找正确的节点let current = this.headlet index = 0while(index++ < position){current = current.next}//3.将position位置的后一个节点的data修改成newDatacurrent.data = newData//返回true表示修改成功return true}//七.实现removeAt方法LinkList.prototype.removeAt = position => {//1.越界判断if (position < 0 || position >= this.length) {return null}//2.删除元素//情况1:position = 0时(删除第一个节点)let current = this.headif (position ==0 ) {//情况2:position > 0时this.head = this.head.next}else{let index = 0let previous = nullwhile (index++ < position) {previous = currentcurrent = current.next}//循环结束后,current指向position后一个节点,previous指向current前一个节点//再使前一个节点的next指向current的next即可previous.next = current.next}//3,length-1this.length -= 1//返回被删除节点的data,为此current定义在最上面return current.data}/*-------------其他方法的实现--------------*///八.实现remove方法LinkList.prototype.remove = (data) => {//1.获取data在列表中的位置let position = this.indexOf(data)//2.根据位置信息,删除结点return this.removeAt(position)}//九.实现isEmpty方法LinkList.prototype.isEmpty = () => {return this.length == 0}//十.实现size方法LinkList.prototype.size = () => {return this.length}}

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

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

相关文章

Tomcat学习

一、入门 在webapp里面必须先创建一个文件夹&#xff0c;文件夹里面放的内容&#xff0c;才会被访问到。 创建一个javaweb项目后 二、servlet 1.概述 2.servlet生命周期 3.servlet实例的创建时机 4.Servlet实例的初始化参数 5.HTTP状态码 6.servelet返回JSON数据 7.fa Servel…

C语言——个位数为 6 且能被 3 整除但不能被 5 整除的三位自然数共有多少个,分别是哪些?

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i,j0;for(i100;i<1000;i) {if(i%106&&i%30&&i%5!0){printf("%6d",i); j;}}printf("\n一共%d个\n",j);return 0; } %6d起到美化输出格式的作用&#xff…

C语言基础篇4:变量与存储

1 局部变量和全局变量 在介绍局部变量和全局变量前&#xff0c;先了解一些关于作用域方面的内容。作用域的作用就是决定程序中的哪些语句是可用的&#xff0c;换句话说&#xff0c;就是程序中的可见性。作用域有局部作用域和全局作用域&#xff0c;那么局部变量就具有局部作用域…

代码随想录算法训练营第四十九天丨 动态规划part12

309.最佳买卖股票时机含冷冻期 思路 相对于动态规划&#xff1a;122.买卖股票的最佳时机II (opens new window)&#xff0c;本题加上了一个冷冻期 在动态规划&#xff1a;122.买卖股票的最佳时机II (opens new window)中有两个状态&#xff0c;持有股票后的最多现金&#xf…

NSS [HUBUCTF 2022 新生赛]checkin

NSS [HUBUCTF 2022 新生赛]checkin 判断条件是if ($data_unserialize[username]$username&&$data_unserialize[password]$password)&#xff0c;满足则给我们flag。正常思路来说&#xff0c;我们要使序列化传入的username和password等于代码中的两个同名变量&#xff0…

番外 1 : Java 环境下的 selenium 搭建

Java 环境下的 selenium 搭建 一 . 下载谷歌浏览器二 . 下载谷歌浏览器驱动2.1 查看谷歌浏览器版本2.2 下载对应版本的谷歌驱动2.3 解压下载好的驱动压缩包 , 将下载好的 chromedriver.exe 放到java 系统环境变量下 三 . 下载 Edge 浏览器的驱动3.1 查看 Edge 浏览器的版本3.2 …

k8s的Init Containers容器实现代码版本升级发布和deployment版本回退:实战操作版

Pod中的初始化容器&#xff1a;Init Containers initContainers实现理论前提:同一个Pod内的容器共享 网络、volume等资源 Init Containers 在Kubernetes中&#xff0c;init容器是在同一个Pod中的其他容器之前启动和执行的容器。它的目的是为Pod上托管的主应用程序执行初始化…

洛谷P9388 [THUPC 2023 决赛] 先人类的人类选别(主席树+权值线段树)

题目 思路来源 P9388 [THUPC 2023 决赛] 先人类的人类选别 - 违规用户名FkZyA0!2 的博客 - 洛谷博客 题解 这个题是2023ccpc深圳热身赛的题目&#xff0c;也是thupc2023决赛的题目&#xff0c; 学弟问了一下&#xff0c;于是就乱搞了一下&#xff0c;搞了很久才a&#xff0…

Linux ____03、文件类型、属性、修改文件属性(更改文件权限)(命令)

文件类型、属性、修改文件属性 一、文件类型二、文件属性三、修改文件属性1、chgrp&#xff1a;更改文件属组2、chown&#xff1a;更改文件属主&#xff0c;也可以同时更改文件属组3、chmod&#xff1a;更改文件9个属性————————如觉不错&#xff0c;随手点赞&#xff…

微信小程序真机调试连接状态一直在正常和未链接之间反复横跳?

背景&#xff1a;小程序真机调试的时候&#xff0c;发现真机的network不显示接口调用情况&#xff0c;控制台也没有输出内容。具体如下所示&#xff1b; 解决方法&#xff1a; 1、确保手机端连接的网络和微信开发者工具网络一致&#xff0c;比如用同一个WiFi 2、真机自动调试…

编程知识\_C与汇编深入分析

1. 汇编怎么调用C函数 1.1 直接调用 bl main 1.2 想传参数怎么办&#xff1f; 在arm中有个ATPCS规则(ARM-THUMB procedure call standard&#xff08;ARM-Thumb过程调用标准&#xff09;。 约定r0-r15寄存器的用途&#xff1a; r0-r3 调用者和被调用者之间传参数 r4-r11 函…

Flink SQL自定义标量函数(Scalar Function)

使用场景&#xff1a; 标量函数即 UDF&#xff0c;⽤于进⼀条数据出⼀条数据的场景。 开发流程&#xff1a; 实现 org.apache.flink.table.functions.ScalarFunction 接⼝实现⼀个或者多个⾃定义的 eval 函数&#xff0c;名称必须叫做 eval&#xff0c;eval ⽅法签名必须是 p…

冒泡排序

贵阳这个地方的天气变化好大呀&#xff0c;前两天晒大太阳&#xff0c;今天就冷的脚抖&#xff0c;简直不要太冷&#xff0c;但是不管怎么样&#xff0c;还是要学习的哟&#xff01; 冬天来了&#xff0c;春天确实还有一点远&#xff01; 好了&#xff0c;话不多说&#xff0c;…

springboot rocketmq 延时消息、延迟消息

rocketmq也有延迟消息&#xff0c;经典的应用场景&#xff1a;订单30分钟未支付&#xff0c;则取消的场景 其他博客提到从rocketmq5.0开始&#xff0c;支持自定义延迟时间&#xff0c;4.x只支持预定义延迟时间&#xff0c;安装rocketmq可参考RocketMq简介及安装、docker安装ro…

【C++】模板初阶

目录 一&#xff0c;泛型编程 二&#xff0c;函数模板 1&#xff0c;函数模板概念 2&#xff0c;函数模板格式 3&#xff0c;函数模板的原理 4&#xff0c;函数模板的实例化 5&#xff0c;模板参数的匹配原则 三&#xff0c;类模板 1&#xff0c;类模板的定义格式 2&…

⑤ 【MySQL】DCL语句 —— 用户管理、权限控制

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL用户与权限 ⑤ 【MySQL】DCL语句 —— 用…

pytorch中对nn.BatchNorm2d()函数的理解

pytorch中对BatchNorm2d函数的理解 简介计算3. Pytorch的nn.BatchNorm2d()函数4 代码示例 简介 机器学习中&#xff0c;进行模型训练之前&#xff0c;需对数据做归一化处理&#xff0c;使其分布一致。在深度神经网络训练过程中&#xff0c;通常一次训练是一个batch&#xff0c…

U-Mail邮件系统安全登录解决方案

企业邮箱是企业对内对外商务往来的主要通信工具&#xff0c;并且企业邮箱里面还包含了大量企业内部隐私信息、商业机密等&#xff0c;很容易成为黑客的攻击目标。其中邮件盗号是企业邮箱遭受攻击的主要形式&#xff0c;一旦企业邮箱密码被黑客盗取&#xff0c;黑客不仅可以利用…

操作系统 | 虚拟机及linux的安装

​ &#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《操作系统实验室》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1.操作系统实验之虚拟机及linux的安装 1.1 实验目的 1.2 实验内容 1.3 实验步骤 …

BIO、NIO、AIO之间有什么区别

文章目录 BIO优缺点示例代码 NIO优缺点示例代码 AIO优缺点示例代码 总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 BIO、NIO和AIO是Java编程语言中用于处理输入输出&#xff08;IO…