软件工程师——(七)数据结构与算法基础

169 阅读14分钟

1. 数组

image.png

1. 存储地址的计算

  • 1、一维数组
    • 1)某个数组变量的存储地址必然是以该数组首个元素(首地址)偏移计算
    • 2)已知第一个元素所在的位置,然后根据每一个元素所占的空间,推算当前要求的元素存储位置
    • 3)i一般从0开始
  • 2、二维数组(二维数组中按行存储和按列存储的区别)
    • 1)按行存储———一行一行的存,不够了起下一行
    • 2)按列存储———一列一列的存,不够了起下一列
  • 3、例题 image.png
    • 例题分析
      • 5行5列———每行可以存放五个元素
      • 按行存储———一行一行的存,不够了起下一行
      • a[2][3]———第已满,该元素在第三行到第列,所以前边有2*5+3=13个元素
      • 所以地址为a+13*2

2. 稀疏矩阵———考点(计算稀疏矩阵某个元素对应一维数组的下标)

image.png

  • 1、说明———一个矩阵记录的元素中大量都为0,称之为稀疏矩阵
  • 2、应试方法———代入法
  • 3、例题 image.png
    • 例题解析
      • 代入值A[0,0]应该对应M[1]———>A、D符合,B、C不符合
      • 代入值A[1,1]应该对应M[3]———>A符合,D不符合
      • 所以答案为A

2. 数据结构的定义

1. 数据结构的概念

  • 计算机存储以及组织数据的方式

2. 数据逻辑结构

  • 1、线性结构 image.png
  • 2、非线性结构(进一步可以分为树形结构(没有环路)图(可能存在环路)) image.png

3. 线性表的定义

image.png image.png

  • 1、顺序表其实就是一维数组形式 image.png
  • 1、单链表删除操作
    • 一个指针q指向要删除的节点a2
    • 一个指针p指向要删除节点之前的节点a1
    • 将a1的next指针指向a3(p->next=q->next)
  • 2、单链表插入操作
    • 一个指针s指向要插入的节点x
    • 一个指针p指向要插入位置后的节点a1
    • 设置新节点x的next指针指向节点a1的next指针指向的节点a2(s->next=p->next)
    • 设置节点a1的next指针指向新节点x(p->next=s)
  • 3、双向链表删除节点———基本不考察
  • 4、双向链表插入节点———基本不考察

4. 线性表-顺序存储与链式存储对比

image.png

5. 线性表—队列与栈———重点考察

image.png

  • 1、习题解答———穷举法
    • a、b、c
    • c、b、a
    • b、a、c
    • a、c、b
    • b、c、a image.png
  • 1、习题解答———D———代入法尝试

3. 广义表

image.png

  • 1、长度求解———最外层元素个数
  • 2、深度求解———递归定义的重数(包含括号重数,即嵌套的次数)
  • 3、表头———最外层第一个元素
  • 4、表尾———除了表头以外的其他所有元素 image.png
  • 1、习题解析
    • 例题1———长度为3,深度为2
    • 例题2
      • tail(LS1)
      • head(tail(LS1))
      • head(head(tail(LS1)))

4. 树与二叉树

1. 树的基本概念

image.png

  • 1、结点的度———一个结点拥有孩子结点数(结点1的度为2、结点3的度为1、结点7的度为0)
  • 2、树的度———树中所有节点拥有最高结点度的结点的结点度数(树的度为2)
  • 3、叶子结点———没有孩子结点的结点(结点4、5、7、8都为叶子结点)
  • 4、分支结点———有相应分支的节点(除了根结点叶子结点外的节点)
  • 5、内部结点———有相应分支的节点(除了根结点叶子结点外的节点)
  • 6、父结点———相对概念(对于结点2和结点4而言,结点2是结点4的父结点)
  • 7、子结点———相对概念(对于结点2和结点4而言,结点4是结点2的子结点)
  • 8、兄弟结点———属于同一父结点的结点
  • 9、层次———一层层的节点

2. 二叉树的重要特征

image.png

  • 1、满二叉树———整棵树没有缺失的节点(都拥有完整的2个子结点,或者完全没有子结点)
  • 2、完全二叉树———除了最后一层,上边的层次都是满二叉树,且最底层节点从左到右排列
  • 3、非完全二叉树———不符合完全二叉树二叉树

3. 二叉树的遍历

image.png

  • 1、层次遍历———一层层从左到右遍历(答案:1、2、3、4、5、6、7、8)
  • 2、前序遍历———根结点访问(访问根结点,再访问左子树结点,然后访问右子树节点)(答案:1、2、4、5、7、8、3、6)
  • 3、中序遍历———根结点中间访问(访问左子树结点,再访问根结点,然后访问右子树节点)(答案:4、2、7、8、5、1、3、6)
  • 4、后序遍历———根结点访问(访问左子树结点,再访问右子树节点,然后访问根结点)(答案:4、8、7、5、2、6、3、1)

4. 反向构造二叉树

image.png

  • 1、说明———知道一定的二叉树遍历序列,反向推出二叉树的情况
  • 2、例题分析
    • 前序确定了,中序确定了左右子树
    • 得到结果如下 image.png

5. 树转二叉树

image.png

  • 1、快捷转换——— 兄弟连线,儿子只要左儿子,然后对树进行旋转

5. 查找二叉树

image.png

  • 1、特点———对于左子树结点都比根结点,右子树结点都比根结点,且子树同样满足以上要求的二叉树,称之为查找二叉树(排序二叉树)
  • 2、意义———极大提高查询速度和效率

6. 最优二叉树(哈夫曼树)

image.png

  • 1、说明———一种工具树,用于哈夫曼编码(多媒体压缩技术中经常使用的一种压缩编码方式,让原始信息编码长度变得更短,从而节省存储空间和传输带宽,是一种无损压缩方式)
  • 2、基本概念
    • 树的路径长度———路径的长度总和(树中所有连接线个数)
    • 权———叶子结点数值代表某个字母出现的频度,这就是权
    • 带权路径长度———先求出路径长度,再乘以权值
    • 树的带权路径长度(树的代价)———所有带权路径长度
  • 3、构造哈夫曼树理念———让一棵带权路径长度最短的情况
  • 4、例题说明
    • 1、构造步骤
      • 1)先选两个最小权值(5和3),构造一个小子树,得到其权值和(8)
      • 2)得到新的数列(去除5和3,加入8)———29、7、7、14、23、11、8
      • 3)重复步骤1和步骤2,得到最终结果
    • 2、求解值
      • 各个叶子结点带权路径长度
        • 5———路径长度(5)*权值(5)=25
        • 29———路径长度(2)*权值(29)=58
        • 7———路径长度(4)*权值(7)=28
        • 8———路径长度(3)*权值(8)=24
        • 14———路径长度(3)*权值(14)=42
        • 23———路径长度(2)*权值(23)=46
        • 3———路径长度(5)*权值(3)=15
        • 11———路径长度(3)*权值(11)=33
      • 树的带权路径长度(树的代价)=各个叶子结点带权路径长度
        • 25+58+28+24+42+46+15+33=271

7. 线索二叉树

image.png

  • 1、概念———二叉树的基础之上,添加虚线的箭线,将节点串起来
  • 2、作用———由于二叉树中许多结点处于空闲状态,有很多指针都是空的没有利用起来,所以提出前、中、后序线索二叉树的概念,从而方便遍历
  • 3、分类
    • 前序线索二叉树
      • 写出遍历顺序———ABDEHCFGI
      • 左子树节点的指针指向前序遍历当前节点前序节点
      • 右子树节点的指针指向前序遍历当前节点后序节点
    • 中序线索二叉树
      • 写出遍历顺序———DBHEAFCGI
      • 左子树节点的指针指向中序遍历当前节点前序节点
      • 右子树节点的指针指向中序遍历当前节点后序节点
    • 后序线索二叉树
      • 写出遍历顺序———DHEBFIGCA
      • 左子树节点的指针指向后序遍历当前节点前序节点
      • 右子树节点的指针指向后序遍历当前节点后序节点

8. 平衡二叉树

image.png

  • 1、说明
    • 排序二叉树最平衡的一个
  • 2、作用———一棵树可能有多个排序二叉树,在这些排序二叉树中,越平衡的排序二叉树查找效率越高
  • 3、特点
    • 任意结点的左右子树深度相差不超过1
    • 每个结点的平衡度只能-1、0或1
  • 4、不平衡二叉树的调整

5. 图

1. 图的基本概念

image.png

2. 图的存储方式

1. 邻接矩阵

image.png

  • 1、矩阵特点说明
    • 矩阵的大小取决于结点的个数(M个节点就对应MxM的矩阵)
    • 顶点i到顶点j有边就用1表示
    • 顶点i到顶点j无边就用0表示
    • 无向图的邻接矩阵有对称性

2. 邻接表

image.png

  • 1、邻接表特点
    • 首先记录所有结点使用一个表(一维数组)
    • 每个结点能够到哪些结点使用链表存储

3. 图的遍历

1.遍历方法

image.png

  • 1、深度遍历———根据线索,深入到底,一层一层下去,直到无法继续深入,才退回进入下一分支
  • 2、广度遍历———把一个节点相邻的所有节点全部访问完,再继续下一个层次

2. 结合存储结构遍历示例(从v0作为起点)

image.png

  • 1、深度遍历———顺序结果列,每一步通过加粗项得到[]中的项,[]中的项作为下一次的入口,{}中为当前步骤中包含的未被访问过的入口项,当结果无法继续产出新项时,进入产出旧项所在步骤的下一次入口,还是没有继续找上一层
    • 1)v0———(v4、v3、v1)———v0、[v4]———{v3、v1}
    • 2)v4———(v6、v1、v0)———v0、v4、[v6]———{v1}
    • 3)v6———(v7、v4、v3)———v0、v4、v6、[v7]———{v3}
    • 4)v7———(v6)———v0、v4、v6、v7———v7不能得到新的值,所以进入v7的产出步骤3的下一次入口作为入口步骤的下一项v3
    • 5)v3———(v6,v0)——————v0、v4、v6、v7、v3———v3不能得到新的值,所以进入v3的产出步骤4的下一次入口作为入口步骤的下一项,但是没有新的入口,所以进入产出v7的步骤3的下一次入口作为入口步骤的下一项,但是没有新的入口,所以进入v6的产出步骤2的下一次入口作为入口步骤的下一项v1
    • 5)v1———(v4、v2、v0)———v0、v4、v6、v7、v3、v1、[v2]———{v2}
    • 6)v2———(v5、v1)———v0、v4、v6、v7、v3、v1、v2、[v5]
    • 7)v5———(v2)———v0、v4、v6、v7、v3、v1、v2、v5———产出v2第5步已经作为下一次入口访问过了,所以进入v6作为入口步骤的下一项v1
  • 2、广度遍历———顺序结果列,每一步通过加粗项得到[]中的项,直到追加不到新的值,且没有可用下一个加粗项
    • 1)v0———(v4、v3、v1)———v0、[v4、v3、v1]
    • 2)v4———(v6、v1、v0)———v0、v4、v3、v1、[v6]
    • 3)v1———(v4、v2、v0)———v0、v4、v3、v1、v6、[v2]
    • 4)v6———(v7、v4、v3)———v0、v4、v3、v1、v6、v2、[v7]
    • 5)v2———(v5、v1)———v0、v4、v3、v1、v6、v2、v7、[v5]

4. 拓扑排序

image.png

  • 1、说明———使用一个序列表示一个图中哪些事件可以先执行,哪些事件可以后执行
  • 2、考察形式———以下哪一个不是该图的拓扑排序?

5. 图的最小生成树(普里姆算法)

  • 1、说明———去掉图中多余的边线,留下的边都是权值比较小的,得到一个
  • 2、相关算法
    • 1)普里姆算法 image.png
      • 基本思想
        • 0)判断有多少个结点(M),所以最终要保留(M-1)条边
        • 1)从任意一个结点出发,该结点定为红点级,其他节点为蓝点级
        • 2)找出从红点级蓝点级集合最短的距离的边,此时该边两端的节点晋升为红点级
        • 3)依次重复步骤1和步骤2(选的不能形成环路,且红点到蓝点选边)
    • 2)克鲁斯塔尔算法 image.png
      • 基本思想
        • 0)判断有多少个结点(M),所以最终要保留(M-1)条边
        • 1)选择图中最短的边
        • 3)依次重复步骤1,前提是不能出现环路,选够(M-1)条边结束选边

6. 算法基础

1. 算法的特点

image.png

2. 算法的时间复杂度和空间复杂度

image.png

3. 查找

1. 顺序查找(时间复杂度=O(n)平均查找长度=(n+1)/2)

image.png

  • 1、说明———逐个比对
  • 2、特点———简单不高效

2. 二分查找(折半查找)(时间复杂度=O(log2n)最多查找次数=⌊log2n⌋+1次)

image.png

  • 1、说明———折半查找
  • 2、特点———效率比顺序查找高,当要查找的数据越多,效率越高
  • 1、例题说明(中间节点取整,每次对比结束后中间节点不纳入下一次对比) image.png

3. 散列表

image.png

  • 1、特点———存储的时候就想好一定的规则,存到相应的空间中
  • 2、例题 image.png
    • 例题分析
      • 3%5=3———>所以3存放在3位置
      • 8%5=3———>3位置已存值冲突,所以8存到3位置的下一个位置4位置
      • 12%5=2———>所以12存放在2位置
      • 17%5=2———>2位置已存值冲突,所以17存到2位置的下一个位置3位置,3位置已存值冲突,所以17存到3位置的下一个位置4位置,4位置已存值冲突,所以17存到4位置的下一个位置5位置
      • 9%5=4———>4位置已存值冲突,所以9存到4位置的下一个位置5位置,5位置已存值冲突,所以9存到5位置的下一个位置6位置
  • 3、散列表冲突的解决办法 image.png
    • 线性探测法———位置被占用时,顺次存到下一个可用的地址
    • 伪随机数法

4. 排序(重点考察)

1. 排序基本概念

  • 1、稳定与不稳定排序
    • 稳定排序———相同的元素排序后顺序不变
    • 不稳定排序———相同的元素排序后顺序有可能发生改变
  • 2、内排序与外排序
    • 内排序———内存中的排序
    • 外排序———外部存储设备中的排序

2. 排序方法分类

  • 1、插入类排序
    • 直接插入排序 image.png
      • 实现过程
        • 第1次———取前两个比较大小排序
        • 第x次———取第x+1个元素依次和前边的(x、x-1、x-2...)元素对比,放在小于其元素的后边
    • 希尔排序———实质(分组后使用直接插入排序) image.png
      • 实现过程
        • 第1次分组个数———d[2]=n/2(取奇数)
        • 第x次分组个数———d[x]=d[x-1]/2(取奇数)
  • 2、交换类排序
    • 冒泡排序———相邻元素之间的比较,逐渐将小元素底部移向顶部的过程 image.png
    • 快速排序———采用分治法 image.png
  • 3、选择类排序
    • 简单选择排序 image.png
      • 实现过程———每一次取剩余所有元素中最小的,依次排序
    • 堆排序
      • 定义———所有的孩子结点小于根节点(大顶堆)、所有的孩子结点大于根节点(大顶堆) image.png
      • 基本思想———不断建立堆,取根,再重建堆的过程 image.png
      • 例题说明
        • 例题1———初建堆生成过程 image.png
          • 1、按照完全二叉树方式使用数组顺次填充元素建树,如图1.1
          • 2、最后一个非叶子结点开始,看其如果大于其孩子结点不发生改变,否则与最大的孩子结点交换位置
          • 3、交换后继续重复步骤2,直到不需要再进行交换
          • 4、进行下一个非叶子结点重复步骤2、步骤3
          • 5、最终得到初建堆
        • 例题2———堆取值重建 image.png
          • 1、去掉根,使用二叉树最后一个结点替换根
          • 2、重复初建堆步骤2、步骤3
          • 3、重复步骤1、步骤2
          • 4、最终得到排序后的序列
  • 4、归并排序———将两个或两个以上的有序的子表合并成一个新的有序表 image.png
  • 5、基数排序 image.png

3. 排序算法的时间复杂度和空间复杂度以及稳定性(重点)

image.png