软件工程 学习笔记 知识梳理

本文详细梳理了软件工程的知识体系,包括软件开发过程、操作系统的主要功能、编译原理、数据结构与算法等内容。重点介绍了操作系统中的进程管理、数据管理的SQL语言以及数据结构中的线性表、树和图。同时,还涵盖了数据库设计和编译原理的基础概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Chapter 1 绪论

软件开发知识体系

  • 项目管理开发: 软件工程
  • 软件逻辑设计: 数据结构与算法
  • 程序编程编译: 编译原理
  • 软件运行环境: 操作系统/数据库

软件开发过程

  1. 问题理解
  2. 算法设计
  3. 数据结构设计
  4. 算法分析
  5. 程序设计
  6. 程序实现

操作系统

操作系统是一组控制和管理计算机硬件和软件资源,合理地对各类作业进行调度,以及方便用户使用的程序的集合。

主要功能

  • 处理机管理: 进程管理
    • 控制: 程序的创建, 撤销, 状态转换
    • 调度: CPU分配
    • 同步: 多个进程协调
    • 通信: 进程信息交换
  • 储存器管理: 内存管理
    • 分配: 为每个作业分配内存 静态分配 动态分配
    • 保护: 确保用户程序只在自己内存内运行 互不干扰
    • 映射: 地址空间 内存空间 地址映射
    • 扩展: 虚拟储存技术扩充内存容量 请求调入, 置换
  • 设备管理: I/O管理
    • 缓冲: 缓和CPU和I/O速度不匹配矛盾
    • 分配: 根据进程I/O请求, 为之分配所需设备
    • 驱动: 设备处理, 实现CPU与设备控制器之间的通信
  • 文件管理: 用户文件, 系统文件管理
    • 储存: 储存空间分配 回收
    • 组织: 建立目录项, 按名存取
    • 读写: 外村读写数据
    • 安全: 放置未核准用户存取, 防止不正确使用文件
  • 用户接口: 提供有好的接口, 方便用户使用
    • 图形用户接口
    • 命令接口
    • 程序接口

软件程序编译

  1. 操作系统依赖: 高级语言 --> 翻译程序 --> 机器码
  2. 不依赖操作系统: 高级语言 --> 翻译程序 --> 中间语言 --> 执行虚拟机

编译步骤

源程序字符串 --> 词法分析器 --> 单词流 --> 词法分析器 --> 语法树 --> 语义分析器 --> 中间代码序列 --> 代码优化器 --> 目标代码生成器 --> 目标程序

计算机软件数据管理

位于用户与操作系统之间的数据管理软件

功能

  • 数据定义
  • 数据操作
  • 数据库运行管理
  • 数据组织, 储存, 管理
  • 数据库建立维护
  • 数据通信接口

SQL

  1. DDL definition
  2. DML manipulation

Chapter 2 数据结构

线性表

  1. 数据元素一一对应, 顺序关系
  2. 位序, 表长, 前驱, 后继, 除第一个和最后一个, 唯一前驱和后继

顺序储存结构

  1. 地址连续 依次存放 起始地址
  2. 随机存取
  3. 定义{基址, 长度length, 容量size}
  4. 插入操作: E = n / 2 E=n/2 E=n/2 O ( n ) O(n) O(n)
   Status  List_Insert(ListPtr L, int pos, ElemType elem){
	Status status = range_error;
	int len = L->length,i;
	if (len = MAXSIZE) status = overflow;
	else if (1<= pos && pos <=len+1){
	   for(i=len;i>=pos;i--)
			L->elem[i+1] = L->elem[i];  /* 数据元素后移一个位置*/
	   L->elem[pos] = elem;
	   L->length ++;  /* 表长加1 */
	   status = success;
	}
	return status;
   }

  1. 删除操作: E = n − 1 2 E=\frac{n-1}{2} E=2n1 O ( n ) O(n) O(n)
Status List_Remove(ListPtr L,int pos){
	Status status = range_error;
	int len = L->length, i;
	if(1<= pos && pos<=len){
	   for(i=pos;i<len;i++)
		    L->elem[i] = L->elem[i+1]; /* 数据元素前移一个位置*/
	   L->length --;  /* 表长减1 */
	   status = success;
	 }
	return status;
}

链式储存结构

  1. 数据域+指针=节点
  2. 头指针 带不带头结点皆可
  3. 查找
Status  List_Locate(ListPtr L, ElemType elem, int *pos){
	Status status = range_error;
	ListNodePtr p = (*L)->next; /*p指向第一个元素结点*/
	int i=1;
	while(p !=NULL){  /* p指向的结点存在才能向下比较*/
	  	if ( p->data == elem ) break; /* 比较 */
	  	i++;
	  	p=p->next;   /*指针后移,同时计数器加1*/
	}
	if(p) {    /*找到给定结点*/
		  *pos = i;
		   status = success;
	}
	return status;
}
  1. 插入
Status  List_Insert(ListPtr L, int pos, ElemType elem){
	Status status;
	ListNodePtr pre,s;
	status = List_SetPosition(L,pos-1,&pre);  /*找插入位置的前驱*/
	if (status ==success){
		 s=(ListNodePtr)malloc(sizeof(ListNode));
		 if (s){
			s->data=elem;
			s->next=pre->next;
			pre->next=s;
		 }
       else 
			status =fatal;
	}
	return status;
}
  1. 删除
Status  List_Remove(ListPtr L, int pos){
	Status status;
	ListNodePtr ptr,q;
	status =List_SetPosition(L, pos-1, &ptr); /*找插入位置的前驱*/
	if(status ==success){
		 q=ptr->next;
		 ptr->next=q->next;
		 free(q);
	}
	return status;
}
  1. 创建
  • 建立一个“空表”
  • 输入数据元素an,建立结点并插入到单链表;
  • 输入数据元素an-1,建立结点并插入到单链表;
  • 依次类推,直至输入a1为止
    p->next=L->next;
    L->next=p;

顺序储存链式储存对比

顺序插入删除不方便 适宜查找静态操作 容量固定 额外内存申请开销
长度变化大 链表

渐进复杂度

O ( g ( n ) ) → 0 ≤ f ( n ) ≤ c g ( n ) O(g(n)) \rightarrow 0\le f(n) \le cg(n) O(g(n))0f(n)cg(n)
a 0 + a 1 n + . . . + a d n d = Θ ( n d ) a_0+a_1n+...+a_dn^d=\Theta(n^d) a0+a1n+...+adnd=Θ(nd)

分治

  1. 问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
  2. 问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题

归并排序

  1. 一对多 根节点没有前驱 其他只有一个前驱 叶子没有后继
  2. 深度

二叉树

  1. 左右子树不能颠倒
  2. 满二叉树: 深度为k 有2^k-1个节点
  3. 完全二叉树: 每个节点都与深度相同的满二叉树一一对应
  4. 顺序储存: 必须为完全二叉树 i左孩子下标为2i 添加虚节点转为完全二叉树
  5. 链式储存: {data, *lc, *rc} 三叉{data , lc,rc,parent}
  6. 遍历
    • 先序, 中序, 后序
void preorder(BiTree T){
  if(T!=NULL){  
      printf("%d\t",T->data);
      preorder(T->lchild);
      preorder(T->rchild);
   }
}
  • 层次
    • 初始化队列,根节点入队列
    • 如果队列不空,则出队列并访问该节点;该节点左孩子入队列,右孩子入队列;如果队列为空,则层次遍历结束
  1. 树的存储结构
    • 双亲表示法
    • 孩子表示法
    • 孩子兄弟表示法
  2. 二叉树与树互换

  1. 树的存储

    • 邻接矩阵
    • 邻接表
      • 无向图: n顶点 e条边 需要n个头结点和2e个链表节点 顶点Vi的度=链表中链表节点数
      • 有向图: 逆邻接表 邻接表
  2. 一个图的邻接矩阵表示是唯一的;邻接表表示不唯一。邻接表中各边表结点的次序取决于建立算法和及输入边的次序.

  3. 邻接表(逆邻接表)中,每个边表对应邻接矩阵中的一行(或一列);边表中结点的个数等于邻接矩阵中的一行(或一列)非0元素的个数。

  4. 邻接表或逆邻接表的空间复杂度为S(n,e)=O(n+e)。若图中的边数e远远小于n2,称为稀疏图,其邻接表比邻接矩阵要节省存储空间。当边数e接近n2 (无向图:e接近n(n-1)/2;有向图:e接近n(n-1))时,称为稠密图,考虑链域占空间,应选择邻接矩阵存储为宜。

  5. 求有向图顶点的度,采用邻接矩阵比邻接表结构方便。在邻接表结构中,求顶点的出度容易,入度困难。逆邻接表中,求顶点的入度容易,出度困难。

  6. 判断边,邻接矩阵比邻接表容易;求边数:邻接矩阵中花费的时间复杂度为O(n2),邻接表中花费的时间复杂度为O(n+e)

  7. 图的遍历

    • 深度优先遍历
    • 广度优先遍历: 栈

贪心算法

  1. 简单, 高校, 可能不是最优解
  2. 活动安排
public static int greedySelector(int [] s, int [] f, boolean a[])
   {
      int n=s.length-1;
      a[1]=true;
      int j=1;
      int count=1;
      for (int i=2;i<=n;i++) {
        if (s[i]>=f[j]) {
          a[i]=true;
          j=i;
          count++;
          }
        else a[i]=false;
        }
      return count;
   }

3.Dijkstra 算法

  1. 无向图转换为有向图不会对计算造成影响
  2. 非负环不会对计算造成影响

Chapter 3 操作系统

进程

一个正在执行中的程序实例

  • 动态性: 正在执行, 存在生命周期
  • 并发: 可以同其他进程一起推进
  • 独立: 地址空间相互独立
  • 异步: 各自独立 不可预知速度执行
  • 结构性: 进程控制块+程序段+数据段

状态转换

  • 就绪: 分配到除CPU以外所有资源, 只要获得CPU, 立即执行
  • 执行: 正在执行
  • 阻塞: 由于发生某事件暂时无法执行
  • 新建状态: 已构造了进程标识符, 表格, 程序还未进入主存
  • 终止: 不再有执行资格, 表格和其他信息暂时保留
  • 挂起: 不再参与CPU竞争, 进程被交换到外存

挂起原因

  • 进程全部阻塞 处理机空闲
  • 负荷过重, 空间紧张
  • 操作系统需要, 挂起后台, 服务进程
  • 终端用户的请求
  • 父进程请求

特征

  • 不能立即执行
  • 挂起条件独立与阻塞
  • 使之挂起的进程: 自身, OS, 父进程
  • 激活挂起进程: 实施挂起操作的进程

阻塞与挂起

  • 阻塞: 是否等待

  • 挂起: 是否被换出内存

  • 就绪/挂起: 只要调入内存就可以执行

  • 阻塞/挂起: 进程在外存. 等待事件

进程控制块PCB

  1. 作用
    • 存在的唯一标志
    • 常驻内存
  2. 块信息
    • 标识符: 内部 操作系统赋予一个整数 外部 创建者提供 用户访问时使用
    • 处理机状态: 寄存器
    • 程序调度信息
    • 进程控制信息 程序和数据地址

创建进程

pid = fork() 父子均在下一条语句执行

  • 子进程 pid=0 父进程为所创建子进程标识
  • 子进程是父进程的精确复制
  • 通过exec()调用族, 加载新的程序
  • fork()和exec()结合使用

线程

  • 调度并分派部分称为线程 资源所有权称为进程
  • 拥有 线程控制块 程序计数器 寄存器 , 其他不拥有资源
  • 独立调度和分派的基本单位
  • 可并发执行 共享资源

进程与线程

  • 进程是资源分配的独立单位
  • 线程是独立调度的基本单位
  • 引入线程更好的并发性
  • 拥有的资源不同
  • 管理, 切换进程开销显著大于线程
  • 同一进程同步 通信方便
  • 线程切换不许系统内核干预

线程类型

  • 用户级线程: 线程创建, 撤销和切换等全部由应用程序完成, 操作系统不知道线程的存在 调度更灵活 但是用户线程引起整个进程阻塞 削弱线程的并发性
  • 内核级线程: 均由系统内核完成 可以调度到多个处理器 进程一个线程被阻塞, 其他也可以调度 但是开销大
  • 混合线程: 多个线程被映射到一个或较少的内核级线程

进程间同步

互斥

  1. 资源共享–>互斥
  2. 进程合作–> 同步
  3. 必须互斥使用的资源称为临界资源
  4. 访问临界区的那段代码称为临界区
  5. 临界区使用原则: 空闲让进 忙则等待 有限等待 让权等待

信号量

  1. 信号量原子操作: wait(s)/P(s) signal(s)/V(s)
  2. 互斥信号量/资源信号量

进程间通信

  1. 进程间通信:共享储存区/消息传递
  2. 消息格式: 消息头-消息体
  3. 消息同步: 发送进程发送消息, 若没有空闲的消息缓冲区 则发送进程阻塞; 接受进程若没有消息可接受, 则接受进程阻塞 直到一条消息到达
  4. send receive
  5. 阻塞发送 阻塞接收/不阻塞发送 阻塞接收/ 不阻塞发送 不阻塞接收
  6. 直接寻址/间接寻址:邮箱
  7. 消息传递互斥:
  • 多个并发执行的发送进程和接收进程共享一个邮箱box,且box的初始状态为仅包含一条空消息;
  • 采用“不阻塞发送,阻塞接收”方式传递消息;
  • 若邮箱中存在一条消息,则允许一个进程进入临界区。
  • 若邮箱为空,则表明有一个进程位于临界区,其它试图进入临界区的进程必须阻塞。
    • 只要保证邮箱中最多只有一条消息,就能保证只允许一个进程进入临界区,从而实现进程互斥使用临界资源。

程序装入和链接

链接

由链接程序(Linker)将编译后形成的一组目标模块,以及它们所需要的库函数链接在一起,形成一个完整的装入模块。

  • 静态链接: 程序运行前, 连接成一个完整的装配模块
    • 相对地址修改
    • 缺点: 不利于代码共享 不利于模块独立升级 浪费储存空间
  • 装入时链接: 边装入边链接
    • 优点: 便于各个模块的升级 代码共享
    • 缺点: 可能链接一些不会执行的模块 装入后不能移动位置
  • 动态链接: 需要该目标模块时再找到模块调入内存
    • 优点: 加快程序装入, 节省内存空间

装入

  • 装入内存

  • 地址重定位: 逻辑地址变为物理地址

  • 分类

    • 绝对装入: 编译时就知道驻存的具体位置, 产生绝对地址的目标代码 不需对程序和数据地址修改 采用符号地址
      • 简单, 每次必须装入统一内存区 不适合多道程序系统
    • 静态重定位: 采用相对地址 必须重定位
      • 重定位后不能移动 不利于内存有效利用
    • 动态重定位: 程序运行时动态进行 需要硬件支持
      • 不必连续存放在内存中 便于共享 有利于紧凑 碎片问题 主流
      • 但需要硬件支持 算法复杂

编译原理

  1. 冯诺依曼体系: 控制器, 存储器, 处理器
  2. 变量: 储存单元抽象, 赋值是修改储存单元的抽象
  3. 编译步骤
    1. 词法分析: 输入字符串, 识别单词符号
    2. 语法分析: 根据语法规则, 将符号构成语法单位, 语法检查
    3. 语义分析: 根据语义规则, 初步编译
    4. 优化: 中间代码等价变换, 代码更有效
    5. 目标代码生成: 生成机器语言程序或汇编语言程序
    6. 符号表管理: 符号表建立, 查找, 更新
    7. 出错处理: 发现 指出 限制
  4. 数据类型: 值的集合和一组操作
  5. 抽象层次: 内部类型, 用户定义类型, 抽象数据类型
  6. 内部类型不能对成分进行操作, 用户类型可以 抽象数据类型不能直接操作, 通过过程访问抽象数据
  7. 用户定义类型分类
    1. 笛卡尔积: C结构
    2. 有限映射: 定义域到值域的映射 数组
    3. 序列: 类型相同 字符串
    4. 递归: T包含T成分, 二叉树
    5. 判定或: C联合 两种不同对象选择
    6. 幂集: T子集的集合, 集合操作
  8. 语句级控制结构
    1. 顺序: 按程序计数器顺序获得指令抽象
    2. 分支和循环: 显式修改程序计数器的值, 无条件转移和条件转移抽象
  9. 单元级控制结构:函数 参数传递 异常处理 并发
  10. 语法 字母表 符号 字汇表:关键字表 词法规则: 规定什么样的字符序列是有效符号 语法规则: 确定符号序列是否合法
  11. 生成(文法): 非终结符 终结符
  12. 识别(语法图): 如果合法, 必须从语法图入口通过出口,识别终结符序列 所有终结符序列称为语言
  13. 语义: 抽象机行为描述语言
  14. 文法分类 G = ( V T , V N , S , P ) G=(V_T, V_N, S, P) G=(VT,VN,S,P)
    1. 0型文法: α → β \alpha \rightarrow \beta αβ
    2. 1型 上下文有关文法 替换时需考虑上下文
    3. 2型上下文无关文法:
    4. 3型 正则文法: (无左递归)
  15. 推导: 产生式替换 最左推导 最右推导 规约
  16. 句型: 包括非终结符, 句子终结符序列
  17. 语法树 叶子:非终结符 短语: 子树末端节点生成的符号串
  18. 二义性: 句子有两颗不同的推导树
  19. 词法分析: 标识符 基本字 常数 运算符 界符 双缓冲区 超前搜索

语法分析

  1. 自上而下
    1. 回溯分析: 推导失败 回溯
    2. 回溯原因: 公共左因子 左递归 ϵ \epsilon ϵ产生式
    3. 左递归与间接左递归的消除
    4. 扩充BNF: {} [] 改进的递归下降 利用循环消除左递归
    5. 预测分析: 下推栈, 当前输入符号, 预测分析表
    6. 预测分析表构建:
      • FIRST集: 注意空串
      • FOLLOW集
      • LL(1) FIRST集互斥, 空串时,FIRST与FOLLOW互斥 仅利用当前非终结符 向前查看1个符号就能决定采取动作
    7. 自下而上:移入 规约 LR分析法
      • 短语 直接短语 句柄

语义翻译

  1. 语义分析的目的是生成代码并实现句子的语义 语义分析生成的不是最终的目标代码,而是便于实现优化的某种中间代码;
  2. offset 产生最早句柄初始化
  3. 对赋值语句类型检查
  4. 拉链 回填

数据库

  1. 数据库是长期存储在计算机内, 有组织的, 可共享的大量数据集合
  2. 按一定的数据模型组织, 描述和储存 独立性高 冗余小 可共享
  3. DBMS: 定义, 创建和维护数据库 控制数据库访问的软件系统
  4. 实体集 表

模式结构

  1. 内模式
  2. (概念|逻辑)模式: 一个数据库只有一个模式 公共数据视图 中间层
  3. 外模式(视图, 用户模式): 用户使用的局部数据 不同用户外模式不同 模式与外模式一对多 外模式与应用一对多
  4. 内模式(存储模式) 物理结构
  5. 外模式/模式映射: 模式改变 修改映射 使外模式保持不变 保证程序独立性

数据模型

  1. 数据结构 操作 约束条件
  2. 关系实例: 表
  3. 关系模式: 关系名 属性名 域名 完整性约束 1NF 不能表中有表
  4. 关系数据库是关系有限集合 关系模式集合称为数据库模式 对应实例集合成为数据库实例
  5. 键: 不能取空值 实体完整性 候选键 主键 外键
  6. 元祖不能重复 顺序不重要
  7. 实体完整性:主键不能为空 参照完整性: 外码 孤子记录
  8. 关系运算
    • 条件连接 在两关系笛卡尔积上的选择运算
    • 自然连接: 相同属性列相等 重复属性列去掉.
    • 左连接(加入左面) 右连接(加入右面)

SQL

  1. CREATE DATABASE | ALTER DATABASE | DROP DATABASE
  2. 完整性约束
    • 主键约束 PRIMARY KEY
    • 唯一性约束 UNIQUE
    • 非空值约束 NOT NULL
    • 参照完整性约束 不允许引用不存在实体
  3. ALTER TABLE

数据库设计

  1. 函数依赖: 属性之间的联系 语义关联性
  2. 决定因子 依赖因子
  3. 完全函数依赖, 部分函数依赖: 单属性只能是完全函数依赖
  4. 主属性: 包含在候选码中的属性
  5. 模式分解必须无损
  6. 可以决定决定其他所有属性的属性是主键
  7. 范式
    • 1NF: 每个属性值都是不可再分的原子值
    • 2NF: 每个非主属性完全函数依赖于候选码 主键只有一个字段 就一定符合2NF
    • 3NF: 每个非主属性不传递依赖于R, 依赖因子必须是候选码
    • BCNF: 每个主属性都不传递函数依赖于候选码

E-R模型

  1. 一多一 一对多 多对多 同一实体型内联系 多个实体型之间联系
  2. 弱实体
  3. 数据库设计方法
    • 直观设计
    • 新奥尔良: 需求分析 概念设计 逻辑设计 物理设计
    • 基于E-R模型的数据库设计
    • 3NF设计方法
    • 面向对象的数据库设计方法
    • 数据库设计计算机辅助
  4. 数据库的三种模型
    • 层次模型:树
    • 网状模型
    • 关系模型
  5. 阶段
    • 需求分析: 明确需要完成何种任务
    • 概念设计: E-R
    • 逻辑设计: 转换为关系模型 模式优化 范式
    • 物理设计: 储存结构 存取方法
    • 实现
    • 运行与维护
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值