1.1 数据结构的基本概念
基本概念
- 抽象数据类型(ADT)的定义取决于它的逻辑特性,不管计算机如何表示和实现,只要它的数学特性不变,则这其实是同一个抽象数据类型。
- 抽象数据类型(ADT)描述了数据的逻辑结构和抽象运算,通常用(D数据对象,S数据关系,P基本操作集)这样的三元组来表示,从而构成一个完整的数据结构定义。
数据结构的三要素
1.逻辑结构:
逻辑结构分为线性结构和非线性结构,线性表是典型的线性结构。非线性结构里又含有集合,树形结构和图状结构(网状结构),集合,树和图是经典的非线性结构。
2.物理结构(数据的存储结构):
主要有顺序存储,链式存储,索引存储,散列存储(哈希Hash存储)。
- 顺序存储:就是逻辑上应该相邻的数据元素也顺序存储在存储单元中。
- 链式存储:就是虽然有数据元素逻辑上是相邻的,但是数据可能分散在任意存储单元中,逻辑相邻的前后数据元素依靠(地址)指针来导向。
- 索引存储:数据可能分散在任意存储单元中,逻辑相邻的前后数据元素依靠一个索引表来导向。
- 散列存储(哈希存储):给定一种公式,通过元素的特征用公式直接计算出该元素的存储空间。
3.数据的运算:
- 针对逻辑结构:指运算的功能。
- 针对存储结构:指运算的具体操作步骤
Notes:
1.逻辑结构:仅描述元素之间的逻辑关系,它可以用多种存储方式来实现。例如:栈,栈既可以才用顺序存储或者链式存储,故属于逻辑结构,有序表是指关键字有序的线性表,同样属于逻辑结构;而顺序表,哈希表,单链表则不是,因为它描述了逻辑结构了之后又将存储结构和数据运算定死了,所以不属于逻辑结构。
2. 在存储数据时,不仅要存储数据元素的值,而且要存储数据元素之间的关系。
3. 对于两种不同的数据结构,逻辑结构或物理结构有可能是相同的,比如:二叉树和二叉排列树,他们的逻辑结构和物理结构完全一致,但是由于数据结构的三要素之一:“数据的运算”的原理不一样,所以这是两种不同的数据结构。
4.相同的逻辑结构,同一种运算在不同的存储方式下实现时,运算的效率有可能不一样,比如:线性表,线性表可以用顺序存储方式实现又可以用链式存储方式实现。在顺序存储方式下,在线性表中插入和删除元素,平均要移动一半的元素,时间复杂度是O(n),但是链式存储方式下,不需要移动其他元素,插入和删除的时间复杂度都仅为O(1)。
1.2 算法和算法评价
算法的基本概念
算法效率的度量
1.时间复杂度:
时间开销与问题规模n的关系O(f(n))
运行时间记为
T
(
n
)
T(n)
T(n)
算法中基本操作重复的次数和问题规模n的比例函数记为
f
(
n
)
f(n)
f(n)
T(n)=O(f(n));
2.空间复杂度
空间开销(系统开销)与问题规模n的关系
加法规则:
O
(
f
(
n
)
)
+
O
(
g
(
n
)
)
=
O
(
m
a
x
(
f
(
n
)
,
g
(
n
)
)
)
O(f(n))+O(g(n))=O(max(f(n),g(n)))
O(f(n))+O(g(n))=O(max(f(n),g(n)))
乘法规则:
O
(
f
(
n
)
)
∗
O
(
g
(
n
)
)
=
O
(
f
(
n
)
∗
g
(
n
)
)
O(f(n))*O(g(n))=O(f(n)*g(n))
O(f(n))∗O(g(n))=O(f(n)∗g(n))
常对幂指阶:
O
(
1
)
<
O
(
log
2
n
)
<
O
(
n
)
<
O
(
n
log
2
n
)
<
O
(
n
2
)
<
O
(
n
3
)
<
O
(
2
n
)
<
O
(
n
!
)
<
O
(
n
n
)
O(1)<O(\log_{2} n)<O(n)<O(n\log_{2}n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)
O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
Notes:
时间复杂度的表示要注意算法执行时间的增长率和f(n)的增长率相同即可,例如O(2n)一般写成O(n)。所以时间复杂度的优劣评估更注重增长率,并且一般忽略在某一特殊数值下的比较。
时间复杂度总是考虑最坏的情况,这能保证算法的运行时间不会比它更长。
算法原地工作是指算法所需的辅助空间是常量。
同一算法,实现语言的级别越高,执行效率会越低
例题:已知两个长度分别为m和n的升序链表,若将他们合并成长度为m+n的一个降序链表,则最坏情况下的时间复杂度是?
答案:O(max(m, n))
无论两个升序链表内部是怎么样的,都要有m+n次移动才能变成一个降序链表,所以这里时间复杂度就应该直接剔除这部分。
这里的时间复杂度主要是考察的两个链表的比较部分,比较应该从每个链表中最大的数开始,也就是从后往前看。
最好的情况:无疑是长度比较短的升序链表a中的第一个数还比另一个升序数列b最后一个数还大,升序链表a中的数肯定是链表中最小的,所以比较只用比较完a的长度后,就能直接将b的剩下的数直接放入。所以比较次数为min(m,n);
举个例子:像b(4,5,6,7)和a(8,9,10),首先10与7比较,10大放入序列;9与7比较,9大放入序列;8与7比较8大放入序列,这时比较短的a序列已经全部放完,剩下的另一个序列已经不需要比较了,直接从后往前一一放入即可。这时就只进行了3次比较。
最坏的情况:无疑是a,b链表都比较到剩任一列最后一个,只有最后一个数是不用比较的,所以出现了m+n-1次比较,
答案为啥是时间复杂度不是O(m+n-1)呢,因为时间复杂度的表示只需要表示增长率,所以表示是一次方即可,但是是O(n)还是O(m)呢?
这是最坏的情况所以应该选比较大得那个,所以O(max(n,m));
感想:
这篇学习笔记是我在学习王道和严蔚敏数据结构的小结,应该算是转载,而且有些不理解的地方也通过上网搜索才了解的东西。以为自己之前学得还行,结果从新复习的时候才发现真的是个渣渣。