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

软考中级软件设计师——数据结构篇

一、数据结构基础概念

  1. 数据结构的分类

    • 线性结构:数组、链表、栈、队列、串
    • 非线性结构:树、图、集合
    • 存储方式:顺序存储、链式存储、索引存储、散列存储 
  2. 时间复杂度与空间复杂度

    • 常见算法复杂度分析
    • 最优子结构问题(如最长公共子序列)的优化方法 

二、线性结构

1. 顺序表(数组)

  • 特点

    • 内存连续分配,支持随机访问(通过下标直接定位)。

    • 插入/删除需移动元素,效率低。

  • 操作复杂度

    • 查找:O(1)

    • 插入/删除:O(n)

  • 应用:静态数据集合,如矩阵存储。

2. 链表

  • 类型

    • 单链表:节点包含数据域 + 指向下一节点的指针。

    • 双向链表:节点含前后指针,支持双向遍历。

    • 循环链表:尾节点指针指向头节点。

  • 特点

    • 内存非连续,插入/删除效率高(仅修改指针)。

    • 查找需遍历,效率低。

  • 操作复杂度

    • 插入/删除(已知位置):O(1)

    • 查找:O(n)

  • 应用:动态数据管理,如内存池、LRU缓存。

3. 栈(Stack)

  • 特点:后进先出(LIFO),仅允许在栈顶操作。

  • 核心操作

    • push:入栈。

    • pop:出栈。

    • peek:查看栈顶元素。

  • 应用:函数调用栈、括号匹配、表达式求值(中缀转后缀)。

4. 队列(Queue)

  • 特点:先进先出(FIFO),队尾插入,队头删除。

  • 核心操作

    • enqueue(x):将元素 x 插入队尾。

    • dequeue():删除队头元素并返回。

    • front():查看队头元素(不删除)。

  • 特殊队列

             1.循环队列:利用模运算解决数组实现的“假溢出”问题。

             2.优先队列:元素按优先级出队(通常用堆实现)。

  • 应用:任务调度、广度优先搜索(BFS)。

5.串(String)

1.基本概念

属性说明
定义由零个或多个字符组成的有限序列,记为 S = "a₁a₂…aₙ"(n ≥ 0)。
术语空串:长度为0的串。
子串:串中任意连续字符组成的子序列。
存储结构顺序存储(数组)或链式存储(块链)。

 2.串的基本操作

操作描述时间复杂度
赋值将一个串复制给另一个串。O(n)
连接将两个串首尾相连。O(n + m)
求子串截取串中从位置 pos 开始的 len 个字符。O(len)
比较按字典序比较两个串的大小。O(min(n, m))
定位(模式匹配)在主串中查找子串的位置。朴素算法 O(nm),KMP算法 O(n + m)

  3.模式匹配算法

 

1. 朴素算法(Brute-Force)

  • 原理:逐个字符比较,失配时主串回溯到起始位置+1。

2. KMP算法

  • 核心思想:利用 部分匹配表(PMT) 避免主串回溯。

  • next数组:记录子串前缀与后缀的最长公共长度。

  • 构建next数组(以子串 T = "ABABC" 为例):

    子串位置01234
    字符ABABC
    next值-10012
  • 匹配过程
    主串指针 i 不回溯,子串指针 j 根据 next[j] 回退。

3.KMP算法手算next数组

步骤(子串 T = "ABABAA"):

  1. 初始化next[0] = -1next[1] = 0

  2. 递推公式

    • 若 T[k] == T[j] → next[j+1] = k + 1

    • 若不等 → k = next[k],循环直到 k = -1

子串索引

j012345
TABABAA
next[j]-100123

三、树与二叉树

1. 二叉树

  • 基本概念

    • 节点:根节点、子节点、叶子节点。

    • :节点的子树数量(二叉树每个节点度 ≤ 2)。

  • 特殊类型

    • 满二叉树:所有层节点数达到最大值。

    • 完全二叉树:最后一层节点左对齐,其他层全满。

  • 遍历方式

    • 前序遍历:根 → 左 → 右(用于复制树结构)。

    • 中序遍历:左 → 根 → 右(二叉搜索树得到有序序列)。

    • 后序遍历:左 → 右 → 根(用于释放树内存)。

    • 层次遍历:按层逐级访问(队列实现)。

2. 二叉搜索树(BST)

  • 性质:左子树节点值 ≤ 根 ≤ 右子树节点值。

  • 操作

    • 查找:类似二分查找,复杂度 O(logn)(平衡时)。

    • 插入/删除:需调整树结构以维持性质。

  • 缺点:不平衡时退化为链表,查找效率降至 O(n)。

3. 平衡二叉树(AVL树)

  • 平衡条件:任意节点左右子树高度差 ≤ 1。

  • 调整操作

    • 左旋:右子树过深时使用。

    • 右旋:左子树过深时使用。

    • 左右旋:先左旋再右旋。

    • 右左旋:先右旋再左旋。

  • 应用:需频繁查找的场景(如数据库索引)。

4. 哈夫曼树

  • 定义:带权路径长度最短的二叉树(权值大的节点靠近根)。

  • 构建步骤

    1. 将权值作为叶子节点。

    2. 每次选权值最小的两节点合并,生成新父节点(权值为子节点和)。

    3. 重复直至只剩一棵树。

  • 应用:数据压缩(哈夫曼编码)。

5. B树与B+树

  • B树

    • 特点:多路平衡搜索树,节点可包含多个关键字和子树。

    • 规则:m阶B树每个节点最多 m 棵子树,关键字数 ∈ [⌈m/2⌉-1, m-1]。

  • B+树

    • 特点:叶子节点包含所有关键字,并按链表链接。

    • 优势:适合范围查询,磁盘I/O更少。

  • 应用:数据库索引、文件系统。


四、图

1. 图的存储

  • 邻接矩阵

    • 二维数组 matrix[i][j] 表示边权。

    • 适合稠密图,空间复杂度 O(n²)。

  • 邻接表

    • 数组 + 链表,每个节点维护邻接节点列表。

    • 适合稀疏图,空间复杂度 O(n+e)。

2. 图的遍历

  • 深度优先搜索(DFS)

    • 递归或栈实现,探索尽可能深的分支。

    • 应用:拓扑排序、连通分量检测。

  • 广度优先搜索(BFS)

    • 队列实现,按层遍历。

    • 应用:最短路径(无权图)、社交网络好友推荐。

3. 最短路径算法

  • Dijkstra算法

    • 单源最短路径(无负权边)。

    • 贪心策略,每次选择距离最近的节点。

  • Floyd算法

    • 多源最短路径,动态规划思想。

    • 三重循环更新距离矩阵。

4. 最小生成树(MST)

  • Prim算法

    • 从任意顶点开始,逐步扩展边(选权值最小的边)。

    • 适合稠密图,时间复杂度 O(n²)。

  • Kruskal算法

    • 按边权升序选择,避免环。

    • 适合稀疏图,时间复杂度 O(e log e)。


五、查找与排序

1. 查找算法

分类静态查找动态查找
定义数据集合在查找过程中不发生变化(无插入、删除操作)。数据集合在查找过程中动态变化(支持插入、删除、修改操作)。
特点- 数据稳定,仅需高效查找。
- 存储结构固定(如数组)。
- 数据动态更新,需保持查找效率。
- 存储结构灵活调整(如树、链表)。
常用算法1. 顺序查找
2. 二分查找(有序表)
3. 哈希查找(静态哈希表)
1. 二叉搜索树(BST)
2. 平衡二叉树(AVL树、红黑树)
3. B树/B+树
4. 哈希表(动态扩展)
时间复杂度- 顺序查找:O(n)
- 二分查找:O(logn)
- 哈希查找:O(1)(理想情况)
- 平衡树:查找/插入/删除 O(logn)
- B树:O(log_m n)(m为阶数)
- 哈希表:平均 O(1)(冲突处理影响)

1. 顺序查找

  • 原理:逐个遍历数据元素,直到找到目标值。

  • 特点

    • 适用于无序表和顺序存储结构。

    • 时间复杂度:O(n)

  • 代码示例

    def sequential_search(arr, target):for i in range(len(arr)):if arr[i] == target:return ireturn -1

2. 二分查找(折半查找)

  • 原理:在有序表中,每次比较中间元素,缩小一半搜索范围。

  • 条件:数据必须有序,且为顺序存储结构。

  • 时间复杂度O(logn)

  • 代码示例

    def binary_search(arr, target):left, right = 0, len(arr) - 1while left <= right:mid = (left + right) // 2if arr[mid] == target:return midelif arr[mid] < target:left = mid + 1else:right = mid - 1return -1

3. 哈希查找

  • 原理:通过哈希函数将关键字映射到存储地址,直接访问。

  • 核心问题:哈希冲突(不同关键字映射到同一地址)。

  • 冲突解决方法

    • 开放定址法

      • 线性探测:冲突后依次查找下一个空位。

      • 二次探测:冲突后按平方增量跳跃查找。

    • 链地址法:冲突位置建立链表,存储所有冲突元素。

  • 时间复杂度

    • 理想情况(无冲突):O(1)

    • 最坏情况(全冲突):O(n)

  • 装填因子:

    属性说明
    定义装填因子(α) = 已存储元素数量 / 哈希表总容量
    作用衡量哈希表的“填充程度”,直接影响冲突概率和操作效率。
    理想范围开放定址法:建议 α ≤ 0.7(如Java HashMap 默认扩容阈值为0.75)。
    链地址法:可容忍 α > 1(但一般控制在0.5~1之间)。
    与性能关系- α 越大 → 冲突概率越高 → 查找/插入效率下降。
    - α 过小 → 空间浪费。
    动态调整当 α 超过阈值时,触发 扩容(Rehashing)
    1. 新建更大容量的哈希表。
    2. 重新计算所有元素的哈希值并插入。
  • 典型例题
    哈希表长度为 7,哈希函数 H(key) = key % 7,用链地址法处理冲突,插入序列 [12, 5, 19, 33]
    哈希表结构

0: 33
1: 
2: 
3: 5 → 19
4: 
5: 12
6: 

2. 排序算法

排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景
冒泡排序O(n²)O(n²)O(1)稳定小规模数据
快速排序O(n logn)O(n²)O(logn)不稳定大规模数据(需随机化)
归并排序O(n logn)O(n logn)O(n)稳定外部排序、稳定需求
堆排序O(n logn)O(n logn)O(1)不稳定实时系统、内存有限
插入排序O(n²)O(n²)O(1)稳定基本有序的小规模数据

1. 冒泡排序

  • 原理:相邻元素两两比较,将最大值“冒泡”到末尾。

  • 特点

    • 时间复杂度:O(n²)

    • 稳定性:稳定(相同元素相对位置不变)。

  • 代码示例

    def bubble_sort(arr):n = len(arr)for i in range(n-1):for j in range(n-1-i):if arr[j] > arr[j+1]:arr[j], arr[j+1] = arr[j+1], arr[j]

2. 快速排序

  • 原理:分治法,选取基准元素,将小于基准的放左边,大于的放右边,递归处理子序列。

  • 核心步骤

    1. 划分:选择基准(如第一个元素),划分左右子序列。

    2. 递归:对左右子序列重复上述步骤。

  • 时间复杂度

    • 平均:O(n logn)

    • 最坏(已有序):O(n²)

  • 稳定性不稳定(交换可能破坏相同元素顺序)。

  • 代码示例

    def quick_sort(arr):if len(arr) <= 1:return arrpivot = arr[0]left = [x for x in arr[1:] if x <= pivot]right = [x for x in arr[1:] if x > pivot]return quick_sort(left) + [pivot] + quick_sort(right)

3. 归并排序

  • 原理:分治法,将序列递归分成两半,排序后合并。

  • 核心操作合并两个有序序列

  • 时间复杂度O(n logn)

  • 稳定性稳定

  • 代码示例

    def merge_sort(arr):if len(arr) <= 1:return arrmid = len(arr) // 2left = merge_sort(arr[:mid])right = merge_sort(arr[mid:])return merge(left, right)def merge(left, right):result = []i = j = 0while i < len(left) and j < len(right):if left[i] <= right[j]:result.append(left[i])i += 1else:result.append(right[j])j += 1result.extend(left[i:])result.extend(right[j:])return result

4. 堆排序

  • 堆的类型

    • 大顶堆:每个节点的值 ≥ 其子节点的值(用于升序排序)。

    • 小顶堆:每个节点的值 ≤ 其子节点的值(用于降序排序)。

  • 存储结构

    • 堆通过 数组 实现,逻辑上是一棵完全二叉树。

    • 父子节点关系(数组下标从 0 开始):

      • 父节点索引:parent(i) = (i-1) // 2

      • 左子节点索引:left_child(i) = 2*i + 1

      • 右子节点索引:right_child(i) = 2*i + 2

  • 堆的调整

    • 下沉(Sink):从当前节点向下调整,确保子树满足堆性质。

    • 上浮(Swim):从当前节点向上调整(堆排序中较少使用)。

  • 稳定性不稳定(交换堆顶与末尾元素可能破坏相同值的顺序)。

  • 代码示例

    def heap_sort(arr):def sink(parent, length):temp = arr[parent]          # 保存父节点值child = 2 * parent + 1      # 左子节点索引while child < length:# 选择较大的子节点if child + 1 < length and arr[child] < arr[child + 1]:child += 1# 父节点 ≥ 子节点,无需调整if temp >= arr[child]:break# 子节点上移arr[parent] = arr[child]parent = childchild = 2 * parent + 1arr[parent] = temp          # 最终位置n = len(arr)# 1. 建堆(从最后一个非叶子节点开始调整)for i in range(n//2 - 1, -1, -1):sink(i, n)# 2. 排序(交换堆顶与末尾元素,调整剩余堆)for i in range(n-1, 0, -1):arr[0], arr[i] = arr[i], arr[0]  # 最大值放到末尾sink(0, i)                       # 调整堆顶元素return arr

5. 插入排序

  • 原理:将未排序元素逐个插入已排序序列的合适位置。

  • 时间复杂度O(n²)

  • 稳定性稳定

  • 代码示例

    def insertion_sort(arr):for i in range(1, len(arr)):key = arr[i]j = i - 1while j >= 0 and arr[j] > key:arr[j+1] = arr[j]j -= 1arr[j+1] = key

     

 

相关文章:

  • C++学习之打车软件—JNI终端编程业务④https协议session开发
  • Vue 3 实现 Excel 表格解析的完整指南
  • 【python实用小脚本-79】[HR转型]Excel难民到数据工程师|用Python实现CSV秒转JSON(附HRIS系统对接方案)
  • React从基础入门到高级实战:React 基础入门 - 列表渲染与条件渲染
  • 物联网 温湿度上传onenet
  • GO语言学习(九)
  • 如何在Mac 上使用Python Matplotlib
  • 网络抓包命令tcpdump及分析工具wireshark使用
  • AI架构师的新工具箱:ChatGPT、Copilot、AutoML、模型服务平台
  • Java常用数据结构底层实现原理及应用场景
  • 大文件上传如何做断点续传?(分别使用vue、React、java)
  • Scp命令使用
  • PPP 拨号失败:ATD*99***1# ... failed
  • AOP的代理模式
  • 计算机系统结构1-3章节 期末背诵内容
  • 从逻辑视角学习信息论:概念框架与实践指南
  • 软考 组合设计模式
  • 数据可视化利器 - Grafana 与 Prometheus 联手打造监控仪表盘
  • 【闲聊篇】java好丰富!
  • grafana/loki-stack 设置日志保存时间及自动清理
  • 深圳网站建设61916/青岛网站关键词排名优化
  • 蔡甸建设局网站/淘宝优化关键词的步骤
  • 彩票引流推广方法/亚马逊关键词优化怎么做
  • php动态网站开发期末考试/百度一下百度搜索百度一下
  • 国外电子政务j建设与我国电子政务网站建设对比/品牌整合营销推广
  • 网站开发什么语言比较好/湖南网站推广公司