基本类型:
数值类型:
指针型:存放变量地址的变量类型
int *p = &A
表示只能存储 int 数据类型的地址,&为取地址符号
E = *p1 * 表示是取指针p地址存放的值
比如
#include
using namespace std;
int main()
{
cout<<“Hello World”<<endl;
int a = 10;
cout<<“a:”<<a<<endl;
int *p = &a;
cout<<“p:”<<p<<endl;
*p = *p + 1;
cout<<“p:”<<p<<endl;
return 0;
}
打印出p的值就是存储p的地址0x7ffea227480c,而打印p的值就是10
构造类型
结构体
不同类型的变量组合在一起构成的变量
函数:
这里使用&进行赋值,是因为如果不适用&进行赋值,那么r只是一个临时变量,改变r的值并不能改变result的值
只有当传入的值需要进行改变,需要&进行取值
时间复杂度
线性表:
存储结构:
顺序存储:
链式存储:
双链表
线性表考点
1.
总结:
双链表的插入
顺序表插入的代码操作
新建单链表:
顺序表的归并
链表的归并
逆置:
求最大值:
链表中的最大值:
划分:
栈:
队列:
考点
表达式转换:
转换结果:
中缀转后缀:过程和转前缀类似,只是运算符放到括号后面
利用栈进行转换
中缀转成后缀过程规则:从左到右扫描中缀表达式,遇到操作数就写出来,遇到操作符就入栈,入栈之前,拿当前扫描到的运算符和栈顶中的运算符优先级做比较,如果扫描到的运算符优先级小于或者等于栈顶运算符的优先级,就把栈点的运算符出栈,并将其写入结果表达式中,并对当前扫描到的运算符进行入栈。对于表达式中含有括号的情况,当遇到左括号直接入栈,当栈点运算符是左括号时,所有扫描到的运算符都入栈,直到遇到右括号时候,执行出栈操作,一直到左括号,并写入结果表达式中,左右括号全部扔掉不写,若扫描完中缀表达式中的所有字符,栈中仍然存在运算符,则运算符全部出栈,并写入表达式中
代码:
中缀转成前缀过程规则:从右到左扫描中缀表达式,遇到操作数就写出来,遇到操作符就入栈,入栈之前,拿当前扫描到的运算符和栈中的运算符优先级做比较,如果扫描到的运算符优先级小于栈点运算符的优先级,就把栈点的运算符出栈,并将其写入结果表达式中,对于表达式中含有括号的情况,当遇到右括号直接入栈,当栈点运算符是左括号时,所有扫描到的运算符都入栈,直到遇到左括号时候,执行出栈操作,一直到右括号,并写入结果表达式中,左右括号全部扔掉不写,若扫描完中缀表达式中的所有字符,栈中仍然存在运算符,则运算符全部出栈,并写入表达式中
代码:
后缀转成前缀过程规则:从右到左扫描中缀表达式,把扫描到运算符所对应的子表达式写在运算符后面
用栈实现各种表达式的求值:
1.用栈求中缀表达式的值
规则:左边s1栈存操作数,右边s2栈存运算符,从左到右扫描表达式,当遇到操作数的时候就入s1栈,当遇到左括号就入s2栈,当遇到运算符的时候,就准备入s2栈,如果s2栈是空或者是左括号,则运算符直接入s2栈,如果s2栈不空,并且不是左括号,则当前扫描的运算符优先级大于栈点运算符的优先级,则入s2栈,扫描的运算符优先级小于等于栈的运算符优先级,持续对s2栈进行出栈操作,每出一个操作符,就从s1栈中出栈两个操作数,和运算符进行一次运算(第一次出栈的运算符在右边,第二次出栈运算符在左边),并把运算结果压入s1栈,直到当前扫描的运算符优先级大于栈点运算符的优先级,将扫描的运算符入栈,如果遇到右括号,则将到左括号所有的运算符都出栈进行运算,当中缀表达式都扫描完,s2栈中还有运算符,就把所有运算符都出栈进行运算,并压入栈中,最后s1栈底的数为表达式的结果
2.用栈求后缀表达式的值
规则:从左到右扫描表达式,当遇到操作数的时候就入栈,当遇到运算符的时候,就从栈中出栈两个操作数,和运算符进行一次运算,并把运算结果压入栈,直至结束
2.用栈求后缀表达式的值
规则:从右到左扫描表达式,当遇到操作数的时候就入栈,当遇到运算符的时候,就从栈中出栈两个操作数(第一次出栈的运算符在左边,第二次出栈运算符在右边),和运算符进行一次运算,并把运算结果压入栈,直至结束
配置问题
双端队列
栈的扩展
第四章:串
串:就是把线性表中的元素限制为字符类型的特殊的线性表
串的基本操作
1.赋值操作:
2.KMP算法:
快速的在一个主串中找到需要的子串
第一步:找到不匹配的位置,然后向前找到公共前后缀(如果模式串中有多个公共前后缀,取最长的那个一)
第二步:把前面的公共前后缀移动到后面
3.求解next数组
第五章:
1. 数组
2.矩阵
特殊矩阵
1.矩阵
三角矩阵:
对角矩阵
稀疏矩阵:
存储方法
三元组表示法(顺序存储):对于矩阵中任意一个元素需要存储元素的值和位置,位置包括行标,列标
其中:第一行一般存储信息5,4,4中的5表示有五个值,存储为4X4的矩阵,第二行1表示值为1,0和3表示下标位置
代码:
邻接表表示法(链式存储):
十字链表表示法:
广义表:
2.存储结构
第六章数与二叉树
1.节点的度:节点引出分支的个数
树的度:这颗树所有节点最大分支数
叶子节点:度为0的节点就叫叶子节点(图中黄色的为叶子节点)
双亲:
祖先:从这个节点的双亲节点开始沿着分支一直向上走,走到根节点,路径上所有的节点都是它的祖先
子孙:
兄弟节点:
堂兄弟节点:
树的高度深度及节点的高度深度:
深度:从根节点开始算,高度从最下方节点开始算
树的存储
顺序存储(双亲存储结构):
链式存储结构:
二叉树:
二叉树形态:
完全二叉树:对一个满二叉树,从最底层开始,从右往左逐个的删除节点所得到的二叉树
满二叉树是一个特殊的完全二叉树
二叉树的性质:
存储结构:
1.顺序存储结构:
这种只适用于完全二叉树的存储
2.链式存储结构:
二叉链表存储结构
树的孩子兄弟存储结构
树和二叉树的相互转换:
把孩子节点全部连起来,只保留一条父节点到孩子节点的关系(一般保留最左边的那条关系)删掉多余的关系
二叉树转成树:
深林和二叉树的相互转化:
二叉树的遍历:
树的遍历:树的叶节点只有一个分支,所有有的节点只有两次访问,故树是没有中序遍历的
另一个种说法:
如果一个二叉树是由树转化过来,那么对这个二叉树进行先序遍历,就是对原树进行先序遍历,如果对二叉树进行中序遍历,相当于对原树进行后序遍历
森林的遍历
将森林转化成二叉树,对二叉树进行先序遍历等于对森林进行先序遍历就等于,对二叉树进行中序遍历等同森林进行后续遍历
递归函数:函数体中调用函数自己
先序遍历:visit§位置不同即为不同的遍历,在(2)的位置为中序遍历,(3)的位置为后序遍历
深度遍历非递归方法:
从根节点开始入栈一个节点,如果栈不空就出栈一个元素,如果这个元素左右孩子至少存在一个就入栈孩子(从右边开始入栈),
二叉树层次遍历(广度优先遍历):节点从上到下一层一层,从左到右
节点进入队列的过程
树的后续遍历:
树的层次遍历:
线索二叉树:用空分支(空指针)指向节点的前驱后继的节点
如果一个节点有左空指针,左空分支指向它的前驱,有右空分支,则指向它的后继
中序线索二叉树遍历:
A4是A2的前驱,A2是A4的后继,A2是A5的前驱
先序线索二叉树遍历:
后续线索二叉树:
哈夫曼树:
哈夫曼二叉树:
统计各个字符出现的次数
每次选两个权值最小的值合并
路径:即是上图黄色线的路径
路径长度:路径上的分支数目(上图为3)
树的路径长度:从根到每个节点的路径长度之和
带权路径:(权值:每个字符出现的次数)
哈夫曼n叉树:
二叉树的确定:根据遍历的序列确定二叉树
先序中序序列中,先找根节点,再把中序序列分成两半,两段序列中,确定的根节点为依据在先序中每段的第一个节点就是左右子树节点,然后再根据先序确定的左右子树根节点,在中序中确定其左右子树位置
后续中序序列中,先找根节点,再把中序序列分成两半,两段序列中,确定的根节点为依据在先序中每段的最后一个节点就是左右子树节点,然后再根据先序确定的左右子树根节点,在中序中确定其左右子树位置
图:多对多关系
顶点的度:与节点有关的边的个数(A1的度为3,与A1有关的边有三条)
完全图
极大连通子图:黄色部分为极大联通子图
图的存储
顺序存储:
表中紫色部分代表行标和列标,行标代表起点,列标代表终点,其他部分为对应的边是否存在,∞0代表不存在,1代表存在
度为行列的和
链式存储:
无向图:
邻接多重表:vi为起点,vj为终点,
图的基础算法:
深度优先遍历
广度优先遍历(BFS)
生成树:删掉图的一些边,让其变成一个树,
最小生成树:生成的树的权值最小,从一个顶点开始,找到和这个顶点相连的最小的边,把边和相连的顶点并入,再在这两个顶点相连形成的树中的找到相连的最小的边和相连的顶点并入,这样依次把所有的点都并入图中
普利姆算法:从一个顶点开始,相连的最小边和顶点并入
克鲁斯卡尔:把当前未被并入的,且并入后不会形成环的权值最小的边并入
并查集:每当并入一条边之前,检查相连的两个顶点是否属于同一个树,如果不是,才把边并入,并把其中一个节点连接到另一个节点上作为孩子节点
最短路径:
迪杰斯塔拉算法
dist:记录起点到其他各顶点的长度
path:存储顶点到其最短路径上前一个顶点的信息(-1表示最短路径上没有前一个顶点,到顶点1,2,3的前一个顶点都为0)
set:标记哪些顶点被选入最短路径
弗洛伊德算法:A:保存的任意两个顶点之间的最短路径长度
path:保存任意两个顶点最短路径的中间点
拓扑排序:
AOV网
关键路径:
在AOE网中,从原点开始,到汇点结束的具有最大长度的那条路径叫关键路径,也是工程完成的最短的时间
每条边代表活动的执行时间
如果某个事件(顶点)有多条边(活动的执行时间),最晚活动的时间就是这个事件最早发生时间
所有事件最早发生时间例子:
所有事件最迟发生时间例子:
所有活动最早发生时间例子:
所有活动最迟发生时间例子(事件最迟发生时间减去活动时间):
活动的最早发生时间和最迟发生时间相同的就是构成关键路径
第八章排序
直接插入排序:把第一个数据作为第一个序列,再依次拿到后面的数据和序列进行比较,根据大小插入到合适的位置上。代码中的n代表要排序的个数
简单选择排序:在无序序列中找到最小的数据,和第一个数据交换位置,再找到第二个最小的和第二个数据交换,依次结束
冒泡排序:依次循环每个关键字,每次发现当前扫描到的关键字比前一个小,就相互交换位置,扫描完成一遍后,最大的关键字会排列到最后放,后面依次重复
希尔排序:取序列的1/2并向下取整,进行两端的对比排序,直到取序列的1/2的值为1
快速排序:
选择第一个元素,把小于他的放在左边,大于他的放在右边,根据这个元素可以分为左右两个,再依次对这两个做排序
一开始的时候,low是0,high为数组长度
堆排序:堆是一个完全二叉树,大顶堆,小顶堆,要求其每个节点的值,都不小于(大于)其孩子节点的值
插入节点:把需要插入的节点链接到所有节点的最后面,然后依次和其父节点比较,比插入节点小的就交换位置
删除节点:把要删除的点拿掉,然后把最后一个位置的顶点插入到删除的位置,再和子节点进行比较调整位置
左边是调整函数,右边是堆排序函数
归并排序:(二路)把所有的元素两两一组进行排序,再归并成一个
基数排序:捅的个数和每位最多的基本单元一致,下列为十进制的数,所以有十个桶
不满三位数的,在前面补0,补满三位,开始第一步,从个位开始,把个位对应的数字放入对应的桶中,然后依次出,先进的先出,然后十位,百位依次操作
最低位相同的放在同一个桶中
进行数据收集
第二次根据第二位(十位)上的数字,放到对应的桶中
再对桶中的数据进行收集:
第三次分配,根据百位的数据放入对应的桶中
数据收集结束,排序结束
稳定性判断:
两个(或者多个)相同的值,在经历排序后,放在一起前后顺序是不变的,就是稳定排序,否则就是不稳定的
起泡排序是稳定的
直接插入排序是稳定的
归并排序
9.查找
线性查找
二分查找:(要求序列是有序的)
折半查找:
在有序数据中,找到low 和 high的位置,然后(low+high)/2向下取整,计算中间的位置
然后和要查找的值进行比较,大于(小于),就更换low(high位置)继续以这种方式查找
折半查找判定树
黄色为成功找到次数,红色为失败查找次数
分块查找:
分成5块,把每块中最大的放到列标中,第一个记为low,最后一个记为high,计算mid =(low+high)/2 比较mid值和查找的值的大小,如果大于(小于)就更改low(high)位置
继续计算,找到查找的数字在那个块中,就遍历那块
maxKey:最大关键字,low,high:关键字的范围
二叉树排序:
如果有左子树,那么左子树的值都小于该节点关键字的值,如果有右子树,那么右子树中的值都大于该节点的关键字值
查找关键字,看查找的关键字从根节点进行比较,如果小于,走左子树,如果大于,走右子树
递归实现
二叉排序树插入关键字:
和查找的逻辑类似,找到位置,进行插入
平衡二叉树:
每个节点的大小为左子树长度减去右子树长度
LL:一棵二叉排序树在其左子树上插入一个节点使得不平衡,
RR:一棵二叉排序树在其右子树上插入一个节点使得不平衡,
B树-1:
B+树:
散列表:根据关键字值来计算出关键字在表种的地址
哈希表:
下方的例子为关键字对13取余
这种一个里面有多个值的就叫冲突
冲突的解决方法:
从冲突的位置开始向后扫描,遇到没有内容的的位置就插入到这个位置上
查找成功
查找不成功
冲突的处理方法:
例子:
n是关键字个数,len是表长
时间复杂度:
错题
1.
正确答案:c ; 自己选择错:A
原因:首先要找到长度为m的链表的末端才能接长度为n的链表
2
正确答案:c ; 自己选择错:A
原因:
3.
正确答案:B ; 自己选择错:D
解析:对于顺序存储的线性表,如果在第(i+1)个位置之前插入一个新元素,那么需要移动的元素数量是i。这是因为新元素需要插入到第i个位置,所以第i个位置及其后面的所有元素都需要向后移动一个位置。现在,考虑插入位置i是随机选择的,那么i的取值范围是1到n+1(因为要在第(n+1)个位置之前插入)。要计算平均移动次数,我们需要对每种可能的i值计算移动次数,然后取平均值。由于i是随机选取的,我们可以假设每个i值被选中的概率是相同的。因此,平均移动次数是:
(1 + 2 + 3 + … + n) / (n+1)
这是一个等差数列的求和问题,其和为:
n * (n + 1) / 2
然后,我们将其除以(n+1)来得到平均移动次数:
(n * (n + 1) / 2) / (n + 1) = n / 2
所以,平均移动次数是n/2。
因此,正确答案是:
B. n/2
4.
正确答案:C ; 自己选择错:A
在静态链表中,通常使用数组来描述链表,数组中的每个元素通常包含两部分信息:一是数据域,用于存放数据元素的值;二是游标(或称为指针),用于存放下一个元素在数组中的位置(下标)。
所以,静态链表中的指针(或游标)实际上表示的是下一个元素在数组中的位置。