课程内容提要
数组
- ——》考点:
1)、存储地址的计算
2)、在二维数组中按行存储和按列存储的区别 - 某个数组变量存储的首地址,以这个数组的首元素(首地址)为偏移来算,第一个元素存在什么位置, 然后根据每个元素占多少空间,推算出当前求的这个元素处于什么位置
- a+i*len:a——>整个数组的首元素地址;偏移量——>i * len(每个数组元素所占用的字节数),i是从0开始计的,
- 每个数组元素所占用的字节数,如果每个数组元素所占用的字节数为1,那么a[1] = a + 1*1
- 例题
- 步骤一、从a[2][3]中可以得出:a[0]、a[1]行已经存满,一共十个元素
- 步骤二、a[2][3]是第第三行第四个元素
- 步骤三、所以求得存储地址为:a + (2x5 + 3) x 2 ——> i=2,j=3,n=5【行数】,len=2
- 步骤四、a[0][0] = a
稀疏矩阵
- ——》考点:计算稀疏矩阵某个元素对应的一维数组的下标,跟计算偏移量是一回事
- 稀疏矩阵的定义:一个矩阵当中所记录的元素,如果大量的元素都是0的话,就是稀疏矩阵
- 为什么只存一半:因为另一半的数据可能是重复的;什么情况是重复的呢?比如图是一个无向图
- ——》考试解题思路:
- 记住公式
- 代入法:任何一个元素都能通过这个公式,得到应该存储的位置上
步骤一、将A(0,0)带入选项公式,由结果应该为M1,可排除B,C
步骤二、代入A(1,1),因为A(1,1)在数组M中的位置为M[3],A00—>M[1] , A10—>M[2]
数据结构的定义
- 数据结构的概念:计算机存储,组织数据的方式
- 数据逻辑结构
- 线性结构
- 非线性结构
1)、树:不存在环路
2)、图:可能存在环路
线性表的定义
- 线性表的概念
- 线性表常见的两种存储结构
顺序表
- 顺序表的定义:开辟了连续的空间,顺序地将表存进来(一维数组方式存信息)
- 链表的定义:每个存储单元,包含了存数据和指针的地方
指针的意义:因为存储空间不一定连续,将离散的空间,用指针连起来,形成了链表
- 单链表:只有一套指针,并且是单向的;定位某个元素的时候,从头开始加
- 循环链表:尾元素的指针,指向了头结点;好处:当前指针在尾结点的时候,不需要从新定义在头结点
- 双向链表:一套指针,分别是从头往后,和逆向。既可以往前挪指向前一个元素,也可以往后挪指向下一个元素
链表的基本操作
- 基本操作
- 单链表删除结点:
1)、同样的几个操作语句,把顺序调整一下,就不能达到预期目标
2)、操作步骤
(1)、因为a3没有直接指针,如果a3有指针x指向,则可有p—>next = x,p指a1,p—>next指向a2
(2)、有因为a2—>next是原本就指向a3的,所以有a1—>next = a2—>next - 单链表插入结点
1)、操作步骤:
(1)、因为p—>next原本指向a2,所以有s—>next指向a2,则s—>next = p—>next
(2)、p—>next再指向x,此时x的地址为a,所以p—>next = s - 双向链表删除结点:步骤与上相同,一般考试不考这么难
- 双向链表插入结点:步骤与上相同
- ——》注意:单链表是分,有头结点和无头结点的
1)、有头结点的好处:
单独有一个头结点,头结点不存任何信息,头结点的下一个元素才存信息;
可以令所有的结点的操作方式变成一致的
如果头结点放了别的元素,存储的具体内容,头结点的处理往往采取不同的处理方式
线性表 - 顺序存储与链式存储的对比
- 链式存储:一个存储结点中分数据和地址(指针),所以假设数据用2个字节,地址用1个字节,则总共需要3个字节,利用率 2/3 = 66%;动态分配,需要时分配再链起来即可
- 顺序存储:需要多少空间得提前告诉,才能分配足够,所以事先需要确定
- 读运算:
1)、顺序存储:读A[5],直接读A[5]即可
2)、链式存储:先定位至头结点,next—>下一个,next再指向下一个,直到指向A[5],局限性:只能一格一格的移动 - 插入运算:
1)、链式中间插入:将上一个结点的next指针赋值给插入结点的next指针,上一个结点的next指针指向下一个结点即可
2)、顺序存储中间插入:比如在3与4之间插入3.5,需要依次将8、7、6、5、4往后移,然后插入到3的后面
线性表 - 队列与栈
- 队列:两端能操作,进去顺序是 1-2-3-4-5,出去的顺序也是 1-2-3-4-5 ,即先进先出
- 栈:只有一端能操作,进去顺序是 1-2-3-4-5 , 出去的顺序是 5-4-3-2-1 ,即先进后出
- ——》考点:看变化
- 循环队列:
- size:可以存的总数
- (4+1)%5=0
- 告诉队头,告诉存了几个数据,求队尾
1)、如果队头为4,队尾为2,存了4、0、1这3个数据
2)、所以(4+3【已经大于5存储容量】)%5【所以需要除于5来进行修正数据】
- 习题(1)
- 虽然按照a、b、c的次序进入栈,但是a进去之后,可以立即对a进行出栈操作
- 再b入栈,b出栈;c入栈,c出栈,得到a、b、c的次序
- 先进入a、b,出b、出a;入c,出c。得到了b、a、c次序
- cba、bca
- 不可能得到
- 习题(2)
1)、排除掉e4之后,将e3、e2、e1的ABCD选项的排列顺序放进图中
2)、看是否能够通过入栈、出栈的规则来得到对应的次序
3)、很明显,先入e1,无论e2从左端还是从右端进入,都是e2e1,e1e2
4)、得不到e2,…,e1,所以得不到e4,e2,e3,e1的输出序列
- ——》技巧:看结果,通过操作是否能够达到
广义表
- 广义表中的每个元素,又可以是广义表,所以称为递归形式
- 广义表的长度:最外层包含的元素个数
- LS1 = (a,(b,c),(d,e))中,a—》表元素,(b,c)—》私表,所以长度为3
- 广义表的深度:包含括号的层数,或嵌套的层数
- 两种操作
- head:取 表头 —— 最外层的第一个表元素
- tail:取 表尾 —— 除表尾以外的所有元素
- 例2猜想:要取字母b,取表尾(tail操作)——》取表头(head操作)——》取表头(head操作)
- 例题
- 例题1
3,2
树与二叉树
- ——》考点:会出现题目的描述中,所以需要基本掌握左边一列的概念
- 定义
- 结点的度:一个结点拥有的孩子结点数,1的度为2,3的度为1,7的度为0
- 树的度:在树当中,<>所有结点当中,结点数最高的那个结点数
- 叶子结点:没有孩子结点的结点,4、5、7、8
- 分支结点:有分支的结点,即有孩子的结点
- 内部结点:夹在中间的结点,即既不是根结点,又不是叶子结点
- 父节点:是相对的,对于 2 —> 4 这两个结点来说,2是父结点,4就是子结点
- 子节点:
- 兄弟结点:同一个父结点下的,同级子结点
- 层次:右边的层次数,就是层次
特殊二叉树
- 满二叉树:除了叶子结点,父结点都是满的
- 完全二叉树:除了叶子结点的那层,上层结点满足是满二叉树的要求,且仅有一个叶子结点的话只能是左结点
- 公式
- 求一层的最大结点个数:先指数-1,再求2k-1
- 求一棵树的最多结点数:先指数运算,再进行整体 -1运算
- 【叶子结点的个数】n0 = n2【2表示度数为2,即度数为2个结点的个数】+ 1
- 第4点:大多用于求左右结点的父节点
树与二叉树 - 二叉树遍历
- 遍历方式(前、中、后的意思是根结点的遍历次序)(子节点都是 左结点 —> 右结点,关键在于根结点的位置)
- 前序遍历:ULR ——> 根结点 - 左结点 - 右结点
- 中序遍历:LUR ——> 左结点 - 根结点 - 右结点
- 后序遍历:LRU ——> 左节点 - 右结点 - 根结点
- 层次遍历:一层一层,从左到右依次遍历
- 解题过程:
1)、中序:先将大的数化分为一颗颗小的子树,直到找到最小的子树,从左子树结点开始,结束后到根结点,再遍历右子树,加入右子树又有左子树,则从左子树的左结点开始遍历,从小到大遍历
树与二叉树 - 反向构造二叉树
- 知道二叉树的遍历方式和序列,推出二叉树的构造
- 知道前序和后序,或者中序和后序,都可以还原一棵二叉树
- ——》解题思维:
1)、前序确定——>根结点
2)、中序确定——>左右子树 - 解题步骤:
1)、由前序得:A——》根节点;由中序得 HBEDF——》左子树,GC——》右子树
2)、由前序得:B——》根结点;由中序得 H——》左子树,EDF——》右子树
3)、由前序得:F——》根结点;由中序得ED——》左子树
4)、由前序得:D——》左子树的根结点;F为下一子树的左结点
5)、由前序得:C——》右子树的根结点;由中序得:G——》左结点
树与二叉树 - 树转二叉树
- ——》要点:依次选,得到一棵根结点没有右子树的树
- 孩子结点——》左子树
- 兄弟结点——》右子树
树与二叉树 - 查找二叉树(排序二叉树)
- 查找二叉树的特性:
- 左子树的结点都要比根结点要小;右子树结点都要比根子树结点都要大
树与二叉树 - 最优二叉树(哈夫曼树)
- 定义:
- 树的路径长度:根结点到目标结点的长度之和
- 权:字符出现的频度
- 带权路径长度:路径的长度 x 权值
- 哈弗曼树的思维:构造一颗带权路径最短的树
- 树的带权路径计算
- 第一颗树
1)、确定叶子结点是1,2,3,8
2)、
结点2的带权路径:2 x (1+1【结点到根结点的路径长度之和】) = 4
结点4的带权路径:4 x (1+1+1) = 12
结点8的带权路径:8 x (1+1+1) = 24
结点1的带权路径:1 x 1 = 1
3)、所以树的带权路径为:4+12+24+1 = 41 - 第二颗树
1)、确定叶子结点是1,2,4,8
2)、
结点4的带权路径:4 x (1+1【结点到根结点的路径长度之和】) = 8
结点1的带权路径:1 x (1+1+1) = 3
结点2的带权路径:2 x (1+1+1) = 6
结点8的带权路径:8 x 1 = 8
3)、所以树的带权路径为:8+3+6+8 = 25
- 例题
- 解题思维:第一步选数值中最小的两个数,求得和,再从数中选一个接近的数相加,直到接近的数为最大值;再用剩下的数组成另一颗右子树。权值都为叶子结点
- 解题步骤
1)、将权值作为叶子结点构建出树
2)、由叶子结点求带权路径的长度之和:5x5+3x5+7x4+14x3+8x3+11x3+29x2+23x2
树与二叉树 - 线索二叉树
- 为什么要有线索二叉树:在二叉树当中,有很多结点是出于空闲的状态,有很多指针都是空的没有利用起来,将空闲的指针利用起来,方便遍历,所以提出了前序线索、中序线索、后序线索
- 前序(中序、后序)线索:前序(中序、后序)线索的箭头是按前序(中序、后序)序列来构成的
- 结点的左空闲——》按照前序遍历的顺序的前驱结点进行指向
- 结点的右空闲——》按照后序遍历的顺序的后驱结点进行指向
- ——》解题步骤:
1)、先把前序遍历的过程先列出来
2)、根据题目问的是坐空闲,还是右空闲;选择前趋或后驱
- 线索二叉树的概念:在二叉树的基础上,会有虚线把很多结点给连接起来,这就是线索二叉树
- 线索二叉树的表示:
- 如何将二叉树转化为线索二叉树:
树与二叉树 - 平衡二叉树
- 平衡二叉树的提出原因
1)、一个二叉树越平衡,查找效率就越高 - 平衡二叉树的定义
1)、任意结点的左右子树深度相差不超过1
- 结点5:左子树的深度为—>1;右子树的深度—>0;平衡度(深度相差)—> 1-0=1
- 结点8:左子树的深度—>0;右子树的深度—>1;平衡度—> 0 - 1 = -1
- 左边树因为在结点39后平衡度不为1,0,-1,所以不为平衡二叉树;右边的每个结点的平衡度都为1,0,-1,符合条件所以是平衡二叉树
2)、每结点的平衡度只能为-1、0或1
- 平衡树的建立过程
- 动态调平衡问题
- 靠中间的结点放在中间的位置上
- 要一层层的使每个子树达到平衡度要求
图 - 基本概念
- 完全图:无论是无向图还是有向图都有完全图的概念
都是两点之间能互相直接到达,无向是一条线连两点,有向是两个有箭头的线指向对方
图的存储 - 邻接矩阵
- 无向图:按对角线可以对折
图的存储 - 邻接表
- 步骤:
- 1)、用一列表将所有的点给列出来
- 2)、将结点能够相连的表给连在头结点的后面;三个格子:1)点位置,2)路径长度,3)连接下一个表格(无箭头)
图 - 图的遍历
- 深度优先:沿着结点直接往下层走,反深度走完一个子树,到另一个子树,走过的点不重复
- 广度优先:一层从左到右,走完所有的结点后再往下一层,走过的点不重复
- 例题
- 深度优先:
- 广度优先:回退往下
图 - 拓扑排序
- 作用:一个图当中,哪些任务可以先执行,哪些任务可以后执行
- 约束:得先完成一个工作,才能开始下一个工作;没有箭头指向说明没有约束
- 注意:执行完后,把结点和线去掉,找下一个没有约束的点开始
图的最小生成树 - 普里姆算法
- 最小生成树的定义:对结点为n的图,选择n-1条边,求和边的权值为最小,从而构成最小生成树
- 树和图的区别:树是没有环路的
- 树的构成要素:结点为n;边数最多为n-1,边如果为n即跟结点数一样,从而形成环路
- 普里姆算法:
- 基本思想:
1)、任意选一个点为红点,看红点与相邻白点之间的路径值,从中选最小值的一条边
2)、将选出边的一端的白点 —> 红点
3)、再从全部红点中与相邻的白点之间,选出最小路径值的边,将边连接的结点转化为红点,以此类推 - ——》注意:选出的边之间不能形成回路
图的最小生成树 - 克鲁斯卡尔算法
- 原则
1)、先确定n-1条边
2)、从图中依次选择最小路径值的边
3)、注意:不能形成环路
算法基础 - 算法的特性
- 输出:至少有一个结果,否则没有意义
算法基础 - 算法的复杂度
- 复杂度
时间复杂度:算法执行下来大概要耗多少时间
空间复杂度:执行过程中要用到的临时空间 - 程序结构不同的时间复杂度挑选
1)、一段程序中有几个时间复杂度,串联——》选时间复杂度最大的那个
2)、嵌套循环:外层n,内层n,一共是O(n2) - 查找二叉树计算:(找某一个结点)
1)、因为二叉树有三层结点,一共有7个结点,所以n是7
查找 - 顺序查找
- ——》思路:挨个比较
- 求平均长度:(1+n) / 2 ——》
1)、1:最好情况,只匹配了一次就查找成功 ;
2)、n:最坏情况,匹配至最后一个,也就是元素的个数 - 时间复杂度:O(n),因为:n+1 —> 1可以省略;n/2 —> 属于 n 这个数量级的
查找 - 二分查找
- 思路:
1)、前提:查找的关键字中,是有序排列的,如果不是有序则不能够使用二分查找法 - 解题步骤:
1)、下标相加 / 2 ,取整(不是四舍五入):1+12=6.5 ——> 6
2)、跟下标为6的元素进行对比
3)、比大小得因为17<18 ——> 确定在左半区
4)、继续求中间坐标:1+5【因为6已经被比较】 / 2 = 3;所以17与10比较,确定在右半区
5)、4+5 / 2 = 4.5 —> 4 ,剩下只有下标为5的元素,如果不是则查找失败 - 时间复杂度:O(log2n),数据越多,比顺序查找O(n)越快
查找 -散列表
- 思路
1)、存储的时候指定个特殊规则,然后根据规则进行快速查找
2)、如果出现冲突,根据处理规矩处理
(1)、第一种处理规矩:线性探测法——》要放的空间被占了,按顺序放在下一个空间,如果下一个空间被占了,再往下一个空间走
(2)、第二种处理规矩:伪随机数法
(3)、第三种处理规矩:再用不同的散列函数 - 预防冲突思路:
1)、研究出好的想法
2)、将空间加大
排序
- ——》考频:重点,上午下午都会随机涉及
- 排序的概念:
- 稳点与不稳定的区别:
1)、稳定的排序:数列中有两个相同值的数,黑色的21在经过排序运算之后,位置不变,仍排在红色的21之前
2)、不稳定的排序:红色的21经过排序运算之后会跳到黑色的21前面来
排序 - 直接插入排序
- 操作步骤:
1)、两个数依次往下进行比较
2)、57 - 68 :57 < 68,位置不发生变化
3)、68 - 59:59 < 68 —>将59插在68之前,59 > 57 —>将59插在57之后。所以最终结果为:57、59、68、52
4)、因为52<57<59<68—>将52插在57、59、68之前,得到52、57、59、68
排序 - 希尔排序
- 取d是5,然后每隔5个元素作为一组,57 - 28,68 - 96,59 - 33,52 - 24,72 -19
排序 - 直接选择排序
- 定义:
1)、第一步,从全部数中选最小的那个,与第一个交换位置
2)、在剩下的数里面选最小的,与第二个数交换,以此类推
排序 - 堆的概念
- 基本思维:
1)、小顶堆:根结点都比孩子结点的值要小
2)、大顶堆:根结点都比孩子结点的值要大 - 基本操作:
1)、好处:相比直接选择排序,从堆中选最小值
排序 - 冒泡排序
- 剩下两个时候就算不用调换也要再排一次
排序 - 快速排序
- 解题步骤:
1)、先定第一个数作为基准,与最后一个元素做比较,如果比它大,则交换位置
2)、左下标左移一个下标,与右端指针指向的元素进行比较
3)、右往前移
排序 - 归并排序
排序 - 基数排序
- 基本思路:
1)、根据个位的数字,将要排序的值,填进相应位置上,各位相同往下排
2)、将由个数收集得到的序列,再根据十位进行收集
排序
- ——》考频:基本考