系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、下面有关事务隔离级别说法正确的是(多选)
- 二、下列选项给出的是从根分别到达两个叶结点路径上的权值序列,能属于同一棵哈夫曼树的是_______。
- 三、平均情况下,以下排序算法中,各自的时间复杂度分别是?直接插入排序、冒泡排序、快速排序、堆排序
- 四、现有【员工】表,其字段有:在职状态、部门、员工编号,求在职员工人数大于100的部门,以下sql正确的是()
- 五、栈a和队列B的初始状态为空,元素Q1,Q2,Q3,Q4,Q5,Q6依次压入栈A,一个元素出栈后即进入队列B,若出队列的顺序为Q2,Q4,Q3,Q6,Q5,Q1则栈a的容量要求最小值为
- 六、现有一个包含m个节点的三叉树,即每个节点都有3个指向孩子节点的指针,请问:在这3m个指针中有(b)个空指针
- 七、T(n) = T(n - 1) + n(n为正整数)及T(0) = 1, 则算法的时间复杂度为()
- 八、简述TCP协议的三次握手和四次挥手并说明为什么要第四次挥手
- 九、编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果 n=2,移位后应该是“hiabcdefgh”
- 十、 给定一个单链表,查找链表中倒数第n个节点。
前言
一、下面有关事务隔离级别说法正确的是(多选)
A.串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
B.未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改 的数据
C.提交读(Read Committed):只能读取到已经提交的数据
D.可重复读(Repeated Read):在同一个事务内的查询都是事务开始时刻一致的
答案ABCD
并发与事务隔离:
并发: 丢失更新,脏读,非重复读,覆盖更新,幻想读
事务隔离: 未提交读,已提交读,可重复读,串行化。
1、更新丢失: 一个事物的更新覆盖了另一个事务的更新
2、脏读: 一个事务读取了另一个事务未提交的数据
3、不可重复读:一个事务两次读取同一个数据两次读取的数据不一致
4、幻象读: 一个事务两次读取一个范围的记录,两次读取的记录数不一致
未提交读: 一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新
已提交读: 一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新
可重复读: 一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务已经提交的对已有记录的更新
串行化: 一个事务在执行过程中可以看到其他事务对数据库所做的更新(事务执行的时候不允许别的是并发执行。事务串行化执行,事务只能一个接一个的执行,而不能并发执行)
二、下列选项给出的是从根分别到达两个叶结点路径上的权值序列,能属于同一棵哈夫曼树的是_______。
A.24,10,5和24,10,7
B.24,10,5和24,12,7
C.24,10,10和24,14,11
D.24,10,5和24,14,6
解析:正确答案D
在哈夫曼树中,左右孩子权值之和为父节点权值。仅以分析选项A为例:若两个10分别属于两棵不同的子树,根的权值不等于其他孩子的权值和,不符;若两个10属同棵子树,其权值不等于其两个孩子(叶节点)的权值和,不符。B、C选项的排除方法一样。
三、平均情况下,以下排序算法中,各自的时间复杂度分别是?直接插入排序、冒泡排序、快速排序、堆排序
答案:O(n2),O(n2),O(nlog2n),O(nlog2n)
解析:
直接插入排序:
直接插入排序算法是一个对少量元素进行排序的有效算法。插入排序的工作原理与打牌时整理手中的牌的做法类似,开始摸牌时,我们的左手是空的,接着一次从桌上摸起一张牌,并将它插入到左手的正确位置。为了找到这张牌的正确位置,要将它与手中已有的牌从右到左进行比较,无论什么时候手中的牌都是排序好的。
例子:插入排序的过程可以联想到打扑克时揭一张牌然后将其到手中有序纸牌的合适位置上。比如我现在手上的牌是7、8、9、J、Q、K,这时揭了一张10,我需要将其依次与K、Q、J、9、8、7比较,当比到9时发现大于9,于是将其插入到9之后。对于一个无序序列,可以将其当做一摞待揭的牌,首先将首元素揭起来,因为揭之前手上无牌,因此此次揭牌无需比较,此后每揭一次牌都需要进行上述的插牌过程,当揭完之后,手上的握牌顺序就对应着该序列的有序形式
冒泡排序:
通过相邻两个元素之间的比较和交换,使较大的元素逐渐从前面移向后面(升序),就像水底下的气泡一样逐渐向上冒泡,所以被称为“冒泡”排序。
算法步骤:
比较相邻元素,如果第一个比第二个大就交换;
对每一个相邻的元素进行同样的工作,从开始直到最后一对,通过比较最大的数据会跑到本次的最后位置;
针对所有的元素进行同样的操作;
直到没有任何一对数字需要比较时排序结束。
时间复杂度:若原数组本身就是有序的(这是最好情况),仅需n-1次比较就可完成,时间复杂度依然为O(n);若是倒序,比较次数为 n-1+n-2+…+1=n(n-1)/2,交换次数和比较次数等值。
所以,其时间复杂度依然为O(n^2)
空间复杂度:使用常数个辅助单元:O(1)
稳定性:由于i>jA[i] = A[j]时, 不会发生交换,因此冒泡排序是一种稳定的排序方法。
快速排序:
快速排序(Quick Sort) 是对冒泡排序的一种改进方法,在冒泡排序中,进行元素的比较和交换是在相邻元素之间进行的,元素每次交换只能移动一个位置,所以比较次数和移动次数较多,效率相对较低。而在快速排序中,元素的比较和交换是从两端向中间进行的,较大的元素一轮就能够交换到后面的位置,而较小的元素一轮就能交换到前面的位置,元素每次移动的距离较远,所以比较次数和移动次数较少,速度较快,故称为“快速排序”。
快速排序的基本思想是:
在待排序的元素任取一个元素作为基准(通常选第一个元素,但最的选择方法是从待排序元素中随机选取一个作为基准),称为基准元素;
将待排序的元素进行分区,比基准元素大的元素放在它的右边,比其小的放在它的左边;
对左右两个分区重复以上步骤直到所有元素都是有序的。
平均时间复杂度:O(Nlog(N))
最坏时间复杂度:O(NN):一般当数据有序或者局部有序的时候会出现这种坏的情况,比如数组正序或者逆序,(数字完全相同的时候也是有序的特殊情况)。
空间复杂度: O(log(N))
稳定性:不稳定排序,在划分算法中,若右端区间有两个关键字相同,且均小于基准值的记录,则在交换到左端区间后,它们的相对位置会发生变化,即快速排序是一种不稳定的排序方法。例如,表L={3,2,2},经过一趟排序后L= {2, 2,3}, 最终排序序列也是L= {2,2,3},显然,2与2的相对次序已发生了变化。
堆排序:
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
每个结点的值都大于其左孩子和右孩子结点的值,称之为大根堆;
每个结点的值都小于其左孩子和右孩子结点的值,称之为小根堆。
四、现有【员工】表,其字段有:在职状态、部门、员工编号,求在职员工人数大于100的部门,以下sql正确的是()
答案:D、SELECT部门,COUNT(员工编号) FROM 员工 WHERE 在职状态=”在职“ GROUP BY 部门 HAVING COUNT(员工编号) > 100
五、栈a和队列B的初始状态为空,元素Q1,Q2,Q3,Q4,Q5,Q6依次压入栈A,一个元素出栈后即进入队列B,若出队列的顺序为Q2,Q4,Q3,Q6,Q5,Q1则栈a的容量要求最小值为
答案:3
分析:0
栈后进先出,队列先进先出。给定出栈顺序:E2,E4,E3,E6,E5,E1,E2要进栈,所以E1必须进栈,进栈顺序:E1,E2,所以s为2下面E2出栈,打印出E2,剩余结果为E4,E3,E6,E5,E1,因为E2出栈了,所以当前栈容量为2,但是只是用了1个,存放E1,下面继续E3进栈,E4进栈,此时s为3,根据出栈结果,那么E4出栈,E3出栈,此时栈容量为3但是只有E1在栈中,剩余结果为E6,E5,E1,同理,E5进栈,E6进栈,此时栈被填满,容量为3,后E6出栈,E5出栈,E1出栈,栈空,容量为3.所以S的容量至少为3.
六、现有一个包含m个节点的三叉树,即每个节点都有3个指向孩子节点的指针,请问:在这3m个指针中有(b)个空指针
A.2m
B.2m+1
C.2m-1
D.3m
答案
B.2m+1
解析:m个节点有m-1个非空指针,其余皆为空指针,故3m-(m-1)=2m+1
七、T(n) = T(n - 1) + n(n为正整数)及T(0) = 1, 则算法的时间复杂度为()
A: O(log n)
B:O(nlog n)
C:O(n)
D: O(n^2)
【解析】 最常考的时间复杂度类型题,计算时记住两点: “代回”和“化简” 因为T(n)=T(n-1)+n…… (1) 由(1)式可知 T(n-1)= T(n - 2 ) + (n - 1)。 代回原式得到T(n) = T(n-2)+(n-1)+ n (2) 继续由(1)式可知T(n - 2) = T(n - 3) +(n - 2). 代入(2)式得到 T(n) = T(n - 3) + (n - 2) + (n - 1) + n. 重复这个过程,知道找到等号右侧的规律。较复杂的式子需要适当化简,但不要彻底化简。 直接写题目给定的出口,本题是T(0) = 1 按照上边找到的规律,补全式子: T(n) - T(0) + 1 + 2+3+……+(n-2)+(n-1) + n = 1 + n(n + 1)/ 2 (高斯求和公式) T(n)的最高阶项是O(n^2)。
八、简述TCP协议的三次握手和四次挥手并说明为什么要第四次挥手
三次握手原理:
第1次握手:客户端发送一个带有SYN(synchronize)标志的数据包给服务端;
第2次握手:服务端接收成功后,回传一个带有SYN/ACK标志的数据包传递确认信息,表示我收到了;
第3次握手:客户端再回传一个带有ACK标志的数据包,表示我知道了,握手结束。
其中:SYN标志位数置1,表示建立TCP连接;ACK标志表示验证字段。
四次挥手
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
四次挥手原理:
第1次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态;
第2次挥手:服务端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务端进入CLOSE_WAIT状态;
第3次挥手:服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态;
第4次挥手:客户端收到FIN后,客户端t进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。
其中:FIN标志位数置1,表示断开TCP连接。
三次握手是为了建立可靠的数据传输通道,四次挥手则是为了保证等数据完成的被接收完再关闭连接。既然提到需要保证数据完整的传输完,那就需要保证双方都达到关闭连接的条件才能断开。
九、编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果 n=2,移位后应该是“hiabcdefgh”
正确解答1:
void LoopMove ( char *pStr, int steps )
{
int n = strlen( pStr ) - steps;
char tmp[MAX_LEN];
strcpy ( tmp, pStr n );
strcpy ( tmp steps, pStr);
*( tmp strlen ( pStr ) ) = '\0';
strcpy( pStr, tmp );
}
正确解答2:
void LoopMove ( char *pStr, int steps )
{
int n = strlen( pStr ) - steps;
char tmp[MAX_LEN];
memcpy( tmp, pStr n, steps );
memcpy(pStr steps, pStr, n );
memcpy(pStr, tmp, steps );
}
十、 给定一个单链表,查找链表中倒数第n个节点。
穷举遍历(两次遍历)
先遍历一遍链表,确定链表中节点的个数l。然后再遍历一遍链表,从前往后第(l-n+1)个节点就是倒数第n个节点。
public ListNode nthToLast(ListNode head,int n){
ListNode first = head;
int length = 0;
while(first != null){
length++;
first = first.next;
}
first = head;
for(int i = 0; i < length-n+1; i++){
first = first.next;
}
return first;
}
双指针(一次遍历)
设置两个指针,第一个指针从头结点向前走到第n-1个节点时,第二个指针开始从头结点出发。当第一个指针走到尾结点时,第二个指针的位置即为倒数第n个节点。
public ListNode nthToLast(ListNode head,int n){
ListNode first = head;
ListNode second = head;
for(int i = 0; i <= n-1; i++){
//第一个指针开始遍历,保证输入的n值小于链表的长度
first = first.next;
}
//第二个指针开始遍历
while(first.next != null){
first = first.next;
second = second.next;
}
return second;
}