收罗了招银网络网上能收到的软开C++方面的面经,整理出来,已经面试过了,主要分为数据库,C/C++,操作系统,计算机网络等几个方面,下面分享给大家。

数据库

1.解释一下事务 和 ACID 特性

事务:是并发控制的基本单位。所谓的事务是指逻辑上的一组操作,组成这组操作的各个功能,要么全部成功,要么全部都不成功。事务可以是一条SQL语句,一组SQL语句或者整个程序。事物的提出是为了解决并发情况下保持数据一致性问题。

start transaction 开启事务

rollback 回滚事务

commit 提交事务

 

Atomicity 原子性

指事务是一个不可分割的操作单位,事务中的操作要么全部成功,要么全部不成功

Consistency 一致性

必须使数据库从一个一致性状态装换到另一个一致性状态

如转账前A+B为2000,A像B转账100,完成后,A和B总和仍然为2000元

Isolation 隔离性

多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所影响

Durability 持久性

一个事务一旦被提交。对数据库的改变就是永久性的,即使数据库发生故障也不会造成影响

2.事务隔离性

不隔离带来问题:

脏读:读取了另一个事务未提交的数据

不可重复读:多次读取同一行,多次读取结果不同,读取了另一个事务提交的数据

幻读:其他事物插入了新记录,导致前后读取不一致、

隔离级别:

读取未提交 READ UNCOMMITED   最低级别,无法解决问题

          读取已提交 READ COMMITED    大多数数据库默认级别   解决脏读

          可重读     REPEATABLE READ  Mysql默认级别    解决脏读,不可重复读

          可串行化   SERIALIZABLE      全部解决,但效率极低,一般不用 带来超时和锁竞争现象

3.索引作用及好处坏处分析

4.EXISTS 和 IN 的区别

IN先执行子查询,将子查询结果和主查询表做笛卡尔积,在进行选择符合条件的,查询次数为两个表记录乘积。

而EXISTS先执行主查询语句,然后根据每一条记录进行子查询语句判定,查询次数为主查询记录数。

因此当子查询表较大时,因使用EXISTS。而 子查询表记录比如只有100条时,宁愿选择in,因为in在内存里遍历比较 ,而EXISTS需要查询数据库,所消耗的性能更高,内存比较更快。

5.内连接,外连接和交叉连接

a.内连接:利用内连接可获取两表的公共部分的记录

Select * from A JOIN B ON A.Aid=B.Bnameid 

select * from A,B where A.Aid=B.Bnameid

.外连接:外连接分为两种,一种是左连接(Left JOIN)和右连接(Right JOIN)

 (1)左连接(Left JOIN):即图3公共部分记录集C+表A记录集A1。

 语句如下:select * from A Left JOIN B ON A.Aid=B.Bnameid 

(2)右连接(Right JOIN):即图3公共部分记录集C+表B记录集B1。

语句如下:select * from A Right JOIN B ON A.Aid=B.Bnameid 

c.交叉连接

  概念:不带WHERE条件子句,它将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积(例如:T_student和T_class,返回4*4=16条记录),如果带where,返回或显示的是匹配的行数

d.全连接

概念:返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值

6.SQL中的触发器有什么作用

https://www.cnblogs.com/yuxiaohui/p/3204817.html

https://www.cnblogs.com/feiquan/archive/2018/04/01/8685722.html

触发器的主要作用就是其能够实现由主键和外键所不能保证的复杂的参照完整性和数据的一致性。除此之外,触发器还有其它许多不同的功能:

(1)强化约束(Enforce restriction)

(2)跟踪变化(Auditing changes)

(3)级联运行(Cascaded operation)。

(4)存储过程的调用(Stored procedure invocation)。

7.视图和表的区别

表与视图很相似,都是可以包含相同类型的数据的二维结构,都有行,列,单元格,在select语句的from字句中,都可以将他们用作数据源。

当需要区分表和视图的时候,通常表被称为基表或者数据表。

不同之处: 

a:表直接将数据存储在磁盘上,视图是将sql语句存储到磁盘上 

b:视图是建立在表的基础上,表存储数据库中的数据,而视图显示已经在表中的数据的外观 

c:表是静态的,而视图是动态的,意思是表中数据发生了改变,其建立在表基础的视图跟着改变 

d:通过视图不能改变表中数据。 

e:删除视图,表不受影响,而删除表,视图不再起作用 

f:视图本身没有数据,只保存了sql语句

总之:记住视图只保存了sql语句,没有保存数据,每次使用视图时会去执行sql语句在它的基表中查询数据,而表却是实实在在的保存着数据。可以将查询语句保存到视图中,在每次需要数据的时候去执行查询,也可以直接将查询语句的结果保存到一个表中,以后使用的时候不再查询,前者没有后者快,后者比前者需要更多的磁盘空间。

可以通过视图来修改基表的数据,但是有很多限制。只支持单表修改

8.B+树的节点分裂

C/C++

1.变量的4种不同存储类型

栈区:局部变量,形参临时变量

堆区:由程序员自己申请 new malloc

全局区:静态变量和全局变量

常量区:常量字符串 等

2.怎么定义一个常量指针

const int *a; 常量指针 ,指向值不可变

int * const a;指针常量 ,指向位置不可变

3.重载和重写,重定义的区别

一、重载(overload)

指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。

(1)相同的范围(在同一个作用域中) ;

(2)函数名字相同;

(3)参数不同;

(4)virtual 关键字可有可无。

(5)返回值可以不同;

二、重写(也称为覆盖 override)

是指派生类重新定义基类的虚函数,特征是:

(1)不在同一个作用域(分别位于派生类与基类) ;

(2)函数名字相同;

(3)参数相同;

(4)基类函数必须有 virtual 关键字,不能有 static 。

(5)返回值相同(或是协变),否则报错;<—-协变这个概念我也是第一次才知道…

(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的

三、重定义(也成隐藏)

(1)不在同一个作用域(分别位于派生类与基类) ;

(2)函数名字相同;

(3)返回值可以不同;

(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆) 。

(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。

Child c; 此时执行c里的函数,父类函数被隐藏,自动执行子类里的函数

Father *b = &c; 此时执行b里的函数,覆盖了的会执行c中的,而重定义的仍执行b中的;

4.结构体里面有没有构造函数和析构函数

可以有,和CALSS区别如下.

class这个关键字还用于定义模板参 数,就像“typename”。但关键字“struct”不用于定义模板参数。

class中默认继承方式是private,而struct的默认继承方式是public

class中默认成员访问权限是private,而struct的默认访问权限是public

5.拷贝构造函数为什么要用引用

不然在调用拷贝构造函数时,创建形参临时变量又会调用拷贝构造函数,会引起无限递归调用。

6.C语言中单向链表和双向链表有什么区别

单向链表,只能访问当前节点的下一个节点。而双向链表可以访问下一个节点和前一个节点

单向循环链表,最后一个节点next指针为NULL,双向循环链表,最后一个节点next指针为*phead,*phead的pre指针为最后一个节点。

7.跳跃表有没有听过

  跳跃表基于有序单链表,在链表的基础上,每个结点不只包含一个指针,还可能包含多个指向后继结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。 查询,删除,插入都是logn

8.java有内存回收的机制,C没有,什么时候出现野指针,什么时候出现内存泄漏

野指针:定义的指针没有及时初始化。delete指针之后,没有及时置为NULL 。指针超过了变量的作用范围。

内存泄漏 https://www.cnblogs.com/liushui-sky/p/7727865.html

9.new和malloc的区别

malloc是标准库函数,支持覆盖。new是运算符,支持重载

malloc和free仅仅分配和回收空间,而new和delete除了分配回收空间,还会调用构造函数和析构函数

malloc返回的是void类型指针,必须进行类型转换。new返回的是具体类型指针

10.静态成员函数为什么不能声明为虚函数

static成员不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义的。

静态与非静态成员函数之间有一个主要的区别。那就是静态成员函数没有this指针。

ps:,静态成员函数也不能被声明为const和volatile. 而static成员函数没有this指针,所以使用const来修饰static成员函数没有任何意义。  volatile的道理也是如此。

数据结构与算法

1.各算法复杂度

最坏情况下复杂度最小的排序算法 堆排序

数组基本有序 插入排序

插排 时间复杂度与比较次数,移动次数都与初始序列有关

快排 时间复杂度与比较次数,与移动次数都与初始序列有关

归排 时间复杂度与初始序列无关,比较次数有关(有序序列),移动次数无关(无论怎么有序,还是每个元素拷贝到新的数组)

选排 时间复杂度与初始序列无关,比较次数无关,移动次数无关

冒排 时间复杂度与初始序列无关,比较次数无关,移动次数有关

2.如何实现环形队列/链表

环形队列:两个指针指向入口,插入一个数后,尾指针进行移动,头指针不动,删除一个数时,头指针向前移即可。注意插入数时,m_tail = m_tail % queue_capacity

环形链表:使用尾插法建立单链表,插入完最后一个数之后,该节点的next指针不指向NULL,而指向*phead。

3.二叉树的遍历有哪几种

前序 根左右

中序 左根右

后序 左右根 递归和非递归都可实现,代码熟悉

层序 使用一个栈来实现,从根节点开始遍历,左右节点入栈,然后访问左子节点,打印,同时左子节点的左右节点再次入栈,一直到栈为空,由此可以实现层序遍历。

https://blog.csdn.net/u012159812/article/details/82316111

编程题

1.寻找字串

BF或者KMP算法

https://blog.csdn.net/u012159812/article/details/80204863

2.单链表反转 复杂度为n

直接标定3个节点,然后对每个节点进行反转,而不会丢失无法访问下个节点

ListNode* ReverseList(ListNode* pHead) {

ListNode *pnewHead=NULL;

ListNode *p=pHead;

while(p)

{

ListNode *pNext=p->next;

p->next = pnewHead;

pnewHead = p;

p=pNext;

}

return pnewHead;

}

3.新旧密码判定

输入三个字符串 旧密码,新密码,新密码确认 ,旧密码不能和新密码相同,新密码2次要一样,且不能是123456或者666666这种简单密码

操作系统:

1.进程和线程

进程:资源分配的基本单位,进程可以并发执行。

线程:独立调度的基本单位,一个进程中可以有多个线程,他们共享进程资源

区别:

a.拥有资源 进程是资源分配基本单位。线程不拥有资源,可以访问隶属进程的资源

b.调度 线程是独立调度的基本单位,在统一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进度中的线程会引起进程切换

c.系统开销 创建和撤销进程的开销远大于线程。进程切换会涉及CPU环境报错和新调度进程CPU环境设置,而线程切换只需保存和设置少量寄存器内容,开销很小

d.通信方面 进程间通信需要进程同步和互斥手段以保证数据一致性,而线程间直接通过读写同一进程中的数据段来进行通信

2.进程通信方式

a.管道 只针对父子进程,半双工

b.FIFO 去掉了父子进程限制 常用于客户-服务器应用程序中

c.消息队列 比FIFO更好

d,信号量

e.共享存储 最快的一种进程通信

f.套接字 解决不同机器间进程通信

3.什么是死锁,必要条件,解决方法

死锁,是指多个进程在运行过程中因为争夺资源而造成的的一种僵局,造成他们都无法向前推进

必要条件:a.互斥条件 一段时间内某资源被一个进程占用,此时其他请求者只能等待

b.请求和保持条件 进程已经保持了至少一个资源,但又提出新的资源请求,而请求的资源被其他进程占有,此时请求进程阻塞,又不会释放自己已经占用的资源

c.不可剥夺条件 进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用时由自己释放

d。环路等待条件 请求资源形成资源环形链,即P0等待P1,p1等待p2,。。。pn等待p0;

解决办法。a.预防死锁 破坏必要条件预防发生死锁

b.避免死锁

c.检测死锁

d.解除死锁

4.sleep和wait的区别

https://blog.csdn.net/xyh269/article/details/52613507

sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。 因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。

wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程

sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁

计算机网络

1.路由层协议除了ip协议还有哪些协议

ICMP

IGMP

2.arp协议有什么作用,具体的协议处理过程? 

由IP地址得到MAC物理地址

3.TCP/IP四层,几个协议分别属于哪层

HTTP DNS 等应用层

TCP UDP 运输层

IP ICMP IGMP RAP RARP 网际层

网络接口层

4.TCP重传机制

5.DNS原理

其他

1.瀑布模型几个阶段

2.动态链接库和静态链接库

3.说10个编程的好习惯

4.简要描述一个客户端服务器通信的步骤 Socket

 

 

10-02 15:14