上午下午都会考,且难度最高
重点:线性表、树与二叉树、排序与查找、算法基础及常见算法
(资料图片)
数组
主要考察一维二维数组存储地址的计算
一维数组存储地址计算:a+i*len;i为索引号,len是每个位置所占的内存大小
二维数组存储地址计算(分为按行优先和按列优先):如五行五列的二维数组a中各个元素占两个字节,则元素a[2] [3]按行优先存储的 存储地址为:13*2+a
稀疏矩阵
即元素先以上下三角矩阵方式排列,然后将其存入数组
考察:计算矩阵中某一个元素对应的数组的下标
数据结构
1.数据结构的概念:数据结构即计算机存储、组织数据的方式
2.数据逻辑结构:分为线性结构和非线性结构;非线性结构又可以分为树形结构(不存在环路)和“图”(可能存在环路)。
线性表的概念
1.概念:线性表是线性结构的基本表现
2.线性表常见的存储结构——顺序表(连续的空间下存储数据):开辟一系列的连续的空间,然后采用一维数组的方式来顺序存储信息
3.线性表常见的存储结构——链表(不连续的空间下存储数据):每个存储单元都包含了存储数据的空间及存储指针的空间(因为这一系 列的空间不一定是连续的,指针的作用则是作为箭头,在两个空闲的空间之中起到指引作用)
4.三种不同的链表——单链表:即只有一种指针在空间之间依次指向的链表,在单链表中用头指针作为栈顶指针时,入栈和出栈都不 需要遍历链表
5.三种不同的链表——循环链表:把尾元素的指针指向头结点(好处是:若当前结点是在尾元素,想要再次经过之前的某个元素,则可 以继续next往下走,,直至遇到那个元素,而无需重新定位)的链表
6.三种不同的链表——双向链表:是可以双向的移动的链表(绝大部分结点都必须要有两个指针),即可以通过头节点往尾结点移动, 也可以通过尾结点向头节点移动的链表
7.链表的特点
(1)查询慢:链表中地址不是连续的,每次查询元素都必须从头开始
(2)增删快:链表结构,增加/删除一个元素,对链表整体结构没有影响,所以增删快
(3)结点:链表中的每一个结点包含了一个数据源(存储数组),两个指针域(存储地址),两个指针分别存储当前结点的位置和下一个 结点的位置,在单链表中,两个结点之间有一条链子连接,但是只是单箭头指向,即从a到b,但不能从b到a,而双向链 表则是在两个结点之间架设两条链子,互相指向,此时结点a可以到b,结点b也可以到a
链表的基本操作
1.单链表的删除节点:如a1——>a2——>a3;这三个结点,若要删除a2,则是让指针P的next=指针Q的next;P的next表示指针P(指 向a1的指针)的下一个指针。
2.单链表的插入结点:如a1——>a2;若要在a1与a2之间插入一个结点a3;则是令S(指向a3的指针)的next=P的next以及P的next=S
3.双向链表的删除结点
4.双向链表的插入结点
空间性能的比较
1.存储密度:顺序存储的存储密度为1(更优),而链式存储的密度则小于1
2.容量分配:顺序存储需要事先确定,而链式存储则是动态更改(更优)
时间性能的比较
1.查找运算:普遍情况下二者时间复杂度一样,但特殊情况下顺序表更为方便
2.读运算:顺序存储更优
3.插入运算:链表更优
4.删除运算:链表更优
队列与栈的概念
1.队列的概念及特点:结点的存储及读取遵循先进先出的规律,原因是队列可以对两端进行操作
2.栈的概念及特点:结点的存储及读取遵循先进后出的规律,原因是栈只能对一端进行操作
3.特殊队列——循环队列:即一种呈圆形的队列,尾指针会随着结点的依次存储而逐渐后移直至与头指针重合;因此:队满条件=队 空条件=“头指针等于尾指针”;解决队满与队空判断条件容易混淆的方法:方法(1)少存一个结点:此时的队 满条件为(tail+1)%size=head
队列与栈的练习
图注:对A选项,让四者依次从左边进入,然后依次从左边出去即可实现;对B选项,先让e1和e2依和e4依次先从左边进入, 再让e3从右边进入,然后出去的顺序就可以是e4、e2、e1、e3;对C选项,让e1和e2从右边进入,e3和e4从左边入, 然后就可以实现C选项;因此答案为:D
注:栈和队列都属于线性表,不过他们都是操作受到限制的线性表
考察广义表的长度计算、深度计算、head及tail运算
广义表的概念
1.概念:广义表是n个元素组成的有限序列,是线性表推广,通常用递归的形式定义,即表里可以包含表(嵌套)
2.表示:LS=(a0,a1.......,an)。注:其中LS是表名,ai是表元素,它可以是表(称作子表),也可以是数据元素(也称原子).其中n是广义 表的长度(最外层包含的元素个数),n=0的广义表为空表;而递归定义的重数就是广义表的深度,直观的说,就是定义中嵌套 的次数(原子的深度为0,空表的深度为1)
广义表涉及的运算
1.head运算:即"取表头"(表头就是最外层的第一个表元素)
2.tail运算:即"取表尾"(表尾就是除了表头以外的所有其他元素组成的新广义表)
基本概念:
结点:图中的1、2、3...数字圆形都表示结点
结点的度:指一个结点所有的孩子结点数(如结点1的度就是2,结点3的结点度即为1)
树的度:即一个树当中,结点的度最高的那个结点的度数
叶子结点:如7、8等没有孩子结点的结点称之为叶子结点
分支结点:即没有分支的结点
内部结点:非叶子结点又非根节点(最上面的那个结点)
父节点和子节点:这是一个相对概念,如2就是4的父节点,4就是2的子节点
兄弟节点:同属于一个父节点的子节点间称之为兄弟节点
层次:行数即为层次,该图中的层次即为4
满二叉树与完全二叉树(特殊的二叉树)
1.满二叉树的概念:整个树可以构成一个完成的三角形即为满二叉树
2.完全二叉树的概念:最后一行的叶子节点的父节点必须要有兄弟结点且它要么也是叶子结点要么只有一个结点且该结点和最后一行 的叶子结点紧挨着
3.二叉树的重要特征:
二叉树遍历
分为两大类的遍历方法:层次遍历与(前序遍历、中序遍历、后序遍历)
遍历:将结点按照一定顺序打印出来
1.层次遍历:从根节点开始,按照从上到下,从左到右的顺序依次遍历结点
2.前序遍历(跟左右):即将跟结点的访问放在最前面。然后访问左右子树结点
3.中序结点(左跟右):先访问左子树结点(左子节点以及它的所有子节点构成的新二叉树),再访问根节点,再访问右子树结点
4.后续遍历(左右跟):先访问左子树结点,再访问右子树结点,再访问跟结点
反向构造二叉树(重点考察)
1.概念:知道二叉树的遍历序列,然后反向推出二叉树的构造
2.例题
图注:解题方法-是标注根节点,然后推左右结点
树转二叉树
由于树的应用主要是二叉树的应用,所以我们需要将树转化为二叉树
1.树转二叉树的基本原则:某个结点的孩子结点都会成为它的左子树结点,某个结点的兄弟结点都会成为它的右孩子结点
2.树转二叉树例题
查找二叉树(一类特殊的二叉树)
1.概念:(每一个)跟节点的左子树结点的键值都小于跟节点,根节点的右子树结点都大于根节点的一类二叉树即被称之为查找二叉树 (或排序二叉树)
2.价值:这种二叉树能极大的提高查询的效率和速度
3.插入运算:
(1)若该键值已存在,则不再插入
(2)若查找二叉树为空树,则以预插入的新结点为查找二叉树
(3)将要插入的结点键值与插入后父结点键值比较,就能确定新结点的位置是父结点的左子节点,还是右子节点
4.删除结点:
(1)若待删除结点是叶子结点,则直接删除
(2)若待删除结点只有一个子节点,则将这个子节点与待删结点的父节点直接连接
(3)若待删除结点p有两个子结点,则在其左子树上,用中序遍历寻找键值最大的结点s,用结点s的值代替结点p的值,然后删除原 结点s,结点s必属于上述(1)或(2)
最优二叉树(哈夫曼树)
考察哈夫曼树的构造
这种二叉树是一种工具,用于哈夫曼编码,哈夫曼编码是一种无损压缩的方式,哈夫曼树中每一个父结点的键值都等于其子结点之和 (不是子树结点);
1.树的路径长度:即在树中指定一条路径,将路劲段数相加
2.权:在最优二叉树中即某个叶子结点的键值(该键值将代表某个字符出现的频度)
3.带权路劲长度:分为结点和二叉树的带权路径长度,结点的带权路径长度等于路径长度*权,二叉树的带权路径长度即为所有结 点的带权路径长度之和
4.哈夫曼树设计的基本思想:让二叉树的带权路径长度尽可能小
线索二叉树
由于二叉树中有许多结点处于空闲的状态,有许多指针并未被利用,而将其空闲资源利用起来方便遍历则是线索二叉树的由来,线索 二叉树根据遍历的分类可以被分成三种线索二叉树:前序二叉树、中序二叉树、后序二叉树
图注:红线代表推出,绿线代表由来;如图一中二叉树的前序遍历为:ABDEHCFGI;
平衡二叉树
即更为平衡、更为饱满的二叉树
1.概念:任意结点的左右子树深度不能相差超过1,即每结点的平衡度(该结点的左右子树结点的深度之差)只能为-1、0或1
图注:图一和图二都属于排序二叉树,但图一的查询效率远低于图二,因为图一不属于平衡二叉树。而图二属于平衡二叉树
图分为有向图和无向图
1.无向图:在该图中,若每一个顶点与其他所有顶点有一条边相连,则称该图为无向图
2.有向图:若每一个顶点与其他所有顶点都带有两条有向边互相联系,则称该图为有向图
图的存储——邻接矩阵
1.矩阵的大小:若有a个顶点,则该矩阵为aXa阶矩阵
2.矩阵的内容:矩阵内只有0和1两种数字,以矩阵为第一行为例,第一个结点按照和后续每一个结点是否有边来确定矩阵的内容,若 有边则对应的该行该列值为1,无边则为0
3.图的广度遍历过程:从图中某个顶点触发,在访问了顶点之后,一次性访问顶点的各个未被访问的邻接点,然后分别从这些邻接点 出发,依次访问它们的邻接点,并使“先被访问的邻接点”先于“后被访问的邻接点”被访问,直到图中所有已访 问的顶点的邻接点都被访问到
图的存储——邻接表
1.概念:首先会有一个表记录每一个结点,即把每个顶点的邻接顶点用链表表示出来,然后用一个一维数组来顺序存储上面每个链表 的头指针
图——图的遍历
图的遍历分为深度优先遍历和广度优先遍历
1.深度优先遍历:首先一条路劲试探到底,然后再回退回来继续深入下一条路劲
2.广度优先遍历:即从顶点开始,一行一行遍历
图——拓扑排序
用一个序列来表达哪些事件可以先执行,哪些事件可以后执行
1.AOV网络:我们把用有向边表示活动之间开始的先后关系,这种有向图称之为用顶点表示活动网络,简称AOV网络
图的最小生成树——普利姆算法
1.最小生成树:如图若有a个顶点,则在图中取a-1条边,用这些顶点和边重新构成一个树,而路径值最短情况下的树即为最小生成树
2.求最小生成树——普利姆算法(最近点法):任选一个结点A并将其标定为红点集,其余所有结点标定为蓝点集,然后将离红点集A距 离最短的结点B连接起来并将其也纳入红点集,然后继续寻找蓝点集和红点集之间的最 短距离结点并将其纳入红点集,重复该操作直至所有结点被纳入红点集(将结点纳入红点 集时注意不能形成环)
3.求最小生成树——克鲁斯卡尔算法(最近边法):任选一条边并将其标定为红点集,其余所有边标定为蓝点集,然后将离红点集边端点 距离最短的边连接起来并将其也纳入红点集,然后继续寻找蓝点集和红点集之间的最 短距离边并将其纳入红点集,重复该操作直至红点集纳入了结点数-1数量的边(将边纳 入红点集时注意不能形成环)
算法的特点
1.有穷性:算法必须在执行有穷步之后结束
2.确定性:算法中每条指令都必须有确切的含义,不能含糊不清
3.算法必须有0及以上的输入
4.算法必须有1及以上的输出
5.有效性:算法的每个步骤都能有效执行并得到确定的结果。例如0=a,b/a就无效
算法的复杂度
包括时间的复杂度(必考)和空间的复杂度
1.时间复杂度的概念:时间复杂度是指程序运行从开始到结束所需要的时间
2.时间复杂度的分析:通常分析时间复杂度的方法时从算法中选取一种对于所研究的问题来说是基本运算的操作,以该操作重复执行 的次数作为算法的1时间度量
3.时间复杂度的计算:一般来说,在算法中,原操作重复执行的次数是规模n的某个函数T(n)。由于许多情况下要精确计算T(n)是困难 的,因此引入渐进时间复杂度在数量上估计一个算法的执行时间,其定义如下
$$如T(n)=3n^3+2n^2+n,则T(n)=O(n^3)$$$$且:O(1)查找的目的是为了在众多关键值中查找到想要的关键值
顺序查找
1.概念:将待查找的关键字为key的元素从头到尾与表中元素进行比较,如果中间存在关键字为key的元素,则返回成功;否则,查找失败
2.顺序查找的平均查找长度:n+1/2
3.顺序查找的空间复杂度:O(n)
4.顺序查找的优缺点:方法简单但效率较低
二分查找法
不是所有序列都能用二分查找法,能使用该方法的前提是该序列是有序排列的(如从大到小或从小到大)
1.概念:首先将n个有序排列数组的元素最小索引值(非零)和最大索引值相加除以二,然后对其进行向下取整,然后查询该取整后的索引值对应的键值并与待查询键值进行比较,若小于键值则对其右边数组继续使用二分法(从小到大排列的数组中)
2.二分取整的时间复杂度:O(log2n)
3.优势:效率高
散列表
在数据进行存储时遵循一定的规则
1.散列表的概念:散列表查找的基本思想是:已知关键值集合U,最大关键字为m。设计一个函数Hash,它以关键字为自变量x,关键字的存储地址为因变量y,将将关键字映射到一个有限的、地址连续的区间T中,这个区间就称为散列表,散列查找中使用到的转换函数称为散列函数
2.散列表中可能遇到的问题:由于关键值和地址是函数关系,所以可能出现两个关键值对应同一个地址的情况
3.解决办法——线性探测法:按出现顺序来定义函数中y值相同的关键值的处理,如b和a冲突,则将b放在a的下一个空单元
4.解决办法——伪随机数法
必考内容
数据的排序按照稳定性可以分为稳定和不稳定排序,按照空间结构可以分为内排序和外排序
直接插入排序
1.概念:即当插入第i个记录时,r1、r2、....rn-1都已经排好序,因此,将第i个记录ri依次与ri-1......r2、r1进行比较,找到合适的位置插入,它简单明了,但速度很慢
2.直接插入排序的步骤
(1)从第一个元素开始,该元素可以认为已经被排序
(2)取出下一个元素,在已经排序的元素序列中从后往前扫描
(3)如果新元素小于已排序元素tmp (4)重复步骤3 j - -,直到找到已排序的元素小于或者等于新元素的位置 array[ j ]<=tmp (5)将新元素tmp插入到该位置 array[ j+1] = tmp (6)重复步骤2~5 3.排序方法图解 4.算法效率 平均时间复杂度:O(N^2) 两个for循环嵌套 最好时间复杂度:O(N) 有序时,j不需要回退,只剩下一个for循环 希尔排序 属于插入排序的一种,效率高于直接插入排序,善于应对大量数据的排序 1.概念:先取一个小于n的整数a1,然后把文件的全部记录分成a1个组,分组方法为:所有距离为d1的的倍数的记录放在同一个组中。分好组后再在各自的组内进行直接插入排序,排序完成以后解除分组,再取第二个小于a1的整数a2,再对该文件的所有记录进行相同方法的分组并同样进行直接插入排序,再取第三个小于a2的整数a3重复该操作........直至所取的整数an等于1为止 如图 2.算法效率 直接选择排序 1.概念:首先在所有记录中选出排序码最小的记录,把它与第一个记录交换,然后在其余的记录内选出排序码最小的记录,与第二个记录交换....依次类推,直到所有记录排完为止 堆排序 1.堆的概念:设有n个元素的序列(K1、K2、.....Kn),当且仅当满足下列关系之一时,称之为堆: (1)ki<=k2i且ki<=k2i+1;(即每一个结点的孩子结点都比自己大) (2)ki>=k2i且ki>=k2i+1;(即每一个结点的孩子结点都比自己小); 其中(1)称为小顶堆(2)称之为大顶堆 2.堆排序的基本思想:先将序列建立堆,然后输出堆顶元素,再将剩下的序列建立堆,然后再输出堆顶元素,依次类推,直到所有元素均输出为止,此时元素输出的序列就是一个有序序列 3.初建堆的过程:对于一个二叉树,要将其调整为大顶锥,应有如下步骤: (1)取树中的非叶子结点 (2)将非叶子结点各自与其子结点的键值进行比较(从下往上),如果比其中一个小,则与其交换位置,若比两个都小,则与最大的交换位置 4.堆排序的过程: (1)初建堆 (2)输出堆顶 (3)取一个叶子结点为新跟结点 (4)再次进行堆的重建 (5)输出堆顶...... 5.冒泡排序 1.概念:冒泡排序的基本原理是通过相邻元素之间的比较和交换,将排序码较小的元素逐渐由底部移向顶部,由于整个排序的过程就像水底下的气泡一样逐渐向上冒,因此称为冒泡算法 2.步骤:一个数组中若有n个元素,对其采用冒泡排序:将第n个元素与第n-1个元素进行比较,若第n个元素较小,则将其与n-1个元素交换位置,再将n-1位置的元素与第n-2位置的元素进行比较....重复该操作 快速排序 1.概念:快速排序采用的是分治法,其基本思想是将原问题分解成若干个规模更小但结构与原问题相似的子问题。通过递归地解决这些子问题,然后再将这些子问题的解组成原问题的解(通俗的讲:就是把一个数组拆成了俩个数组) 2.步骤 (1)在数组中任取一个数为基准 (2)定义一个指针,先指向左边第一个数,再指向右边第一个数,再指向左边第二个数,再指向右边第二个数.... (3)将基准于指针指向的数进行比较,若该数大于基准,则和基准交换位置,若小于基准则位置不变 (4)最后将得到一个以基准为分割数的,右边大于基准的数组集合,左边小于基准的数组集合 归并排序 1.概念:归并也称合并,是将两个或两个以上的有序子表合并成一个新的有序表。若将两个有序表合并成一个有序表,称为二路合并 2.步骤:合并的过程是:比较A[i]与A[j]的排序码大小,若A[i]的排序码小于等于A[j]的排序码,则将第一个有序表中的元素A[i]复制到R[k]中,并令i和k分别加1;如此循环下去,直到第一个有序表比较和复制完,然后再将另一个有序表的剩余元素复制到R中 基数排序 1.概念:将关键字拆分为个位、十位、百位...并对其各自位进行排序最后得出结果 2.步骤:对于一个数组R (1)先收集其个位并对其个位进行排序(个位相同的则按照出现顺序紧挨着) (2)按照个位排序的顺序将数组元素进行排序 (3)对刚刚排号的数组进行收集十位进行排序 (4)再将数组按照十位排序的顺序将数组元素进行排序 (5).......重复该操作,直至位数排尽 各个排序算法的时间复杂度和空间复杂度及稳定性(必考)平均时间复杂度 最好时间复杂度 最坏时间复杂度 空间复杂度 稳定性 O(n^2) O(n) O(n^2) O(1) 稳定 平均时间复杂度 最好时间复杂度 最坏时间复杂度 空间复杂度 稳定性 O(nlogn) O(n^1.3) O(n^2) O(1) 不稳定