GESP6 · 2025年3月真题

客观题逐题精讲

15 道单选 + 10 道判断。每题保留题干、选项、答案、考点、分步推导和易错提醒,适合投影讲评与课后复习。

一、考点地图

0/1 背包状态转移方程1 题
动态规划求找零最优解1 题
动态规划算法性质1 题
二叉排序树(BST)的插入操作1 题
二叉排序树(BST)的极值性质1 题
二叉树的递归遍历顺序1 题
二叉树的广度优先搜索(BFS)1 题
二叉树中序遍历的递归实现1 题
非递归 DFS 与栈的应用1 题
格雷码的编码规律1 题
格雷码的递归构造规律(镜像法)1 题
构造函数与拷贝构造函数的区别1 题

二、单选题逐题讲

单选题 1类与对象的定义及特性

在面向对象编程中,类是一种重要的概念。下面关于类的描述中,不正确的是()。

  1. A类是一个抽象的概念,用于描述具有相同属性和行为的对象集合。
  2. B类可以包含属性和方法,属性用于描述对象的状态,方法用于描述对象的行为。
  3. C类可以被实例化,生成具体的对象。
  4. D类一旦定义后,其属性和方法不能被修改或扩展。
展开解析
答案:D
类与对象的定义及特性
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 类是抽象模板,对象是具体实例。
  2. 类定义后可以通过继承进行扩展(子类增加属性/方法)或通过多态重写方法,D项称“不能修改或扩展”违背了面向对象的开放封闭原则。
易错点:混淆类定义的静态性与面向对象的可扩展性(继承)。
单选题 2哈夫曼树的构造规则

哈夫曼编码是一种数据压缩算法。以下关于哈夫曼编码的描述中,不正确的是()。

  1. A哈夫曼编码是一种变长编码,频率高的字符使用较短的编码,频率低的字符使用较长的编码。
  2. B在构造哈夫曼树时,频率越低的字符离根节点越近,频率越高的字符离根节点越远。
  3. C哈夫曼编码的生成过程基于贪心算法,每次选择频率最低的两个节点进行合并。
  4. D哈夫曼编码是一种前缀编码,任何一个字符的编码都不会是另一个字符编码的前缀,因此可以实现唯一解码。
展开解析
答案:B
哈夫曼树的构造规则
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 哈夫曼树构造时,权值越大的节点越靠近根节点(路径越短),从而使总带权路径长度最小。
  2. B项称“频率越低离根越近”与贪心合并原则相反。
易错点:错误记忆权值大小与到根节点路径长度的正反比关系。
单选题 3二叉树的递归遍历顺序

以下代码实现了树的哪种遍历方式?

void traverse(TreeNode* root) {
    if (root == nullptr) return;
    cout << root->val << " ";
    traverse(root->left);
    traverse(root->right);
}
  1. A前序遍历
  2. B中序遍历
  3. C后序遍历
  4. D层次遍历
展开解析
答案:A
二叉树的递归遍历顺序
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 代码先输出当前节点的值 cout << root->val,再递归访问左子树和右子树,遵循“根-左-右”的顺序,符合前序遍历定义。
易错点:未能通过访问操作(cout)相对于递归调用的位置判断遍历类型。
单选题 4完全二叉树的层序遍历特性

以下关于完全二叉树的代码描述,正确的是()。

bool isCompleteTree(TreeNode* root) {
    if (root == nullptr) return true;

    queue<TreeNode*> q;
    q.push(root);
    bool hasNull = false;
    while (!q.empty()) {
        TreeNode* node = q.front();
        q.pop();
        if (node == nullptr) {
            hasNull = true;
        } else {
            if (hasNull) return false;
            q.push(node->left);
            q.push(node->right);
        }
    }
    return true;
}
  1. A该代码用于判断一棵树是否为满二叉树
  2. B该代码用于判断一棵树是否为完全二叉树
  3. C该代码用于判断一棵树是否为二叉搜索树
  4. D该代码用于计算树的高度
展开解析
答案:B
完全二叉树的层序遍历特性
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 代码通过队列 BFS 遍历,用 hasNull 记录是否出现过空节点。
  2. 完全二叉树要求节点连续填充,若遇到空节点后再次出现非空节点,则不是完全二叉树。
易错点:混淆完全二叉树(节点连续)与满二叉树(每层全满)的判定逻辑。
单选题 5二叉排序树(BST)的插入操作

以下代码实现了二叉排序树的哪种操作?

TreeNode* op(TreeNode* root, int val) {
    if (root == nullptr) return new TreeNode(val);
    if (val < root->val) {
        root->left = op(root->left, val);
    } else {
        root->right = op(root->right, val);
    }
    return root;
}
  1. A查找
  2. B插入
  3. C删除
  4. D遍历
展开解析
答案:B
二叉排序树(BST)的插入操作
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 代码中 new TreeNode(val) 表明在找到空位置时创建新节点,并根据 val 与当前节点值的大小关系决定向左或向右递归挂载。
  2. 这是典型的 BST 插入过程。
易错点:将带有节点创建逻辑的插入操作误认为单纯的查找。
单选题 6哈夫曼树的构造过程

给定字符集 {A, B, C, D} 的出现频率分别为 {5, 1, 6, 2},则正确的哈夫曼编码是()。

  1. AA: 0, B: 100, C: 11, D: 101
  2. BA: 11, B: 100, C: 0, D: 101
  3. CA: 0, B: 101, C: 11, D: 100
  4. DA: 10, B: 101, C: 0, D: 100
展开解析
答案:B
哈夫曼树的构造过程
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 合并过程:1.合并最小的B(1)和D(2)得3;
  2. 2.合并新节点3和A(5)得8;
  3. 3.合并8和C(6)得14。
  4. 由此得路径长度:C(1位), A(2位), B和D(3位)。
  5. 选项B符合此长度规律。
易错点:未按贪心原则始终合并当前频率最小的两个节点。
单选题 7动态规划算法性质

关于动态规划的描述,正确的是()。

  1. A动态规划算法的时间复杂度总是低于贪心算法。
  2. B动态规划要求问题必须具有最优子结构和重叠子问题两个性质。
  3. C动态规划通过递归实现时不需要存储中间结果。
  4. D动态规划的核心思想是将问题分解为互不重叠的子问题。
展开解析
答案:B
动态规划算法性质
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 动态规划核心特征:1.最优子结构(原问题最优解包含子问题最优解);
  2. 2.重叠子问题(子问题被反复计算)。
  3. 不重叠子问题是分治法的特征,而非动态规划。
易错点:混淆动态规划与分治法在子问题重叠性上的区别。
单选题 8构造函数与拷贝构造函数的区别

以下代码中,类的构造函数被调用了()次。

class MyClass {
    public:
        MyClass() {
            cout << "Constructor called!" << endl;
        }
};

int main() {
    MyClass obj1;
    MyClass obj2 = obj1;
    return 0;
}
  1. A1
  2. B2
  3. C3
  4. D0
展开解析
答案:A
构造函数与拷贝构造函数的区别
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. MyClass obj1; 调用默认构造函数,输出一次。
  2. MyClass obj2 = obj1; 属于拷贝初始化,调用的是拷贝构造函数,而非默认构造函数,因此不会产生该输出。
易错点:误认为 obj2 = obj1 是赋值语句,或认为拷贝初始化也会触发默认构造函数。
单选题 9循环队列的入队(enQueue)原理

以下代码实现了循环队列的哪种操作?

class CircularQueue {
    int* arr;
    int front, rear, size;
    public:
        CircularQueue(int k) {
            size = k;
            arr = new int[k];
            front = rear = -1;
        }
        bool enQueue(int value) {
            if (isFull()) return false;
            if (isEmpty()) front = 0;
            rear = (rear + 1) % size;
            arr[rear] = value;
            return true;
        }
    };
}
  1. A入队
  2. B出队
  3. C查看队首元素
  4. D判断队列是否为空
展开解析
答案:A
循环队列的入队(enQueue)原理
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 代码中 rear = (rear + 1) % size 实现了尾指针在数组中的循环后移,随后 arr[rear] = value 存入新数据,这符合循环队列入队操作的特征。
易错点:无法根据 rear 指针的更新方式识别其为入队而非出队操作。
单选题 10非递归 DFS 与栈的应用

以下代码实现了二叉树的深度优先搜索(DFS),并统计叶子结点的数量,则横线上应填写()。

int countLeafNodes(TreeNode* root) {
    if (root == nullptr) return 0;

    stack<TreeNode*> s;
    s.push(root);
    int count = 0;
    while (!s.empty()) {
        TreeNode* node = s.top();
        s.pop();

        if (node->left == nullptr && node->right == nullptr) {
            count++;
        }

        if (node->right) s.push(node->right);
            // 在此处填入代码
    }
    return count;
}
  1. Aif (node->left) s.push(node->left);
  2. Bif (node->left) s.pop(node->left);
  3. Cif (node->left) s.front(node->left);
  4. Dif (node->left) s.push(node->right);
展开解析
答案:A
非递归 DFS 与栈的应用
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 非递归 DFS 利用栈实现,访问完父节点后需将其子节点压入栈中。
  2. 代码已将右孩子入栈,横线处应补充左孩子的入栈逻辑,即 if (node->left) s.push(node->left);
易错点:误选 popfront 等不属于栈压入操作或不符合 DFS 逻辑的选项。
单选题 11二叉树的广度优先搜索(BFS)

以下代码实现了二叉树的广度优先搜索(BFS),并查找特定值的节点,则横线上应填写()。

TreeNode* findNode(TreeNode* root, int target) {
    if (root == nullptr) return nullptr;
    queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        TreeNode* current = q.front();
        q.pop();
        if (current->val == target) {
            return current; // 找到目标节点
        }
        // 在此处填入代码
    }
    return nullptr;
}
if (current->left) q.push(current->left);
if (current->right) q.push(current->right);
if (current->left) q.pop(current->left);
if (current->right) q.pop(current->right);
if (current->left) q.front(current->left);
if (current->right) q.front(current->right);
if (current->left) q.push(current->right);
if (current->right) q.push(current->left);
  1. Aif (current->left) q.push(current->left); if (current->right) q.push(current->right);
  2. Bif (current->left) q.pop(current->left); if (current->right) q.pop(current->right);
  3. Cif (current->left) q.front(current->left); if (current->right) q.front(current->right);
  4. Dif (current->left) q.push(current->right); if (current->right) q.push(current->left);
展开解析
答案:A
二叉树的广度优先搜索(BFS)
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. BFS 利用队列按层级访问节点。
  2. 从队列弹出当前节点后,需将其存在的左右子节点按序加入队尾(push),以便在后续轮次中访问下一层。
易错点:在 BFS 框架中混淆了入队(push)与出队(pop/front)的操作语义。
单选题 12格雷码的递归构造规律(镜像法)

以下代码用于生成 n 位格雷编码。横线上应填写()。

vector<string> generateGrayCode(int n) {
    if (n == 0) return {"0"};
    if (n == 1) return {"0", "1"};

    vector<string> prev = generateGrayCode(n - 1);
    vector<string> result;

    for (string s : prev) {
        result.push_back("0" + s); // 在前缀添加 0
    }
    for (int i = prev.size() - 1; i >= 0; i--) {
        // 在此处填入代码
    }
    return result;
}
  1. Aresult.push_back("1" + prev[i]);
  2. Bresult.push_back("0" + prev[i]);
  3. Cresult.push_back(prev[i] + "1");
  4. Dresult.push_back(prev[i] + "0");
展开解析
答案:A
格雷码的递归构造规律(镜像法)
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 构造n位格雷码常基于n-1位:先在前缀加'0',再将n-1位序列逆序排列后前缀加'1'。
  2. 代码中循环从 prev.size()-1 递减,对应逆序加'1'的操作。
易错点:忽略了第二个循环的逆序特征,或混淆了格雷码构造的前缀添加规则。
单选题 130/1 背包状态转移方程

以下代码实现了0/1背包问题的动态规划解法。假设物品重量为 weights[],价值为 values[],背包容量为 W,横线上应填写()。

int knapsack(int W, vector<int>& weights, vector<int>& values) {
    int n = weights.size();
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= W; j++) {
            if (weights[i-1] > j) {
                dp[i][j] = dp[i-1][j]; // 当前物品装不下
            } else {
                dp[i][j] = max(____); // 在此处填入代码
            }
        }
    }
    return dp[n][W];
}
  1. Adp[i-1][j], values[i-1]
  2. Bdp[i-1][j], dp[i-1][j - weights[i-1]] + values[i-1]
  3. Cdp[i][j-1], values[i-1]
  4. Ddp[i-1][j - weights[i-1]] + values[i-1], dp[i][j-1]
展开解析
答案:B
0/1 背包状态转移方程
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 当第 i 件物品能装下时,最大价值取“不选(dp[i-1][j])”与“选中(扣除重量后的前一状态价值 dp[i-1][j-weights[i-1]] 加上该物价值)”的较大值。
易错点:混淆 0/1 背包与完全背包,在转移时错误引用当前行 dp[i] 的状态。
单选题 14栈在符号匹配中的应用

以下代码用于检查字符串中的括号是否匹配,横线上应填写()。

bool isBalanced(string s) {
    stack<char> st;
    for (char c : s) {
        if (c == '(' || c == '[' || c == '{') {
            st.push(c);
        } else {
            if (st.empty()) return false; // 无左括号匹配
            char top = st.top();
            st.pop();
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                    return false;
            }
        }
    }
    return _____; //在此处填入代码
}
  1. Atrue
  2. Bfalse
  3. Cst.empty()
  4. D!st.empty()
展开解析
答案:C
栈在符号匹配中的应用
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 括号匹配成功不仅要求遍历中每个右括号都能找到对应的左括号弹出,还要求遍历结束后栈为空(没有孤立的左括号)。
  2. 故应返回 st.empty()
易错点:只关注遍历过程中的校验,忽略了遍历结束后栈中可能仍残留左括号的情况。
单选题 15面向对象的多态与向上转型

关于下面代码,说法错误的是()。

class Shape {
protected:
    string name;

public:
    Shape(const string &n) : name(n) {}

    virtual double area() const { return 0.0; }
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(const string& n, double r) : Shape(n), radius(r) {}
    double area() const override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double width; // 宽度
    double height; // 高度
public:
    Rectangle(const string& n, double w, double h) : Shape(n), width(w), height(h) {}
    double area() const override {
        return width * height;
    }
};

int main() {
    Circle circle("MyCircle", 5.0);
    Rectangle rectangle("MyRectangle", 4.0, 6.0);

    Shape* shapePtr = &circle;
    cout << "Area: " << shapePtr->area() << endl;

    shapePtr = &rectangle;
    cout << "Area: " << shapePtr->area() << endl;

    return 0;
}
  1. A语句 Shape* shapePtr = &circle; 和 shapePtr = &rectangle; 出现编译错误
  2. BShape 为基类,Circle 和 Rectangle 是派生类
  3. C通过继承,Circle 和 Rectangle 复用了 Shape 的属性和方法,并扩展了新的功能
  4. DCircle 和 Rectangle 通过重写(override)基类的虚函数 area 和基类指针,实现了运行时多态
展开解析
答案:A
面向对象的多态与向上转型
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. C++ 中基类指针可以合法地指向其派生类对象(向上转型),这是多态的核心实现手段,编译器完全支持。
  2. 因此 A 项描述“出现编译错误”是错误的。
易错点:对派生类对象与基类指针之间的赋值兼容性缺乏理解。

三、判断题逐题讲

判断题 1哈夫曼树的定义与性质

哈夫曼树在构造过程中,每次合并权值最小的两个节点,最终生成的树带权路径长度最小。

  1. 正确正确
  2. 错误错误
展开解析
答案:正确
哈夫曼树的定义与性质
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 哈夫曼树通过贪心策略不断合并当前权值最低的节点,确保了所有叶子节点的带权路径长度(WPL)达到最小,是理论上的最优二叉树。
易错点:误认为哈夫曼树必须是完全二叉树或平衡二叉树。
判断题 2格雷码的编码规律

格雷编码的相邻两个编码之间必须有多位不同,以避免数据传输错误。

  1. 正确正确
  2. 错误错误
展开解析
答案:错误
格雷码的编码规律
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 格雷码的核心设计初衷是相邻编码之间仅有“一位”不同,旨在通过减少电平跳变位来降低信号传输过程中的状态不稳定性和错误率。
易错点:将格雷码误认为是某种为了增加区分度而让位差尽可能大的编码。
判断题 3搜索算法与辅助数据结构

在树的深度优先搜索(DFS)中,使用队列作为辅助数据结构以实现“先进后出”的访问顺序。

  1. 正确正确
  2. 错误错误
展开解析
答案:错误
搜索算法与辅助数据结构
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. DFS 遵循“先进后出”原则,非递归实现必须使用栈(Stack)。
  2. 队列遵循“先进先出”,是实现广度优先搜索(BFS)的核心工具。
易错点:混淆了栈与队列在不同遍历策略中的应用。
判断题 4二叉树中序遍历的递归实现

以下代码实现的是二叉树的中序遍历:

void traverse(TreeNode* root) {
    if (root == nullptr) return;
    traverse(root->left);
    cout << root->val << " ";
    traverse(root->right);
}
  1. 正确正确
  2. 错误错误
展开解析
答案:正确
二叉树中序遍历的递归实现
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 代码中的输出语句 cout 位于两次递归调用之间,执行顺序为:左子树 -> 根节点 -> 右子树,这完全符合中序遍历的定义。
易错点:未能通过 cout 在递归代码段中的相对位置识别遍历顺序。
判断题 5C++ 构造函数重载规则

C++ 支持构造函数重载,但默认无参数的构造函数只能有一个。

  1. 正确正确
  2. 错误错误
展开解析
答案:正确
C++ 构造函数重载规则
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 函数重载要求参数列表不同。
  2. 无参构造函数的签名是唯一的,因此一个类内不可能同时定义两个不带参数的默认构造函数,否则会导致调用歧义。
易错点:认为只要函数体内容不同,同参数列表(或无参数)的构造函数也可以并存。
判断题 6二叉排序树(BST)的极值性质

二叉排序树(BST)中,若某节点的左子树为空,则该节点一定是树中的最小值节点。

  1. 正确正确
  2. 错误错误
展开解析
答案:错误
二叉排序树(BST)的极值性质
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. BST 的最小值位于整棵树“最左边”的节点。
  2. 仅左子树为空只能说明它是局部最小值,若该节点是父节点的右子树根,则其父节点必然更小。
易错点:将“无左孩子”片面地理解为“全树最小”,忽略了其作为右孩子时与父节点的大小关系。
判断题 7动态规划求找零最优解

在动态规划解决一维硬币找零问题时,若硬币面额为 [1, 3, 4],目标金额为 6,则最少需要 2 枚硬币 ( 3 + 3 ) (3+3)。

  1. 正确正确
  2. 错误错误
展开解析
答案:正确
动态规划求找零最优解
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 目标 6,面额 [1, 3, 4]。
  2. 动态规划通过计算发现 3+3=6 仅需 2 枚硬币,而贪心策略先选 4 后需补充两个 1(总 3 枚),证明 2 是最优解。
易错点:受贪心算法直觉干扰,错误得出需 3 枚硬币的结论。
判断题 8面向对象编程的封装性

面向对象编程中,封装是指将数据和行为绑定在一起,并对外隐藏实现细节。

  1. 正确正确
  2. 错误错误
展开解析
答案:正确
面向对象编程的封装性
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 封装将属性和方法封装在类中,并通过访问修饰符限制外部直接访问内部数据,只暴露必要接口,极大增强了系统的安全性与解耦性。
易错点:忽略封装中“隐藏实现细节”这一核心要素,误以为仅仅是代码堆叠。
判断题 9完全二叉树的结构判定

以下代码创建的树是一棵完全二叉树:

TreeNode* root = new TreeNode{1};
root->left = new TreeNode{2};
root->right = new TreeNode{3};
root->left->left = new TreeNode{4};
  1. 正确正确
  2. 错误错误
展开解析
答案:正确
完全二叉树的结构判定
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 按层序遍历该树,节点编号依次为 1(根)、2(左)、3(右)、4(2的左)。
  2. 填充顺序严格连续且无空位,完全符合完全二叉树定义。
易错点:误以为只有满二叉树(所有叶子在同一层)才是完全二叉树。
判断题 10双向链表实现栈和队列

栈和队列均可以用双向链表实现,插入和删除操作的时间复杂度为 O(1)

  1. 正确正确
  2. 错误错误
展开解析
答案:正确
双向链表实现栈和队列
思考路径:先看这是概念判断、代码阅读还是计算题;再把题干限制拆成 2-4 个小步骤,最后对照选项排除常见误区。

分步推导

  1. 双向链表通过维护首尾指针,支持在 O(1) 内完成两端的增删。
  2. 栈(一端操作)和队列(首删尾增)均可借此实现高效的常数级复杂度操作。
易错点:认为链表不支持随机访问,从而误判其首尾定向操作的时间复杂度。
答案速查表

单选题

1D2B3A4B5B6B7B8A9A10A11A12A13B14C15A

判断题

1正确2错误3错误4正确5正确6错误7正确8正确9正确10正确