数据结构与算法基础
数组
一维数组a[n]存储地址计算公式:a+ilen
二维数组a[m][n]存储地址计算公式:
1、按行存储:a+(in+j)len
2、按列存储:a+(jm+i)len
首先起始地址为a,在计算过程中可以根据图来计算,方便理解,不必死记公式。二维数组先行后列
1 1 1 1 1
1 1 1 1 1
1 1 1 1 0
0 0 0 0 0
0 0 0 0 0
因为a[0][0]为起始地址a,并且每个元素占两个字节,所以a[2][3]地址为a+132=a+26
稀疏矩阵
计算方式就是使用代入法,将A0,0中的0,0代入到公式中,避免公式的复杂性。
线性表
数组、链表
队列、栈
主要考察这种类型的题目,简单
广义表
广义表的长度:以最外层括号为基准,里面元素的个数即为长度。
广义表的深度:括号嵌套的层数表示深度。
广义表的基本运算:取表头:head(Ls)和取表尾:tail(Ls)
表尾是除了第一个元素以外所有元素
如例2中,head(head(tail(LS1)))
树与二叉树
结点的度:一个节点有多少孩子节点就有多少度
树的度:树中最大结点度就是树的度
叶子结点:树中没有孩子结点的就是叶子结点
分支结点:顾名思义,带有分支的结点
内部结点:非叶子结点和根结点的结点
兄弟结点:拥有同一个父结点的结点
二叉树
二叉树的遍历
层次遍历:1 2 3 4 5 6 7 8
前序遍历:1 2 4 5 7 8 3 6
中序遍历:4 2 7 8 5 1 3 6
后续遍历:4 8 7 5 2 6 3 1
反向构造二叉树
A
/
B C
/ \ /
H F G
/
D
/
E
树转二叉树
孩子结点 -》左子树结点
兄弟结点 -》右孩子结点
主要看连线的那图,最左边的结点都当作根节点,其余兄弟结点都当作右节点。使用连线法可直观得出结果。
查找二叉树
左子树小于根节点,右子树大于根节点(左子树结点都小于根节点,右子树结点都大于根节点在删除和插入的时候需要牢记)
最优二叉树(哈夫曼树)
树的路径长度:树中路径的累加
权:每个结点上的数字
带权路径长度:树的路径长度 * 结点上的权值
树的带权路径长度(树的代价):树的所有叶子结点的带权路径长度累加
构造哈夫曼树
在计算过程中要保证每次选取最小的两个值相加(包括计算出来的结果),如果计算出来的结果不是剩下最小的就另起一个如下
线索二叉树
根据前、中、后序遍历可以得知指针指向
平衡二叉树
任意结点的左右子树深度相差不超过1
每个结点的平衡度只能为-1、0或1
图
无向图:点与点之间连线没有箭头
有向图:点与点之间连线有箭头
完全图:
邻接矩阵
在矩阵里,例如R0,1第一行第二个表示1能否到2,能就是1不能就是0.
邻接表
类似hashmap结构,在链表中存储的能到达的点和距离两个信息
图的遍历
如上图
广度优先遍历:V0 V4 V3 V1 V6 V2 V5 V7 (按照链表后的顺序去找到对应的结点)
深度优先遍历:V0 V4 V6 V7 V1 V2 V5 V3 (按照链表后第一个回溯找之前结点)
拓扑排序
图的最小生成树
(树和图最大的区别是是否有环路)
普里姆算法
原则是不能形成环路,以点为中心选择最短路径一次相连
克鲁斯卡尔算法
不能形成环路,以边为中心,选择最短的边,将点连接起来
算法基础
算法的复杂度
时间复杂度:是指程序运行从开始到结束所需的时间。通常分析时间复杂度的方法是从算法中选取一种对与所研究的问题来说基本运算的操作,以该操作重复执行的次数作为算法的时间度量。
常见对算法执行所需时间的度量:
O(1) < O(log2n) < O(n) < O(nlog2n) < O(n2) < O(n3) < O(2n)
O(log2n):典型的对数复杂度算法是二分查找算法。不断迭代取当前范围的中间值,判断目标值是小于还是大于中间值,排除不含目标的那一部分。及时数组长度翻了一倍也只需要多迭代一次!,随着数组长度的增加,运行时间将呈对数增长。
O(nlog2n):同时包含对数和线性部分,常见的算法是归并排序,利用迭代将数组分成小块,对每个小块拆分排序,然后顺序重新将各个小块合并在一起。
O(2n):随着规模增加,运行时间按照固定倍数增长,例如斐波那契数列中的第n项,每当输入 n 增加 1 时,执行的操作数量就会翻倍。这是因为我们没有缓存每个函数调用的结果,所以必须从最开始重新计算所有先前的值。因此,该算法的时间复杂度为 O(2n)。
空间复杂度:是指对一个算法在运行过程中临时占用存储空间大小的度量。一个算法的空间复杂度只考虑在运行过程中为局部变量分配的存储空间大小。
散列表
1、线性探测法:冲突就+1
2、伪随机数法:随机
排序
直接插入排序
希尔排序
直接选择排序
堆排序
冒泡排序
快速排序