查看原文
其他

面银行软开,我最自信了!!

小林coding 小林coding 2024-04-19

图解学习网站:xiaolincoding.com

大家好,我是小林。

有同学问我银行软开岗位的面试要怎么准备?难度如何?

银行的面试跟互联网公司的面试还是有区别。银行除了技术面试之外,还会有结构化面试、无领导讨论的面试问题,这类形式主要是考察同学们的软实力,以及解决问题的思路。

那针对技术面试,银行也会问八股文,但是问的不多,考察的时间也比较短,银行技术面试时间 20 分钟(10 个问题以内),互联网大厂的技术面试都得 1 个小时(20-30 个问题),是 3 倍的强度。

学历有优势的同学,面银行难度不大,只需要准备好一些简单八股文基本都能应对技术面试了,不用学太多内容。

银行开发主要是Java后端,学C++的同学也可以面银行,面试偶尔会出几个C++八股文,但是需要重点深入学习MySQL、网络、数据结构与算法。

这次主要分享农业银行、招联、交通的技术面试问题。

范围的考察主要是 Java(基础、集合、多线程、JVM)、MySQL(索引+事务)、计算机网络(HTTP、TCP)、数据结构与算法、Linux命令,给准备面试银行的同学做一个参考。

农行

行锁和表锁的区别?

表锁的锁粒度比行锁大,表锁是锁住整张数据库表,而行锁只锁住某一行记录,使用行锁的并发性能会比行锁更高。

MySQL 的 InnoDB 存储引擎和 MyISAM 引擎都支持表锁,但是只有 InnoDB 存储引擎才支持行级锁的,而 MyISAM 引擎并不支持行级锁。所以,MyISAM 读写并发性能没有 InnoDB 存储引擎高。

表级锁主要有这几种锁:

  • 表锁:表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。
  • 元数据锁:元数据锁为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。当有线程在执行 select 语句( 加 MDL 读锁)的期间,如果有其他线程要更改该表的结构( 申请 MDL 写锁),那么将会被阻塞,直到执行完 select 语句( 释放 MDL 读锁)。反之,当有线程对表结构进行变更( 加 MDL 写锁)的期间,如果有其他线程执行了 CRUD 操作( 申请 MDL 读锁),那么就会被阻塞,直到表结构变更完成( 释放 MDL 写锁)。
  • 意向锁:当执行插入、更新、删除操作,需要先对表加上「意向锁」,然后对该记录加行级锁,意向锁的目的是为了快速判断表里是否有记录被加锁。

行级别锁主要有这几种锁:

  • 记录锁:住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的,满足读读共享、读写互斥的特性。当行记录有记录锁的时候,其他记录就无法修改和删除这条记录。
  • 间隙锁:只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象,间隙锁可以防止其他事务插入新记录。
  • 临键锁:是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身,临键锁既能避免其他事务修改和删除记录,也能避免其他事务插入新记录

事务的四大特性介绍一下

事务必须要遵守 4 个特性,分别如下:

  • 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样,就好比买一件商品,购买成功时,则给商家付了钱,商品到手;购买失败时,则商品在商家手中,消费者的钱也没花出去。
  • 一致性(Consistency):是指事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态。比如,用户 A 和用户 B 在银行分别有 800 元和 600 元,总共 1400 元,用户 A 给用户 B 转账 200 元,分为两个步骤,从 A 的账户扣除 200 元和对 B 的账户增加 200 元。一致性就是要求上述步骤操作后,最后的结果是用户 A 还有 600 元,用户 B 有 800 元,总共 1400 元,而不会出现用户 A 扣除了 200 元,但用户 B 未增加的情况(该情况,用户 A 和 B 均为 600 元,总共 1200 元)。
  • 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,因为多个事务同时使用相同的数据时,不会相互干扰,每个事务都有一个完整的数据空间,对其他并发事务是隔离的。也就是说,消费者购买商品这个事务,是不影响其他消费者购买的。
  • 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

隔离方式有几种?是不是隔离级别越高越好?

隔离级别主要有 4 种:

  • 读未提交,指一个事务还没提交时,它做的变更就能被其他事务看到;
  • 读提交,指一个事务提交之后,它做的变更才能被其他事务看到;
  • 可重复读,指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别
  • 串行化;会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行;

按隔离水平高低排序如下,隔离级别越高,代表事务并发性能越差。

图片

JVM、JDK、JRE三者关系?

它们之间的关系如下:

  • JVM是Java虚拟机,是Java程序运行的环境。它负责将Java字节码(由Java编译器生成)解释或编译成机器码,并执行程序。JVM提供了内存管理、垃圾回收、安全性等功能,使得Java程序具备跨平台性。

  • JDK是Java开发工具包,是开发Java程序所需的工具集合。它包含了JVM、编译器(javac)、调试器(jdb)等开发工具,以及一系列的类库(如Java标准库和开发工具库)。JDK提供了开发、编译、调试和运行Java程序所需的全部工具和环境。

  • JRE是Java运行时环境,是Java程序运行所需的最小环境。它包含了JVM和一组Java类库,用于支持Java程序的执行。JRE不包含开发工具,只提供Java程序运行所需的运行环境。

说几个你懂的排序算法?

img
  • 冒泡排序:通过相邻元素的比较和交换,每次将最大(或最小)的元素逐步“冒泡”到最后(或最前)。时间复杂度:最好情况下O(n),最坏情况下O(n^2),平均情况下O(n^2)。,空间复杂度:O(1)。
  • 插入排序:将待排序元素逐个插入到已排序序列的合适位置,形成有序序列。时间复杂度:最好情况下O(n),最坏情况下O(n^2),平均情况下O(n^2),空间复杂度:O(1)。
  • 选择排序(Selection Sort):通过不断选择未排序部分的最小(或最大)元素,并将其放置在已排序部分的末尾(或开头)。时间复杂度:最好情况下O(n^2),最坏情况下O(n^2),平均情况下O(n^2),空间复杂度:O(1)。
  • 快速排序(Quick Sort):通过选择一个基准元素,将数组划分为两个子数组,使得左子数组的元素都小于(或等于)基准元素,右子数组的元素都大于(或等于)基准元素,然后对子数组进行递归排序。时间复杂度:最好情况下O(nlogn),最坏情况下O(n^2),平均情况下O(nlogn),空间复杂度:最好情况下O(logn),最坏情况下O(n)。
  • 归并排序(Merge Sort):将数组不断分割为更小的子数组,然后将子数组进行合并,合并过程中进行排序。时间复杂度:最好情况下O(nlogn),最坏情况下O(nlogn),平均情况下O(nlogn)。空间复杂度:O(n)。
  • 排序(Heap Sort):通过将待排序元素构建成一个最大堆(或最小堆),然后将堆顶元素与末尾元素交换,再重新调整堆,重复该过程直到排序完成。时间复杂度:最好情况下O(nlogn),最坏情况下O(nlogn),平均情况下O(nlogn)。空间复杂度:O(1)。

讲一下快排原理

快排使用了分治策略的思想,所谓分治,顾名思义,就是分而治之,将一个复杂的问题,分成两个或多个相似的子问题,在把子问题分成更小的子问题,直到更小的子问题可以简单求解,求解子问题,则原问题的解则为子问题解的合并。

快排的过程简单的说只有三步:

  • 首先从序列中选取一个数作为基准数
  • 将比这个数大的数全部放到它的右边,把小于或者等于它的数全部放到它的左边 (一次快排 partition
  • 然后分别对基准的左右两边重复以上的操作,直到数组完全排序

具体按以下步骤实现:

  • 1,创建两个指针分别指向数组的最左端以及最右端
  • 2,在数组中任意取出一个元素作为基准
  • 3,左指针开始向右移动,遇到比基准大的停止
  • 4,右指针开始向左移动,遇到比基准小的元素停止,交换左右指针所指向的元素
  • 5,重复3,4,直到左指针超过右指针,此时,比基准小的值就都会放在基准的左边,比基准大的值会出现在基准的右边
  • 6,然后分别对基准的左右两边重复以上的操作,直到数组完全排序

注意这里的基准该如何选择?最简单的一种做法是每次都是选择最左边的元素作为基准,但这对几乎已经有序的序列来说,并不是最好的选择,它将会导致算法的最坏表现。还有一种做法,就是选择中间的数或通过 Math.random() 来随机选取一个数作为基准。

img

TCP、HTTP关系是什么?

HTTP 是应用层的协议,TCP是传输层的协议。

image-20240108005159940

HTTP协议通常基于TCP协议进行数据的可靠传输,所以客户端 HTTP 发送请求之前,需要先通过 TCP 三次握手建立 TCP 连接,然后才能发送 HTTP 请求给服务器,服务器接收到请求后,处理并生成相应的HTTP响应消息,再通过TCP连接返回给客户端。

Python数据类型有几种?

  • 数值型:包括整数(int)、浮点数(float)和复数(complex)。
  • 字符串:用于表示文本和字符序列,使用单引号或双引号括起来。
  • 列表(List):用于存储多个有序的元素,可以包含不同类型的数据,使用方括号 [] 来表示。
  • 元组(Tuple):类似于列表,但是元组是不可修改的,使用圆括号 () 来表示。
  • 字典(Dictionary):用于存储键值对(key-value)的数据结构,键(key)和值(value)之间使用冒号 : 分隔,使用花括号 {} 来表示。
  • 集合(Set):用于存储无序、唯一的元素,不支持重复元素,使用花括号 {} 或 set() 函数来创建。

招联(一面+二面)

mysql的逻辑结构是怎样的?

查询语句执行流程

MySQL 的架构共分为两层:Server 层和存储引擎层

  • Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现,主要包括连接器,查询缓存、解析器、预处理器、优化器、执行器等。另外,所有的内置函数(如日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等。)都在 Server 层实现。
  • 存储引擎层负责数据的存储和提取。支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同的存储引擎共用一个 Server 层。现在最常用的存储引擎是 InnoDB,从 MySQL 5.5 版本开始, InnoDB 成为了 MySQL 的默认存储引擎。我们常说的索引数据结构,就是由存储引擎层实现的,不同的存储引擎支持的索引类型也不相同,比如 InnoDB 支持索引类型是 B+树 ,且是默认使用,也就是说在数据表中创建的主键索引和二级索引默认使用的是 B+ 树索引。

mysql 存储引擎层底层结构是什么呢?

从数据结构的角度来看,MySQL 常见索引有 B+Tree 索引、HASH 索引、Full-Text 索引。

每一种存储引擎支持的索引类型不一定相同,我在表中总结了 MySQL 常见的存储引擎 InnoDB、MyISAM 和 Memory 分别支持的索引类型。

InnoDB 是在 MySQL 5.5 之后成为默认的 MySQL 存储引擎,B+Tree 索引类型也是 MySQL 存储引擎采用最多的索引类型。

img

类的加载和双亲委派原则

我们把 Java 的类加载过程分为三个主要步骤:加载、链接、初始化。

首先是加载阶段(Loading),它是 Java 将字节码数据从不同的数据源读取到 JVM 中,并映射为 JVM 认可的数据结构(Class 对象),这里的数据源可能是各种各样的形态,如 jar 文件、class 文件,甚至是网络数据源等;如果输入数据不是 ClassFile 的结构,则会抛出 ClassFormatError。

加载阶段是用户参与的阶段,我们可以自定义类加载器,去实现自己的类加载过程。

第二阶段是链接(Linking),这是核心的步骤,简单说是把原始的类定义信息平滑地转化入 JVM 运行的过程中。这里可进一步细分为三个步骤:

  • 验证(Verification),这是虚拟机安全的重要保障,JVM 需要核验字节信息是符合 Java 虚拟机规范的,否则就被认为是 VerifyError,这样就防止了恶意信息或者不合规的信息危害 JVM 的运行,验证阶段有可能触发更多 class 的加载。
  • 准备(Preparation),创建类或接口中的静态变量,并初始化静态变量的初始值。但这里的“初始化”和下面的显式初始化阶段是有区别的,侧重点在于分配所需要的内存空间,不会去执行更进一步的 JVM 指令。
  • 解析(Resolution),在这一步会将常量池中的符号引用(symbolic reference)替换为直接引用。

最后是初始化阶段(initialization),这一步真正去执行类初始化的代码逻辑,包括静态字段赋值的动作,以及执行类定义中的静态初始化块内的逻辑,编译器在编译阶段就会把这部分逻辑整理好,父类型的初始化逻辑优先于当前类型的逻辑。

再来谈谈双亲委派模型,简单说就是当类加载器(Class-Loader)试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载 Java 类型。

string stringbuilder stringbuffur的区别?

String 是 Java 语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String 对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。

StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder。

StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。

抽象和接口的区别?

相同点:

  • 都不能被实例化,接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。

不同点:

  • 实现方式:实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
  • 方法方式:接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
  • 访问修饰符:接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。
  • 变量:抽象类可以包含实例变量和静态变量,而接口只能包含常量(即静态常量)。

Collections和Collection的区别

  • Collection是Java集合框架中的一个接口,它是所有集合类的基础接口。它定义了一组通用的操作和方法,如添加、删除、遍历等,用于操作和管理一组对象。Collection接口有许多实现类,如List、Set和Queue等。

  • Collections(注意有一个s)是Java提供的一个工具类,位于java.util包中。它提供了一系列静态方法,用于对集合进行操作和算法。Collections类中的方法包括排序、查找、替换、反转、随机化等等。这些方法可以对实现了Collection接口的集合进行操作,如List和Set。

Java集合的分类

List是有序的Collection,使用此接口能够精确的控制每个元素的插入位置,用户能根据索引访问List中元素。常用的实现List的类有LinkedList,ArrayList,Vector,Stack。

  • ArrayList是容量可变的非线程安全列表,其底层使用数组实现。当几何扩容时,会创建更大的数组,并把原数组复制到新数组。ArrayList支持对元素的快速随机访问,但插入与删除速度很慢。
  • LinkedList本质是一个双向链表,与ArrayList相比,,其插入和删除速度更快,但随机访问速度更慢。

Set不允许存在重复的元素,与List不同,set中的元素是无序的。常用的实现有HashSet,LinkedHashSet和TreeSet。

  • HashSet通过HashMap实现,HashMap的Key即HashSet存储的元素,所有Key都是用相同的Value,一个名为PRESENT的Object类型常量。使用Key保证元素唯一性,但不保证有序性。由于HashSet是HashMap实现的,因此线程不安全。
  • LinkedHashSet继承自HashSet,通过LinkedHashMap实现,使用双向链表维护元素插入顺序。
  • TreeSet通过TreeMap实现的,添加元素到集合时按照比较规则将其插入合适的位置,保证插入后的集合仍然有序。

Map 是一个键值对集合,存储键、值和之间的映射。Key 无序,唯一;value 不要求有序,允许重复。Map 没有继承于 Collection 接口,从 Map 集合中检索元素时,只要给出键对象,就会返回对应的值对象。主要实现有TreeMap、HashMap、HashTable、LinkedHashMap、ConcurrentHashMap

  • HashMap:JDK1.8 之前 HashMap 由数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突),JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树,以减少搜索时间
  • LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
  • HashTable:数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  • TreeMap:红黑树(自平衡的排序二叉树)
  • ConcurrentHashMap:Node数组+链表+红黑树实现,线程安全的(jdk1.8以前Segment锁,1.8以后CAS锁)

arraylist和linkedlist的共性和区别

ArrayList和LinkedList都是Java中常见的集合类,它们都实现了List接口。

共性是都可以用来存储和操作一组对象、都支持动态添加和删除元素、都允许元素的重复。

区别如下

底层数据结构不同:

  • ArrayList使用数组实现,通过索引进行快速访问元素。
  • LinkedList使用链表实现,通过节点之间的指针进行元素的访问和操作。

插入和删除操作的效率不同:

  • ArrayList在尾部的插入和删除操作效率较高,但在中间或开头的插入和删除操作效率较低,需要移动元素。
  • LinkedList在任意位置的插入和删除操作效率都比较高,因为只需要调整节点之间的指针。

随机访问的效率不同:

  • ArrayList支持通过索引进行快速随机访问,时间复杂度为O(1)。
  • LinkedList需要从头或尾开始遍历链表,时间复杂度为O(n)。

空间占用:

  • ArrayList在创建时需要分配一段连续的内存空间,因此会占用较大的空间。
  • LinkedList每个节点只需要存储元素和指针,因此相对较小。

ArrayList适用于频繁随机访问和尾部的插入删除操作,而LinkedList适用于频繁的中间插入删除操作和不需要随机访问的场景。

hashmap和ConcurrentHashmap的区别是什么?

HashMap 不是线程安全的,多个线程同时进行读写操作可能会导致数据不一致或抛出异常。

ConcurrentHashMap是线程安全的,JDK 1.7 是通过分段锁来保证线程安全的,JDK 1.8 ConcurrentHashMap 主要通过 volatile + CAS 或者 synchronized 来实现的线程安全的。

代码题

  • 用两个栈实现队列

  • 十进制转二进制

交通银行

说一下主键和索引

主键是用于唯一标识数据库表中每一行数据的字段或字段组合。它具有以下特点:

  • 主键必须是唯一的,每一行数据都必须具有唯一的主键值。
  • 主键不能为NULL,即主键字段的值不能为空。
  • 一个表只能有一个主键。

主键的作用是保证每一行数据的唯一性,并且可以通过主键来快速定位和访问表中的数据。

索引是一种数据结构,用于加快数据库表的查询速度。它通过创建索引来提高数据的检索效率。索引可以建立在一个或多个列上,这些列可以是表中的任意字段。索引的创建过程会对指定的列进行排序和存储,以便快速定位和访问数据。

索引的作用是加快查询操作的速度,通过使用索引,可以减少数据库的扫描和比较操作,从而提高查询的效率。但是索引也会占用额外的存储空间,并且在插入、更新和删除操作时需要维护索引,会增加写操作的开销。

主键和索引可以结合使用,主键字段通常会自动创建一个索引。使用主键作为索引可以保证数据的唯一性,并且可以通过主键快速定位和访问数据。此外,还可以根据具体的查询需求创建其他索引,以提高特定查询的效率。

索引的优缺点?

索引最大的好处是提高查询速度,但是索引也是有缺点的,比如:

  • 需要占用物理空间,数量越大,占用空间越大;
  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增大;
  • 会降低表的增删改的效率,因为每次增删改索引,B+ 树为了维护索引有序性,都需要进行动态维护。

所以,索引不是万能钥匙,它也是根据场景来使用的。

说一些Linux常用命令?

  • 文件相关(mv mkdir cd ls)

  • 进程相关( ps top netstate )

  • 权限相关(chmod chown useradd groupadd)

  • 网络相关(netstat ip addr)

  • 测试相关(测试网络连通性:ping 测试端口连通性:telnet)

修改文件权限用什么命令?

用 chmod 命令,可以修改文件或目录的权限。

以下是几个使用chmod命令修改文件权限的例子:

  1. 将文件(例如file.txt)设置为只读权限:
chmod 400 file.txt
  1. 将文件设置为所有者可读写权限,其他用户只能读取权限:
chmod 644 file.txt
  1. 将文件设置为所有者可读写执行权限,所属组用户可读执行权限,其他用户只能读取权限:
chmod 755 file.txt
  1. 将目录设置为所有者可读写执行权限,所属组用户可读执行权限,其他用户只能读取权限:
chmod 755 directory/

在这些例子中,chmod命令后面的三个数字代表了不同的权限组:

  • 第一位表示所有者的权限。
  • 第二位表示所属组的权限。
  • 第三位表示其他用户的权限。

每个数字可以使用 0-7 之间的数值来表示权限:

  • 0 表示没有权限。
  • 1 表示执行权限。
  • 2 表示写权限。
  • 4 表示读权限。

可以根据需要自由组合这些数字来设置文件或目录的权限。

解释一下c++的继承、封装、多态。

  • 继承:C++中的继承允许一个类(派生类/子类)从另一个类(基类/父类)继承属性和方法。派生类可以通过继承基类来扩展和重用代码。在C++中,派生类可以通过关键字"public"、"protected"或"private"来指定继承的方式和访问权限。

  • 封装:C++中的封装将数据和操作数据的函数捆绑在一起,对外隐藏实现细节。通过使用类的访问修饰符(public、protected、private),我们可以控制对类的成员的访问权限。公共成员(public)可以被其他类和函数访问,私有成员(private)只能被本类的成员访问,保护成员(protected)可以被派生类的成员访问。

  • 多态:C++中的多态允许不同类型的对象对同一消息做出响应,具体行为取决于对象的实际类型。通过使用虚函数(virtual function)和虚函数表(vtable),C++实现了运行时多态。多态可以通过基类指针或引用来实现,可以提高代码的灵活性和可复用性。

了解哪些数据结构?

  • 数组:数组的内存空间是连续的,随机访问的时间复杂度是O1,适用于需要按索引访问元素的场景,但是插入和删除元素较慢,时间复杂度是On
  • 链表:链表是由节点组成,节点之间是分散存储的,内存不连续,每个节点存储数据和指向下一个节点的指针。适用于频繁插入和删除元素的场景,随机访问元素较慢。
  • 栈:栈是一种后进先出的数据结构,只允许在栈顶进行插入和删除操作。
  • 队列:队列是一种先进先出(FIFO)的数据结构,允许在队尾插入元素,在队首删除元素。
  • 树:树是一种非线性数据结构,由节点和边组成,每个节点可以有多个子节点。树适用于表示层次关系的场景,例如文件系统、组织结构等。

说一下队列和栈的区别

主要区别在于元素的插入和删除方式以及元素的访问顺序。

插入和删除方式:

  • 队列:队列采用先进先出(FIFO)的方式,即新元素插入队尾,删除操作发生在队首。
  • 栈:栈采用后进先出(LIFO)的方式,即新元素插入栈顶,删除操作也发生在栈顶。

元素的访问顺序:

  • 队列:队列的元素按照插入的顺序进行访问,先插入的元素先被访问到。
  • 栈:栈的元素按照插入的顺序进行访问,但是最后插入的元素先被访问到。

队列适用于需要按照插入顺序进行处理的场景,例如任务调度;

queue

而栈适用于需要维护最近操作状态的场景,例如函数调用。

历史好文:

后端突击训练营,又开始卷了!

今年这情况,想读研了。。。

还得是腾讯,捞了我一把!

不愧是字节,面个实习也满头大汗!

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存