当前位置: 首页 > news >正文

【C++上岸】C++常见面试题目--数据结构篇(第十五期)

欢迎来到C++面试题系列的第15期!😊 数据结构是面试中的高频考点,掌握它们能帮你轻松上岸。今天,我们聚焦数据结构篇,详细解答10个常见问题。用简单易懂的语言和代码示例(C++实现)帮你理解核心概念🚀。
上岸必备!一次性搞懂八大高频考点+代码实战 🌟


文章目录

        • 🔍 1. 直接选择排序算法
        • 💦 2. 冒泡排序算法
        • ⚡ 3. 快速排序算法
        • 🌳 4. 堆排序算法
        • 🌀 5. 希尔排序算法
        • 🌿 6. 二叉树后序遍历的从后往前输出
        • 🔄 7. 自底向上的二叉树层序遍历
        • 👉 8. 二叉树的右视图
        • 🧹 9. 原地移除指定元素
        • 🔢 10. 有序数组的平方排序
      • 💎 结语


🔍 1. 直接选择排序算法

核心思想:每次从未排序序列中选最小元素,放到已排序序列末尾。
时间复杂度O(n2)O(n^2)O(n2),空间复杂度:O(1)O(1)O(1)

void selectionSort(vector<int>& arr) {for (int i = 0; i < arr.size() - 1; i++) {int minIndex = i;for (int j = i + 1; j < arr.size(); j++) {if (arr[j] < arr[minIndex]) minIndex = j; // 找最小值下标}swap(arr[i], arr[minIndex]); // 交换到有序区末尾}
}

举个栗子🌰:[5,2,9,1] → 第一轮选最小1交换 → [1,2,9,5] → 第二轮选2(已在位)→ 第三轮选5交换 → [1,2,5,9]


💦 2. 冒泡排序算法

核心思想:相邻元素两两比较,将较大元素"冒泡"到右侧。
优化点:若某轮无交换,说明已有序可提前终止!

void bubbleSort(vector<int>& arr) {for (int i = 0; i < arr.size() - 1; i++) {bool swapped = false;for (int j = 0; j < arr.size() - 1 - i; j++) {if (arr[j] > arr[j + 1]) {swap(arr[j], arr[j + 1]);swapped = true;}}if (!swapped) break; // 无交换则提前退出}
}

动图联想🎞️:像气泡从水底上升,大的数慢慢浮到右侧~


⚡ 3. 快速排序算法

分治思想:选基准(pivot),划分小于/大于基准的子数组,递归排序。
平均时间复杂度O(nlog⁡n)O(n \log n)O(nlogn)

void quickSort(vector<int>& arr, int l, int r) {if (l >= r) return;int i = l, j = r, pivot = arr[(l + r) / 2]; // 选中间为基准while (i <= j) {while (arr[i] < pivot) i++;while (arr[j] > pivot) j--;if (i <= j) swap(arr[i++], arr[j--]);}quickSort(arr, l, j); // 递归左子数组quickSort(arr, i, r); // 递归右子数组
}

面试注意❗:手写时需处理边界条件,避免死循环!


🌳 4. 堆排序算法

核心步骤

  1. 建最大堆(父节点 ≥ 子节点)
  2. 交换堆顶与末尾元素,堆大小-1
  3. 调整剩余元素为新堆
void heapify(vector<int>& arr, int n, int i) {int largest = i, l = 2 * i + 1, r = 2 * i + 2;if (l < n && arr[l] > arr[largest]) largest = l;if (r < n && arr[r] > arr[largest]) largest = r;if (largest != i) {swap(arr[i], arr[largest]);heapify(arr, n, largest);}
}void heapSort(vector<int>& arr) {for (int i = arr.size() / 2 - 1; i >= 0; i--) // 建堆heapify(arr, arr.size(), i);for (int i = arr.size() - 1; i > 0; i--) {swap(arr[0], arr[i]);     // 移堆顶到末尾heapify(arr, i, 0);       // 调整剩余堆}
}

口诀🧠:父节点i,左子2i+1,右子2i+2


🌀 5. 希尔排序算法

改进插入排序:按增量分组插入排序,增量逐轮缩小至1。
时间复杂度O(n1.3)O(n^{1.3})O(n1.3) ~ O(n2)O(n^2)O(n2)

void shellSort(vector<int>& arr) {for (int gap = arr.size() / 2; gap > 0; gap /= 2) { // 增量序列for (int i = gap; i < arr.size(); i++) {int temp = arr[i], j;for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {arr[j] = arr[j - gap]; // 组内插入排序}arr[j] = temp;}}
}

增量选择🔧:常用gap = n/2, n/4, ... 1


🌿 6. 二叉树后序遍历的从后往前输出

需求:输出顺序为右子树 → 左子树 → 根(反向后序)
解法:用栈实现根 → 右 → 左遍历,结果反转即可!

vector<int> postorderTraversal(TreeNode* root) {vector<int> res;stack<TreeNode*> stk;if (root) stk.push(root);while (!stk.empty()) {TreeNode* node = stk.top(); stk.pop();res.push_back(node->val);if (node->left) stk.push(node->left);  // 左先入栈if (node->right) stk.push(node->right); // 右后入栈(先出)}reverse(res.begin(), res.end()); // 反转得后序return res;
}

逻辑🤔:栈的LIFO特性使右子树先出,反转后符合后序要求。


🔄 7. 自底向上的二叉树层序遍历

输出要求:从最后一层向根节点逐层输出
技巧:正常BFS层序遍历,结果反转每层

vector<vector<int>> levelOrderBottom(TreeNode* root) {vector<vector<int>> res;queue<TreeNode*> q;if (root) q.push(root);while (!q.empty()) {int size = q.size();vector<int> level;for (int i = 0; i < size; i++) {TreeNode* node = q.front(); q.pop();level.push_back(node->val);if (node->left) q.push(node->left);if (node->right) q.push(node->right);}res.push_back(level);}reverse(res.begin(), res.end()); // 反转层顺序return res;
}

示例🌲:

输入:     3      自底向上输出: [[15,7], [9,20], [3]]/ \9  20/  \15   7

👉 8. 二叉树的右视图

题目:给定根节点root,返回从右侧能看到的节点值(每层最右节点)
解法:BFS层序遍历时,记录每层最后一个元素

vector<int> rightSideView(TreeNode* root) {vector<int> res;queue<TreeNode*> q;if (root) q.push(root);while (!q.empty()) {int size = q.size();for (int i = 0; i < size; i++) {TreeNode* node = q.front(); q.pop();if (i == size - 1) res.push_back(node->val); // 当前层最右节点if (node->left) q.push(node->left);if (node->right) q.push(node->right);}}return res;
}

关键点🔑:每层循环中,i == size-1时即为最右节点。


🧹 9. 原地移除指定元素

要求O(1)O(1)O(1)空间,原地移除nums中所有val
双指针法:快指针扫描,慢指针标记非val位置

int removeElement(vector<int>& nums, int val) {int slow = 0;for (int fast = 0; fast < nums.size(); fast++) {if (nums[fast] != val) {nums[slow++] = nums[fast]; // 非val元素前移}}return slow; // 新长度
}

示例📊:
nums = [3,2,2,3], val = 3 → 快指针跳过3,慢指针记录[2,2] → 返回长度2


🔢 10. 有序数组的平方排序

题目:非递减数组nums,返回平方后的非递减数组
最优解:双指针从两端向中间扫描,比较绝对值大小!

vector<int> sortedSquares(vector<int>& nums) {int n = nums.size();vector<int> res(n);int left = 0, right = n - 1, pos = n - 1; // 从后往前填充while (left <= right) {if (abs(nums[left]) > abs(nums[right])) {res[pos--] = nums[left] * nums[left];left++;} else {res[pos--] = nums[right] * nums[right];right--;}}return res;
}

为什么从后往前❓:平方后最大值只可能出现在两端(负数的平方可能很大)!


💎 结语

🎉 恭喜你完成本期的学习!数据结构是C++面试的基石,多加练习这些题目,上岸指日可待。如果有疑问,欢迎留言讨论~💪

🌟如果觉得有用,点个赞吧!👍 收藏本文,面试前翻一翻,上岸更轻松! 如果觉得有用,点赞支持一下,你的鼓励是我持续更新的动力!😊 也欢迎关注我,获取更多“C++上岸”系列干货。下期见!🚀

http://www.dtcms.com/a/322656.html

相关文章:

  • 搜索算法经典案例
  • SpringSecurity过滤器链全解析
  • navicat 连接docker容器里面mysql服务失败解决
  • 传输线的瞬时阻抗
  • UE破碎Chaos分配模型内部面材质
  • Jmeter性能测试之安装及启动Jmeter
  • Nginx 安全加固与服务监控体系
  • 如何无损压缩图片至原大小的10%?
  • ComfyUI——舒服地让大模型为我所用
  • 常用性能测试工具及使用方法介绍
  • 【内核配置】CONFIG_DEBUG_USER 配置项原理分析
  • 线程安全的单例模式,STL和智能指针
  • golang的二维数组
  • 直接插入排序算法:可视化讲解与C语言实现
  • 【R语言】单细胞数据整合质量评估(3)
  • Matlab 基于BP神经网络结合Bagging(BP-Bagging)集成算法的单变量时序预测 (单输入单输出)
  • Linux运维新手的修炼手扎之第26天
  • Effective C++ 条款31: 将文件间的编译依存关系降至最低
  • 飞算JavaAI:人工智能与Java的创新融合与应用前景
  • 5、docker镜像管理命令
  • Qt/C++开发监控GB28181系统/实时监测设备在线离线/视频预览自动重连/重新点播取流/低延迟
  • MySQL 复制表详细说明
  • 某金融APP防护检测分析
  • PromptPilot打造高效AI提示词
  • 智慧农业-无人机视角庄稼倒伏农作物倒伏检测数据集VOC+YOLO格式541张1类别
  • 计算机视觉CS231n学习(6)
  • 跨境电商系统开发:ZKmall开源商城的技术选型与代码规范实践
  • 3D感知多模态(图像、雷达感知)
  • node.js 零基础入门
  • LangChain-Unstructured 基础使用:PDF 与 Markdown 处理解析