计算机基础知识-数据结构

计算机基础知识-数据结构

第一章 数据结构基础与算法复杂度

Q1. 什么是数据结构?包含哪两个层面的结构?

标准答案:数据结构是相互之间存在一种或多种特定关系的数据元素的集合,用于组织、存储和管理数据,以支持高效的操作。它包含两个核心层面:

  • 逻辑结构:数据元素之间的抽象关系(分为线性结构、树形结构、图形结构、集合结构);
  • 存储结构(物理结构):数据在计算机内存中的存储方式(分为顺序存储、链式存储、索引存储、散列存储)。

Q2. 算法的五个基本特性是什么?

标准答案:算法是解决特定问题的有限指令序列,必须满足以下 5 个特性:

  1. 有穷性:算法执行有限步后必然终止;
  2. 确定性:每一步指令的含义唯一,无歧义;
  3. 可行性:每一步操作都能通过有限次基本运算实现;
  4. 输入:有零个或多个输入(零输入表示算法本身确定初始条件);
  5. 输出:有一个或多个输出(必须有结果反馈)。

Q3. 时间复杂度和空间复杂度的定义,如何分析?

标准答案

  • 时间复杂度:衡量算法执行时间随输入规模增长的变化趋势,记为O(f(n))O(f(n))O(f(n))(大 O 表示法),分析时只需关注执行次数最多的 "主导项",忽略常数项和低次项(如2n2+3n+12n^2+3n+12n2+3n+1的时间复杂度为O(n2))O(n^2))O(n2));
  • 空间复杂度:衡量算法运行过程中所需额外存储空间随输入规模增长的变化趋势,同样用大 O 表示法,需区分 "输入数据占用空间" 和 "额外空间"(仅统计额外空间)。
  • 常见复杂度排序(从小到大):O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)O(1)<O(log2n)<O(n)<O(nlog2n)<O(n^2)<O(n^3)<O(2^n)<O(n!)O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)。

第二章 线性表(顺序表、链表)

Q1. 顺序表和单链表的优缺点对比?

标准答案

维度 顺序表 单链表
存储方式 连续的内存空间 离散的内存空间,结点含数据域 + 指针域
访问效率 随机访问,O(1) 顺序访问,O(n)
插入 / 删除 需移动元素,平均O(n) 只需修改指针,O(1)(找到位置后)
空间利用率 预分配空间,易浪费 / 溢出 按需分配,无浪费,但指针占用额外空间
适用场景 频繁查询、元素数量固定 频繁插入 / 删除、元素数量动态变化

Q2. 如何判断单链表是否有环?如何找到环的入口结点?

标准答案

  • 判断是否有环:采用 "快慢指针法(龟兔赛跑算法)"。快指针每次走 2 步,慢指针每次走 1 步,若两指针相遇,则链表有环;若快指针走到链表尾部(指向 NULL),则无环。
  • 找环的入口结点:当快慢指针相遇后,将慢指针重置到链表头结点,快慢指针均改为每次走 1 步,再次相遇的结点即为环的入口结点。
  • 原理:设链表头到环入口的距离为aaa,环入口到相遇点的距离为bbb,环长为ccc,则相遇时快指针走了a+b+kca+b+kca+b+kc,慢指针走了a+ba+ba+b,且a+b+kc=2(a+b)a+b+kc=2(a+b)a+b+kc=2(a+b),化简得a=kc−b=(k−1)c+(c−b)a=kc−b=(k−1)c+(c−b)a=kc−b=(k−1)c+(c−b),即头到入口的距离等于相遇点绕环到入口的距离

Q3. 反转单链表的两种实现方法?

标准答案

  1. 迭代法(三指针法):定义pre(前驱)、curr(当前)、next(后继)三个指针,初始pre=NULLcurr=head;遍历链表,每次先保存curr->nextnext,再将curr->next指向pre,然后pre=currcurr=next,直到curr=NULL,最终pre为反转后的头结点。时间复杂度O(n),空间复杂度O(1)。
  2. 递归法:递归终止条件为head==NULLhead->next==NULL(返回当前结点);递归处理head->next,得到反转后的子链表头结点new_head;将head->next->next指向headhead->next=NULL,返回new_head。时间复杂度O(n),空间复杂度O(n)(递归栈开销)。

第三章 栈与队列

Q1. 栈和队列的定义、特性及核心应用场景?

标准答案

  • 栈:限定仅在表尾(栈顶)进行插入和删除操作的线性表,遵循 "先进后出(FILO)" 原则;

    核心应用:函数调用栈、括号匹配、表达式求值(中缀转后缀)、浏览器后退 / 前进、递归转迭代。

  • 队列:限定在表尾(队尾)插入、表头(队头)删除的线性表,遵循 "先进先出(FIFO)" 原则;

    核心应用:广度优先搜索(BFS)、消息队列、任务调度(如打印机排队)、缓冲区设计。


Q2. 如何用两个栈实现一个队列?

标准答案 :设计两个栈:入队栈stack_in、出队栈stack_out,核心逻辑:

  1. 入队操作:直接将元素压入stack_in
  2. 出队操作:若stack_out为空,将stack_in中的所有元素依次弹出并压入stack_out(反转顺序),再从stack_out弹出栈顶元素;若stack_out非空,直接弹出栈顶元素。
  • 时间复杂度:入队O(1),出队均摊O(1)(每个元素最多入栈和出栈各两次);空间复杂度O(n)。

Q3. 循环队列如何判断空和满?

标准答案 :循环队列采用 "牺牲一个位置" 的方式区分空和满(避免front==rear同时表示空和满):

  • 判空条件:front == rear(队头指针等于队尾指针);
  • 判满条件:(rear + 1) % maxsize == front(队尾指针的下一个位置等于队头指针,maxsize为队列最大容量)。
  • 补充:队列长度计算公式为(rear - front + maxsize) % maxsize

第四章 字符串

Q1. 朴素模式匹配(BF 算法)和 KMP 算法的区别,KMP 算法的核心思想?

标准答案

  • BF 算法:暴力匹配,主串指针iii和模式串指针jjj逐位比较,匹配失败时i回溯到i−j+1i−j+1i−j+1,jjj重置为 0;时间复杂度O(n∗m)O(n∗m)O(n∗m)(nnn为主串长度,mmm为模式串长度),效率低。
  • KMP 算法:核心是 "利用已匹配的前缀信息,避免主串指针回溯",通过预处理模式串生成next数组(记录模式串每个位置的最长相等前后缀长度),匹配失败时仅回溯模式串指针j到next[j-1],主串指针i不回溯;时间复杂度O(n+m)O(n+m)O(n+m),效率更高。
  • next数组定义:next[i]表示模式串前i+1i+1i+1个字符组成的子串中,最长的相等前缀和后缀的长度。

Q2. 如何判断一个字符串是否为回文字符串?

标准答案:采用 "双指针法":

  1. 定义左指针left(初始 0)、右指针right(初始字符串长度 - 1);
  2. 循环比较s[left]s[right]:若不相等,直接返回false;若相等,left++right--
  3. left >= right时,循环结束,返回true
  • 时间复杂度O(n)O(n)O(n),空间复杂度O(1)O(1)O(1);若允许修改字符串,也可反转字符串后对比,但空间复杂度会升至O(n)O(n)O(n)。

第五章 树与二叉树

Q1. 二叉树的核心性质?

二叉树的 5 个核心性质(均适用于任意二叉树):

  1. 第 iii 层最多有 2i−12^{i-1}2i−1 个结点 (i≥1i \ge 1i≥1);

  2. 高度为 kkk 的二叉树最多有 2k−12^k - 12k−1 个结点 (k≥1k \ge 1k≥1,满二叉树);

  3. 任意二叉树中,叶子结点数 (n0n_0n0) = 度为 2 的结点数 (n2n_2n2) + 1 (n0=n2+1n_0 = n_2 + 1n0=n2+1);

  4. 有 nnn 个结点的完全二叉树,高度为 ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1⌊log2n⌋+1;

  5. 完全二叉树中,结点 iii (从 1 开始编号) 的左孩子为 2i2i2i,右孩子为 2i+12i + 12i+1,父结点为 ⌊i/2⌋\lfloor i/2 \rfloor⌊i/2⌋。


Q2. 二叉树的四种遍历方式及实现思路?

标准答案

遍历方式 顺序 实现思路
前序遍历 根 → 左 → 右 递归:先访问根结点,再递归左子树,最后递归右子树;迭代:用栈,先压右子树再压左子树
中序遍历 左 → 根 → 右 递归:先递归左子树,再访问根结点,最后递归右子树;迭代:用栈,先遍历到左子树最深处
后序遍历 左 → 右 → 根 递归:先递归左子树,再递归右子树,最后访问根结点;迭代:用栈,标记结点是否已访问
层序遍历 按层从上到下、从左到右 用队列实现:先入队根结点,循环出队结点并访问,再入队其左、右孩子

Q3. 二叉搜索树(BST)、平衡二叉树(AVL)、红黑树的区别?

标准答案

维度 二叉搜索树(BST) 平衡二叉树(AVL) 红黑树
核心定义 左子树 < 根 < 右子树,中序遍历有序 任意结点左右子树高度差≤1 的 BST 满足 5 条规则的 BST(红黑规则)
平衡条件 无平衡要求,可能退化为单链表 严格平衡(高度差≤1) 近似平衡(黑高相同)
插入 / 删除 无需调整,O(h)(h为树高) 需旋转调整(LL/RR/LR/RL),O(logn) 需旋转 + 变色调整,O(logn)
查找效率 最好O(logn),最坏O(n) 稳定O(logn) 稳定O(logn)
应用场景 数据量小、插入删除少 查找频繁、插入删除少 插入删除频繁(如 HashMap、TreeSet)

红黑树 5 条规则:① 结点非红即黑;② 根结点为黑;③ 叶子结点(NIL)为黑;④ 红结点的孩子必为黑;⑤ 任意结点到其叶子结点的所有路径上黑结点数量相同。


Q4. B 树和 B + 树的区别,B + 树为何适合数据库索引?

标准答案

  • 核心区别:
    1. 关键字存储:B 树的所有结点(叶子 + 非叶子)都存储关键字;B + 树仅叶子结点存储关键字,非叶子结点仅存索引(指向叶子结点的指针);
    2. 叶子结点:B + 树叶子结点通过链表相连,B 树无此结构;
    3. 查询:B 树可能在非叶子结点找到关键字,B + 树必须遍历到叶子结点(查询效率稳定)。
  • B + 树适合数据库索引的原因:
    1. 非叶子结点仅存索引,内存页可存储更多关键字,减少 IO 次数;
    2. 叶子结点链表相连,支持范围查询(数据库高频操作);

​ 3. 查询效率稳定(所有查询都到叶子结点)。


第六章 图

Q1. 深度优先搜索(DFS)和广度优先搜索(BFS)的区别

标准答案

维度 深度优先搜索(DFS) 广度优先搜索(BFS)
实现方式 递归 / 栈 队列
遍历顺序 先深后广,优先遍历分支到底 先广后深,按层遍历
空间复杂度 O(h)(h为图的深度 / 树高) O(n)(n为顶点数,需存储队列)
核心应用 连通性判断、拓扑排序、找路径 无权图最短路径、层序遍历
能否找最短路径 无权图中不一定能(可能绕远路) 无权图中可找到最短路径

Q2. 最小生成树的 Prim 算法和 Kruskal 算法的区别?

标准答案

维度 Prim 算法 Kruskal 算法
核心思想 从一个顶点出发,逐步添加 "连接已选顶点和未选顶点的最小权边" 按边权从小到大排序,依次选边,避免环(用并查集判断)
处理对象 顶点
时间复杂度 O(V2)O(V^2)O(V2)(邻接矩阵)/O(ElogV)O(ElogV)O(ElogV)(邻接表 + 堆) O(ElogE)O(ElogE)O(ElogE)(排序占主导)
适用场景 稠密图(顶点少、边多) 稀疏图(顶点多、边少)

Q3. 迪杰斯特拉(Dijkstra)算法的核心思想及适用场景?

标准答案

  • 核心思想:求解"单源最短路径"(从一个源点到其他所有顶点的最短路径),基于"贪心策略":

    1. 初始化:源点到自身距离为 000,到其他顶点距离为 ∞\infty∞,标记源点为"已确定最短路径";

    2. 循环:每次从未确定的顶点中选"距离源点最近的顶点 uuu",标记为已确定;

    3. 松弛操作:更新所有与 uuu 相邻的顶点 vvv 的距离(若 dist[v]>dist[u]+w(u,v)dist[v] > dist[u] + w(u, v)dist[v]>dist[u]+w(u,v),则更新
      dist[v]=dist[u]+w(u,v) dist[v] = dist[u] + w(u, v) dist[v]=dist[u]+w(u,v));

    4. 直到所有顶点都被标记为已确定。

  • 适用场景 :无负权边的图(若有负权边,需用 Bellman-Ford 算法);时间复杂度 O(V2)O(V^2)O(V2)(邻接矩阵) / O((V+E)log⁡V)O((V + E)\log V)O((V+E)logV)(邻接表 + 堆)。


第七章 查找

Q1. 二分查找的条件、实现思路及复杂度?

标准答案

  • 适用条件:① 数据存储在顺序表中(随机访问);② 数据有序(升序 / 降序)。
  • 实现思路(升序):
    1. 定义左边界left=0,右边界right=n-1(n为数组长度);
    2. 循环:当left ≤ right时,计算中间位置mid = (left + right) / 2
    3. 比较arr[mid]和目标值:相等则返回midarr[mid] > 目标值right=mid-1arr[mid] < 目标值left=mid+1
    4. 循环结束未找到则返回 - 1。
  • 时间复杂度:O(log2n)O(log2n)O(log2n)(每次排除一半元素);空间复杂度:递归实现O(log2n)递归实现O(log2n)递归实现O(log2n),迭代实现O(1)O(1)O(1)。

Q2. 哈希表(散列表)的哈希冲突解决方法?

标准答案

哈希冲突指不同关键字通过哈希函数得到相同的哈希地址,核心解决方法分为两类:

  1. 开放地址法:冲突后在哈希表内找下一个空位置,包括:

    • 线性探测:di=id_i = idi=i(i=1,2,...i = 1, 2, \dotsi=1,2,...),即冲突后依次向后找空位置,易产生"堆积";

    • 二次探测:di=±i2d_i = \pm i^2di=±i2,避免线性探测的堆积问题,但不能遍历所有位置;

    • 双重哈希:di=i∗h2(key)d_i = i * h_2(key)di=i∗h2(key)(h2h_2h2为第二个哈希函数),冲突后按第二个哈希函数计算步长。

  2. 链地址法(拉链法):每个哈希地址对应一个链表,冲突的关键字直接插入链表尾部;无堆积问题,删除方便,是 HashMap(Java)、Python 字典的底层实现。

  • 补充:还有再哈希法(换哈希函数)、公共溢出区法(冲突元素放入溢出区),但应用较少。

第八章 排序

Q1. 快速排序的核心思想、步骤及复杂度?

核心思想:基于 "分治策略",通过一趟排序将数组分为两部分,左部分≤基准值,右部分≥基准值,再递归排序左右两部分。

实现步骤:

  1. 选基准:从数组中选一个元素作为基准(如首元素、尾元素、三数取中法);
  2. 划分:遍历数组,将≤基准的元素放左,≥基准的元素放右,基准归位;
  3. 递归:分别对左、右子数组重复上述步骤,直到子数组长度≤1。

复杂度:

  • 时间复杂度:最好O(nlogn)O(nlogn)O(nlogn),平均O(nlogn)O(nlogn)O(nlogn),最坏 O(n\^2) (数组已有序,基准选首尾);
  • 空间复杂度:O(logn)O(logn)O(logn)(递归栈,最坏O(n)O(n)O(n));
  • 稳定性:不稳定(交换时可能打乱相同元素的相对位置)。

Q2. 常见排序算法的稳定性及复杂度对比?

标准答案

排序算法 时间复杂度(最好 / 平均 / 最坏) 空间复杂度 稳定性
冒泡排序 O(n)/O(n2)/O(n2)O(n)/O(n^2)/O(n^2)O(n)/O(n2)/O(n2) O(1)O(1)O(1) 稳定
插入排序 O(n)/O(n2)/O(n2)O(n)/O(n^2)/O(n^2)O(n)/O(n2)/O(n2) O(1)O(1)O(1) 稳定
选择排序 O(n2)/O(n2)/O(n2)O(n^2)/O(n^2)/O(n^2)O(n2)/O(n2)/O(n2) O(1)O(1)O(1) 不稳定
快速排序 O(nlogn)/O(nlogn)/O(n2)O(nlogn)/O(nlogn)/O(n^2)O(nlogn)/O(nlogn)/O(n2) O(logn)O(logn)O(logn) 不稳定
归并排序 O(nlogn)/O(nlogn)/O(nlogn)O(nlogn)/O(nlogn)/O(nlogn)O(nlogn)/O(nlogn)/O(nlogn) O(n)O(n)O(n) 稳定
堆排序 O(nlogn)/O(nlogn)/O(nlogn)O(nlogn)/O(nlogn)/O(nlogn)O(nlogn)/O(nlogn)/O(nlogn) O(1)O(1)O(1) 不稳定
基数排序 O(d(n+r))O(d(n+r))O(d(n+r))(d为位数,r为基数) O(n+r)O(n+r)O(n+r) 稳定
相关推荐
reembarkation2 小时前
光标在a-select,鼠标已经移出,下拉框跟随页面滚动
java·数据库·sql
愣头不青2 小时前
617.合并二叉树
java·算法
麦麦鸡腿堡3 小时前
JavaWeb_请求参数,设置响应数据,分层解耦
java·开发语言·前端
不想看见4044 小时前
Valid Parentheses栈和队列--力扣101算法题解笔记
开发语言·数据结构·c++
计算机安禾4 小时前
【C语言程序设计】第37篇:链表数据结构(一):单向链表的实现
c语言·开发语言·数据结构·c++·算法·链表·蓝桥杯
没有bug.的程序员4 小时前
Serverless 弹性扩容引发的全线熔断:Spring Boot 启动耗时从 1s 压缩至 0.3s 的物理级绞杀
java·spring boot·kubernetes·serverless·扩容·线上
bearpping5 小时前
java进阶知识点
java·开发语言
独自破碎E5 小时前
【面试真题拆解】你知道ThreadLocal是什么吗
java·jvm·面试
kkkkatoq5 小时前
JAVA中的IO操作
java·开发语言