标签:标记 推理 数据结构与算法 长度 恢复 树的高度 如何 非递归 非递归算法
1.描述一个算法优劣用计算次数的
数量级。1M/1G/1T。
与问题相关的规模用n
T(n)=n^2/n^3
2.常见的时间复杂度(用大O表示法表示)
常数阶 O(1)
线性阶 O(n)
平方阶 O(n^2)
对数阶 O(logn)
nlogn阶 O(nlogn)
立方阶 O(n^3)
指数阶 O(2^n )
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)
logn 是2为底n的对数,2通常省略
迭代就是O(n)
计算时间复杂度可以用横向展开*纵向进行计算
----------------------
1.顺序表
*通过存储的方式分类可以用为为,存元素本身和存元素的地址
一般存不同数据类型的元素存元素的地址
*根据是否能进行扩充修改分为动态顺序表和静态顺序表
* 顺序表由表头与数据区两部分组成,而根据二者之间的关系可将顺序表分为
一体式结构与分离式结构
* 为了考虑数据的动态变化
通常采用分离式
* Python中 list 和 tuple 就是采用分离式、动态顺序表的数据结构。
因此,可以通过顺序表连续的特点通过下标找到该元素的位置
* 扩充策略,空列表分配8个元素,四个字节存储区,采用的存地址。
再扩充,区满倍增4,阈值50000采用一倍
2.链表
*因为顺序表是连续存储数据的,
所以在扩充修改时时间复杂度很高
所以引出了另外一种链表数据结构。而
它与顺序表都是线性表,是一维的数据结构。
*至今,链表的数据基本结构有数据区、链接区。数据区+链接区=结点
数据区存放数据,链接区存储它关联的下个元素地址。
第一个节点称为头结点,第二个节点称为尾节点
* 根据连接的方向,可以分为单向链接和双向链接
* 从时间复杂度来看,链表和顺序表没差多少。
在存数据时链表占内存多,但是可以分散
顺序表可一通过下标一次找到,但必须有一块连续的存储空间
* 必须得有个_head指向第一个节点,我们称之为首结点
* 链表中不在首位,在指定位置增删查都需要从头遍历。使用cur、pre游标配合count进行操作
* 构建一个链表数据结构要定义两个类,一个是Node结点类,一个是链表类。结点类是存储数据和next指针的,
链表类是将个节点串穿起来
3.栈
* 链表顺序表描述是数据如何存放,而栈描述的是数据的操作特性,栈是单口,后进先出
4.队列双口,先进先出
* 栈与队列相比:栈,一段开口的容器,从哪进从哪出,先进的被压到底下只能后出,后进的反而可以先出。
队列:一个通的管道,一端进一端出,也就是先进先出。
5.排序算法
1.冒泡
2.选择排序
3.插入排序
4.希尔排序
5.快速排序 --->核心就是找位置。两个游标互换
快速排序时间复杂度 n*logn
6.归并排序 ---对新列表进行操作,使用递归式不断开辟新空间,浪费内存,但时间上是最理想的,最稳定的。
面试:1)你知道哪些排序算法
2)写几个你所知道的排序算法,必须掌握快排
7.搜索
*二分法查找 ---- 查找范围必须是有序的顺序表。优点:查找速度快,平均性能好;分为递归版本和非;递归版本。
8.递归与循环
9.tree
1)基本名词术语
* 节点的度:有几个子节点;树的度:整个最大的节点度
* 叶节点:度为零的结点 分支节点:
* 层次的定义:从根开始定义起,根为第一层,根的子节点为第二层
* 深度的定义:节点的最大层次
* 有序树和无序树:根据树中子节点之间没有用顺序关系判断
2)树的种类
无序树
有序树
* 二叉树:
完全二叉树:高度为h,除了h层,其余所有节点都达到最大度
满二叉树:所有层必须达到最大度
平衡二叉树
排序二叉树
* 霍夫曼树
* B树
3)二叉树必须要掌握:
* 遍历方法:层次遍历(广度优先遍历)、先序、中序、后序等深度优先遍历-----递归算法与非递归算法
(根据 根 的位置命名,左右固定,看根在哪个位置)---无限追踪到最小二叉树。
* 层次遍历:通过队列+循环来实现
* 深度遍历:通过递归来实现,打印,找树的顺序来判断是先序中序还是后序
* 根据遍历序列恢复二叉树
4)用于递归的终止判断放到最前面
9.快速排序最优时间复杂度nlogn
这种情况是你每次找出来的枢值位于整个序列的中间左右,这样在每次分的时候,分别对他左右两边进行重复操作。
而每次操作时间复杂度是n,一共进行logn次操作,总共的时间复杂度是nlogn。可以把这种情况理想成完全二叉树
(左右两个子树的高度差的绝对值不超过1),这样它拆分到叶子结点刚刚为nlogn次。每一次搜索的时间复杂度为n
那么一共就是nlogn
而最坏时间复杂度是n方,也就是说每次分的的时候,枢值取的都是最小或最大,取的都是两边的。
而这种情况与上面类比相当于非平衡二叉树,取极限情况,二叉搜索树将退化成近似链或链,
此时,其操作的时间复杂度将退化成线性的,即O(n)。而每次搜索为n,一共分n方。
10.具有n个结点的非空完全二叉树的深度为h=logn+1.
11.动态规划-------------------
1.与数学归纳推理法想结合去思考。
1)马尔科夫模型A(i-1)----->A(i)。就是说每后一项都由前一项推理出来,这种推理被称为贪心法。
2)高阶马尔科夫模型A{1,2,3....i}----->A(i+1)。后一项需要它前面的每一项才能推理出来。这种推理称为动态规划
12.桶排序:
1)原理:桶排序也称计数排序,就是将数据集里面所有元素按顺序列举出来,然后统计元素出现的次数。
最后按顺序输出数据集里面的元素。
实现方式:
[桶—关键字]映射函数。具体实现方式是创建一个长度
为待排序元素最大值的数组,数组中元素均为0,然后同过将元素出现的次数进行技术的表示,将每一个存在元素的值标记为1。
按照顺序,将这些元素的索引打印出来,打印出来的新列表即为排序以后的顺序。
2)优点:速度快,对于重复元素较多的序列比较有利
3)缺点:在创建一个桶时会占用很多内存空间,也是一种以时间换空间的做法。目前自己只掌握排正整数,不够完善。
4)时间复杂度O(2
13.哈希表:
哈希表的构造方法是:假设要存储的数据元素个数为n,设置一个长度为m(m≥n)的连续存储单元,
分别以每个数据元素的关键字为自变量,通过哈希函数,把映射为内存单元的某个地址,并将该数据元素存储在该内存单元中。
从数学的角度来看,哈希函数实际上是关键字到内存单元的映射,
1)计算机计算过程中离不开比较和查找,而哈希表就是经典便于查找的数据结构没有之一,一步到位。
2)其特点就是存储时随机的,并且采取不同的哈希算法存储的位置是不同的。按照一定的哈希算法之后,再去找某个元素,
只需要去找它对应的key值即可,时间复杂度为O(1)
3)而使用hash最经常遇到的就是冲突,也就是两个元素对应同样一个Key,所以要想办法去解冲突。
哈希冲突通常是很难避免的,解决哈希冲突有很多种方法,通常分为两大类:
开放定址法:它是一类以发生哈希冲突的哈希地址为自变量,通过某种哈希函数得到一个新的空闲内存单元地址的方法(如图),开放定址法的哈希冲突函数通常是一组;
链表法:当未发生冲突时,则直接存放该数据元素;当冲突产生时,把产生冲突的数据元素另外存放在单链表中。
4)常用哈希算法
直接定址法:该方法是取关键字的某个线性函数值为哈希地址。可以简单的表示为:,优点是不会产生冲突,但缺点空间复杂度可能会很高,适用于元素较少的情况下;
除留余数法:它是用数据元素关键字除以某个常数所得的余数作为哈希地址,该方法计算简单,适用范围广,
是最经常使用的一种哈希函数,可以表示为:,该方法的关键是常数的选取,一般要求是接近或等于哈希表本身的长度
,理论研究表明,该常数取素数时效果最好。
数字分析法:该方法是取数据元素关键字中某些取值较均匀的数字位来作为哈希地址的方法,这样可以尽量避免冲突,但是该方法只适合于所有关键字已知的情况。对于想要设计出更加通用的哈希表并不适用。
标签:标记 推理 数据结构与算法 长度 恢复 树的高度 如何 非递归 非递归算法
原文地址:https://www.cnblogs.com/SutCoderHang/p/9703544.html