文章目录
- 一、选择题
- 二、编程题
一、选择题
1、二叉树是非线性数据结构,所以(C )
A. 它不能用顺序存储结构存储;
B. 它不能用链式存储结构存储;
C. 顺序存储结构和链式存储结构都能存储;
D. 顺序存储结构和链式存储结构都不能使用
答案解析:C
二叉树既可以用链式存储,也可以用顺序存储,不同的类型的二叉树适合不同的存储方式;
比如完全二叉树适合顺序存储,这样比较节省空间;普通的二叉树可以用链式存储。
2、执行(B )操作时,需要使用队列作为辅助存储空间。
A. 查找哈希(hash)表
B. 层序遍历
C. 先序(根)遍历二叉树
D. 深度优先搜索图
答案解析:B
二叉树的层序遍历是从根节点开始从上到下,从左到右每一层进行遍历。
二叉树进行层序遍历时,需要利用队列的先进先出原则,将每一个结点的左孩子和右孩子依次放入队列,防止下一层节点丢失
或者结点的顺序被打乱。
3、中序遍历为abcd的二叉树可能是下面的哪棵【多选】(C D )
A.
B.
C.
D.
答案解析:C D
中序遍历就是先访问二叉树的左子树,在访问二叉树的根节点,最后访问二叉树的右子树;
A图中序遍历的结果是:dbac
B图中序遍历的结果是:cbda
C图中徐遍历的结果是:abcd
D图中徐遍历的结果是:abcd
所以选择 C D
4、关于堆数据结构,下面描述中不恰当的一项是:(D )
A. 用堆可以实现优先队列(priority_queue)
B. 使用堆可以实现排序算法,复杂度为NlogN
C. 堆是一棵完全二叉树
D. 在大顶堆的二叉树中,第N层中的所有元素比第N+1层中的所有元素都要大
答案解析:D
堆是一棵完全二叉树;
优先队列的底层实现是堆结构;
堆排序是一种经典的排序算法,时间复杂度为NlogN;
大顶堆只能保证根节点的元素值比左右子树的元素值大,但是如果某一层有很多结点,我们只能保证每一个结点满足这样的规
律,但并不意味着某一个结点的值大于其它结点的左右孩子。
5、下列关键字序列为堆的是(A )
A. 100,60,70,50,32,65
B. 60,70,65,50,32,100
C. 65,100,70,32,50,60
D. 70,65,100,32,50,60
答案解析:A
堆分为大根堆和小根堆;大根堆中每一个结点的值都大于其左右子树的值,小根堆中每一个结点的值小于其左右子树的值;
A选项中的数据序列为大根堆,按照序列
100为根节点,100的左子树为60,右子树为70,得出根节点值大于左右子树结点值
60的左子树为50,右子树为32,70的左子树为65,左子树和右子树的结点值也分别遵循大根堆的规律;所以选A
二、编程题
1、用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和
empty)。实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
OJ链接
示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
加粗样式【解题思路】:
使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元
素。入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈
的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分
别对应栈顶和栈底。由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以
简单实现。出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即
可(不移除元素)。由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。
class MyStack {
private Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
// 获取当前队列元素个数
int n = queue.size();
// 1.先入队
queue.add(x);
// 2+3.将前n个元素依次出队再入队
for (int i = 0; i < n; i++) {
queue.add(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
2、用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实
现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
OJ链接
示例:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
【解题思路】:
一个队列是 FIFO 的,但一个栈是 LIFO 的。这就意味着最新压入的元素必须得放在栈底。为了实现这个目的,我们首先需要把 s1 中所有的元素移到 s2 中,接着把新元素压入 s2。最后把 s2 中所有的元素弹出,再把弹出的元素压入s1。
class MyQueue {
// s1存储具体元素
private Stack<Integer> s1;
// s2作为辅助
private Stack<Integer> s2;
public MyQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void push(int x) {
if (s1.isEmpty()) {
s1.push(x);
}else {
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
// 直接将队尾元素入s1
s1.push(x);
// 将s2的所有元素依次出栈再入s1
while (!s2.isEmpty()) {
s1.push(s2.pop());
}
}
}
public int pop() {
return s1.pop();
}
public int peek() {
return s1.peek();
}
public boolean empty() {
return s1.isEmpty();
}
}