软考中级-软件设计师 数据结构与算法
文章目录
- 考点
- 数据结构基础
- 线性结构
- 非线性结构
- 常见算法
- 排序算法
- 查找算法
- 递归算法
- 分治算法
- 动态规划
- 贪心算法
- 复杂度分析
考点
在软考中,数据结构与算法的考点主要集中在以下方面:
- 基本概念:掌握各类数据结构的定义、特点和应用场景。
- 常用算法的理解与应用:尤其是排序算法和查找算法的实现及复杂度分析。
- 递归与分治思想:通过实际案例理解递归和分治的原理和用法。
- 算法效率分析:理解时间复杂度和空间复杂度,能够分析给定算法的效率。
数据结构基础
数据结构是指一组数据的存储和组织方式,决定了数据的操作效率。主要包括线性结构和非线性结构,具体如下:
线性结构
线性结构的数据按顺序排列,典型的数据结构包括数组、链表、栈和队列。
- 数组:一种定长数据结构,优点是可以通过索引快速访问元素,但删除和插入操作的效率较低。
- 链表:由节点构成的链式存储结构,适合动态数据管理。链表分为单链表、双链表和循环链表,操作灵活,但需要额外的存储空间存放指针。
反转链表
#include <iostream>
using namespace std;struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* curr = head;while (curr != nullptr) {ListNode* nextTemp = curr->next;curr->next = prev;prev = curr;curr = nextTemp;}return prev;
}int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);head->next->next->next = new ListNode(4);head->next->next->next->next = new ListNode(5);ListNode* reversed = reverseList(head);while (reversed) {cout << reversed->val << " ";reversed = reversed->next;}return 0;
}
// 输出: 5 4 3 2 1
- 栈:一种“后进先出”(LIFO, Last In First Out)的数据结构,适用于递归和逆序操作。
- 队列:一种“先进先出”(FIFO, First In First Out)的数据结构,适合需要按顺序处理的场景。队列有普通队列、双端队列和循环队列等变种。
非线性结构
非线性结构的数据排列方式更为复杂,主要包括树、图等。
- 树:一种层次结构,每个节点有一个父节点和多个子节点。常见的树包括二叉树、平衡树、B树和红黑树等。树结构用于表达层级关系,适合快速查找和动态排序。
使用递归计算二叉树的深度
/* 输入1/ \2 3/ \
4 5
*/
#include <iostream>
using namespace std;struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};int maxDepth(TreeNode* root) {if (!root) return 0;int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);return max(leftDepth, rightDepth) + 1;
}int main() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);cout << "最大深度: " << maxDepth(root);return 0;
}
// 输出: 最大深度: 3
- 图:一种更加复杂的非线性结构,由顶点和边构成,可以表示节点间的多对多关系。图分为无向图和有向图,广泛应用于网络连接、地图导航等场景。
常见算法
算法是解决特定问题的步骤集合,软考中级软件设计师考试常考的算法包括排序、查找、递归、分治和贪心算法等。
排序算法
排序算法是将数据按照一定顺序排列的过程。常见的排序算法包括:
- 冒泡排序:每次相邻比较交换,复杂度为 O ( n 2 ) O(n^2) O(n2) 适用于小规模数据。是一种稳定的排序算法。
#include <iostream>
#include <vector>
using namespace std;void bubbleSort(vector<int>& arr) {int n = arr.size();for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {swap(arr[j], arr[j + 1]);}}}
}int main() {vector<int> arr = {64, 34, 25, 12, 22, 11, 90};bubbleSort(arr);for (int i : arr) cout << i << " ";return 0;
}
// 输出: 11 12 22 25 34 64 90
- 选择排序:每次选择最小(或最大)元素放到正确位置,复杂度为 O ( n 2 ) O(n^2) O(n2) 。是一种不稳定的排序算法。
#include <iostream>
#include <vector>
using namespace std;void selectionSort(vector<int>& arr) {int n = arr.size();for (int i = 0; i < n - 1; i++) {int min_index = i;for (int j = i + 1; j < n; j++) {if (arr[j] < arr[min_index]) {min_index = j;}}swap(arr[i], arr[min_index]);}
}int main() {vector<int> arr = {64, 25, 12, 22, 11};selectionSort(arr);for (int i : arr) cout << i << " ";return 0;
}
// 输出: 11 12 22 25 64
- 插入排序:每次将一个元素插入已排序的部分,复杂度为 O ( n 2 ) O(n^2) O(n2) ,对少量元素时高效。是一种稳定的排序算法。
#include <iostream>
#include <vector>
using namespace std;void insertionSort(vector<int>& arr) {int n = arr.size();for (int i = 1; i < n; i++) {int key = arr[i];int j = i - 1;while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j = j - 1;}arr[j + 1] = key;}
}int main() {vector<int> arr = {12, 11, 13, 5, 6};insertionSort(arr);for (int i : arr) cout << i << " ";return 0;
}
// 输出: 5 6 11 12 13
- 快速排序:分治算法的典型应用,通过选择“基准”将数据分割成两部分,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。是一种不稳定的排序算法,最坏的情况是数据基本有序的时候,时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
#include <iostream>
#include <vector>
using namespace std;int partition(vector<int>& arr, int low, int high) {int pivot = arr[high];int i = (low - 1);for (int j = low; j < high; j++) {if (arr[j] < pivot) {i++;swap(arr[i], arr[j]);}}swap(arr[i + 1], arr[high]);return i + 1;
}void quickSort(vector<int>& arr, int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}int main() {vector<int> arr = {3, 6, 8, 10, 1, 2, 1};quickSort(arr, 0, arr.size() - 1);for (int i : arr) cout << i << " ";return 0;
}
// 输出: 1 1 2 3 6 8 10
- 归并排序:也是分治算法,通过递归将数据不断分割、排序后合并,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。是一种稳定的排序算法。
#include <iostream>
#include <vector>
using namespace std;void merge(vector<int>& arr, int left, int mid, int right) {int n1 = mid - left + 1;int n2 = right - mid;vector<int> L(n1), R(n2);for (int i = 0; i < n1; i++) L[i] = arr[left + i];for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;}k++;}while (i < n1) arr[k++] = L[i++];while (j < n2) arr[k++] = R[j++];
}void mergeSort(vector<int>& arr, int left, int right) {if (left >= right) return;int mid = left + (right - left) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);
}int main() {vector<int> arr = {12, 11, 13, 5, 6, 7};mergeSort(arr, 0, arr.size() - 1);for (int i : arr) cout << i << " ";return 0;
}
// 输出: 5 6 7 11 12 13
- 堆排序:基于堆这种特殊的树结构进行排序,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。是一种不稳定的排序算法。
#include <iostream>
#include <vector>
using namespace std;// 调整堆,使得以i为根节点的子树满足最大堆性质
void heapify(vector<int>& arr, int n, int i) {int largest = i; // 初始化 largest 为根节点int left = 2 * i + 1; // 左子节点int right = 2 * i + 2; // 右子节点// 如果左子节点存在且大于根节点if (left < n && arr[left] > arr[largest]) {largest = left;}// 如果右子节点存在且大于当前最大节点if (right < n && arr[right] > arr[largest]) {largest = right;}// 如果最大值不是根节点,则交换并继续堆化if (largest != i) {swap(arr[i], arr[largest]);heapify(arr, n, largest);}
}// 主函数,使用堆排序对数组进行排序
void heapSort(vector<int>& arr) {int n = arr.size();// 构建最大堆for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 一个个取出元素进行排序for (int i = n - 1; i > 0; i--) {// 将当前堆顶(最大值)移到数组末尾swap(arr[0], arr[i]);// 调整剩余堆heapify(arr, i, 0);}
}int main() {vector<int> arr = {12, 11, 13, 5, 6, 7};heapSort(arr);cout << "排序后的数组: ";for (int i : arr) cout << i << " ";return 0;
}
// 输出: 5 6 7 11 12 13
查找算法
查找算法用于在数据集合中寻找特定元素,常见的查找算法有:
- 顺序查找:逐个检查每个元素,复杂度为 O(n),适用于无序数据。
#include <iostream>
#include <vector>
using namespace std;int linearSearch(const vector<int>& arr, int target) {for (int i = 0; i < arr.size(); i++) {if (arr[i] == target) {return i; // 找到目标元素,返回其索引}}return -1; // 未找到返回 -1
}int main() {vector<int> arr = {10, 20, 30, 40, 50};int target = 30;int index = linearSearch(arr, target);if (index != -1)cout << "元素 " << target << " 在索引 " << index << " 处";elsecout << "元素未找到";return 0;
}
// 输出: 元素 30 在索引 2 处
- 二分查找:要求数据有序,通过不断将搜索范围缩小一半,复杂度为 O(logn)。
#include <iostream>
#include <vector>
using namespace std;int binarySearch(const vector<int>& arr, int target) {int left = 0, right = arr.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid; // 找到目标值,返回索引}if (arr[mid] < target) {left = mid + 1; // 目标值在右半部分} else {right = mid - 1; // 目标值在左半部分}}return -1; // 未找到返回 -1
}int main() {vector<int> arr = {10, 20, 30, 40, 50};int target = 40;int index = binarySearch(arr, target);if (index != -1)cout << "元素 " << target << " 在索引 " << index << " 处";elsecout << "元素未找到";return 0;
}
// 输出: 元素 40 在索引 3 处
- 哈希查找:通过散列函数将键值直接映射到位置,查找效率高,但需要合理的哈希函数和冲突处理策略。
#include <iostream>
#include <unordered_map>
using namespace std;int hashSearch(const unordered_map<int, int>& hashTable, int target) {if (hashTable.find(target) != hashTable.end()) {return hashTable.at(target); // 找到目标值,返回索引}return -1; // 未找到返回 -1
}int main() {vector<int> arr = {10, 20, 30, 40, 50};unordered_map<int, int> hashTable;// 将数组元素存入哈希表中,键为元素值,值为索引for (int i = 0; i < arr.size(); i++) {hashTable[arr[i]] = i;}int target = 30;int index = hashSearch(hashTable, target);if (index != -1)cout << "元素 " << target << " 在索引 " << index << " 处";elsecout << "元素未找到";return 0;
}
// 输出: 元素 30 在索引 2 处
递归算法
递归是指一个函数调用自身的方式,适合解决结构相似的问题。常见的递归算法包括斐波那契数列、阶乘计算、全排列等。
递归的基本思想是将问题分解成更小的子问题。实现递归算法时,必须定义好递归出口,以避免无限递归。
分治算法
分治法将大问题分解成多个小问题分别求解,再将小问题的解合并得到原问题的解。快速排序和归并排序就是典型的分治法应用。
分治算法的一般步骤为:
- 将大问题划分为若干子问题;
- 递归解决每个子问题;
- 合并子问题的结果。
动态规划
动态规划是一种将复杂问题分解为多个子问题,通过保存子问题的解避免重复计算的策略,适合有重叠子问题和最优子结构的情况。
常见动态规划问题有背包问题、最长公共子序列、矩阵链乘法等。
贪心算法
贪心算法是一种每一步选择当前最优解的策略,适合求解一些局部最优即全局最优的问题。例如:活动选择问题、最小生成树(Prim算法和Kruskal算法)等。
复杂度分析
算法复杂度分为时间复杂度和空间复杂度。
- 时间复杂度:衡量算法执行时间随输入规模增长的变化。常见的时间复杂度有常数阶 O ( 1 ) O(1) O(1)、对数阶 O ( l o g n ) O(logn) O(logn)、线性阶 O ( n ) O(n) O(n)、平方阶 O ( n 2 ) O(n^2) O(n2) 等。
- 空间复杂度:衡量算法运行时所需的额外空间。需要在设计算法时平衡时间和空间的效率。
相关文章:
软考中级-软件设计师 数据结构与算法
文章目录 考点数据结构基础线性结构非线性结构 常见算法排序算法查找算法递归算法分治算法动态规划贪心算法 复杂度分析 考点 在软考中,数据结构与算法的考点主要集中在以下方面: 基本概念:掌握各类数据结构的定义、特点和应用场景。常用算…...
关于CSS表达使中使用的 max() 函数
定义: max() 函数:它会返回括号中给定的值中的最大值。 比如,width: max(250px, 25vw);-------它比较 250px 和 25vw,然后选择其中的较大值作为元素的宽度。 让我们逐步解析这个表达式: 250px:表示一个…...
51单片机教程(八)- 数码管的静态显示
1、项目分析 使用数码管显示指定的字符、数字和符号。 2、技术准备 1、显示器及其接口 单片机系统中常用的显示器有: 发光二极管LED(Light Emitting Diode)显示器、液晶LCD(Liquid Crystal Display)显示器、CRT显…...
案例精选 | 河北省某检察院安全运营中异构日志数据融合的实践探索
河北省某检察院是当地重要的法律监督机构,肩负着维护法律尊严和社会公平正义的重要职责。该机构依法独立行使检察权,负责对犯罪行为提起公诉,并监督整个诉讼过程,同时积极参与社会治理,保护公民权益,推动法…...
clickhouse自增id的处理
msyql 中创建数据表的时候可以通过AUTO_INCREMENT 来实现,clickhouse中可以通过其他方式来处理 一、 默认值 创建表时可以实用默认值,该列值可以自动递增。如下所示 CREATE TABLE my_table ( id UInt32 DEFAULT IDENTITY(AUTO_INCREMENT), name Strin…...
国内读新加坡公立大学在职博士是一种怎样的体验?还中文授课
国内读新加坡公立大学在职博士是一种怎样的体验?还中文授课 在国内享受国际化教育体系,这样的优势无论在学术和职业发展上,还是在个人综合素质和拓宽国际视野方面,都是无法抗拒的诱惑。当下这所新加坡公立大学就给了国内在职人员…...
linux 配置core
在Linux系统中,当一个程序崩溃时,系统可以生成一个名为"core dump"的文件。这个文件包含了程序崩溃时的内存映像,可以用来调试和确定程序崩溃的原因。生成core dump文件的功能是由内核配置的,可以通过多种方式来控制这个…...
postcss-loader运行报错
解决方案: 1、检查postcss和postcss-cssloader相关依赖 npm list postcss postcss-loader 2、原因: 你的依赖中存在 PostCSS 的版本冲突: 3、结局方案: 升级整个工具链到新版本(推荐): npm…...
智能存储解决方案:探索 TDengine 的多级存储功能
在当今数据驱动的时代,如何高效地存储和管理海量数据已成为企业面临的一大挑战。为了应对这一需求,TDengine Enterprise 不仅支持使用对象存储(S3),还早已引入了独特的多级存储功能。这一功能不仅能够降低存储成本&…...
Vue 3 中Pinia状态管理库的使用方法总结
Pinia 是 Vue 3 的状态管理库,旨在替代 Vuex,提供更简洁和更灵活的 API。以下是如何在 Vue 3 项目中使用 Pinia 的详细步骤。 1. 安装 Pinia 首先,你需要在你的 Vue 3 项目中安装 Pinia。你可以使用 npm 或 yarn 进行安装: npm…...
劫持微信聊天记录并分析还原 —— 访问数据库并查看聊天记录(五)
本工具设计的初衷是用来获取微信账号的相关信息并解析PC版微信的数据库。程序以 Python 语言开发,可读取、解密、还原微信数据库并帮助用户查看聊天记录,还可以将其聊天记录导出为csv、html等格式用于AI训练,自动回复或备份等等作用。下面我们…...
vue3+vite 前端打包不缓存配置
最近遇到前端部署后浏览器得清缓存才能出现最新页面效果得问题 所以…按以下方式配置完打包就没啥问题了,原理很简单就是加个时间戳 /* eslint-disable no-undef */ import {defineConfig, loadEnv} from vite import path from path import createVitePlugins from…...
Dinky控制台:利用SSE技术实现实时日志监控与操作
1、前置知识 1.1 Dinky介绍 实时即未来,Dinky 为 Apache Flink 而生,让 Flink SQL 纵享丝滑。 Dinky 是一个开箱即用、易扩展,以 Apache Flink 为基础,连接 OLAP 和数据湖等众多框架的一站式实时计算平台,致力于流批一体和湖仓一体的探索与实践。 致力于简化Flink任务开…...
cannot locate symbol _ZTVNSt6__ndk119basic_ostringstreamIcNS_
编译正常,运行报错:cannot locate symbol _ZTVNSt6__ndk119basic_ostringstreamIcNS_ 简单记录: 1、编译ffmpeg so库,编译正常; 2、AndroidStudio建立项目,引用so库,编译正常,运行…...
SwiftUI开发教程系列 - 第4章:数据与状态管理
在 SwiftUI 中,数据与视图的绑定可以自动响应数据变化,实时更新 UI。SwiftUI 提供了多种数据管理方式,包括 @State、@Binding、@ObservedObject 和 @EnvironmentObject 等属性包装器。本章将逐一介绍这些属性包装器的用途及其最佳实践。 4.1 使用 @State 进行本地状态管理 …...
API接口:助力汽车管理与安全应用
随着汽车行业的飞速发展,越来越多的汽车管理技术被应用到交通安全和智慧交通系统中。在这一过程中,API接口起到了至关重要的作用。通过API接口,我们可以实现诸如车主身份验核、车辆信息查询等功能,从而为汽车智慧交通发展与安全应…...
聊一聊在字节跳动做项目质量改进的经验
引言 那一年,我刚毕业一年多,在第一家公司依然到了成长瓶颈期,一是不愿意频繁出差(做乙方的无奈);二是疲于每天重复的手工测试(团队缺乏技术氛围),技术上难有突破的机会…...
CSS基础概念:什么是 CSS ? CSS 的组成
什么是 CSS? CSS(层叠样式表,Cascading Style Sheets)是一种用于控制网页外观的样式表语言。通过定义样式规则,CSS 可以指定 HTML 页面中各个元素的显示方式,包括颜色、布局、字体、间距等。 与 HTML 专注…...
鸿蒙next版开发:ArkTS组件自定义事件分发详解
在HarmonyOS 5.0中,ArkTS提供了灵活的自定义事件分发机制,允许开发者对组件的事件进行细粒度的控制。自定义事件分发对于实现复杂的用户界面交互和提升用户体验至关重要。本文将详细解读如何在ArkTS中实现自定义事件分发,并提供示例代码进行说…...
计算机图形学论文 | 多边形中的点可见性快速算法
🦌🦌🦌读论文 🐨🐨摘要 针对点的可见性计算这一计算几何中的基础问题,提出一种支持任意查询点的可见多边形快速计算的基于多边形Voronoi图的点可见性算法。以与Voronoi骨架路径对应的Voronoi通道概念&…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
算法打卡第18天
从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7…...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
