参考:《用python解决数据结构和算法》
O(f(n))提供了计算过程中实际步数的近似值。函数 f(n)是原始函数 T(n)中主导部分的简化表示。【T(N)是赋值语句数量】
T(n) = 5n²+27n+1005 当 n 越来越大时,我们就可以忽略其余项,只关注用 5n²来代表 T(n)的近似值了。同样,系数 5 的作用也会越来
越小,也可以忽略。我们就会说函数 T(n)的数量级 f(n) = n²,即 O(n²)
修改列表:这个“append”操作是 O(1)。然而,串联运算符+是 O(k),这里 k是指正在被连接的列表的大小
当 pop 操作每次从列表的最后一位删除元素时复杂度为 O(1),而将列表的第一个元素或中间任意一个位置的元素删除时,复杂度则为 O(n).这种执行方式会让 index 索引
操作的复杂度降为 O(1)
字典:条目的访问和赋值都是 O(1)的时间复杂度。字典的另一个重要的操作是所谓的“包含”。检查一个键是否存在于字典中也只需 O(1)的时间。
动态规划问题中:可以通过记录中间出现过的结果来减少工作量
================
栈: 添加项和移除项都发生在同一“端”。这一端通常被称为“顶”。另一端的顶部被称为“底”。
队列: 新元素的加入在队列的一端,这一端叫做“队尾”(rear),已有元素的移除发生在队列的另一端,叫做“队首”(front)
双端队列 : 元素可以在队首插入或删除,也可以在队尾插入或删除
链表的节点:
考虑一个有 n 个节点的链表, isEmpty 方法复杂度是 O(1),因为它只需要检查链表的头指针是否为 None。对于方法 size,
则总需要 n 个步骤,因为除了遍历整个链表以外,没有办法知道链表的节点数。因此, size 方法的复杂度是 O(n)。
无序列表的 add 方法的复杂度是 O(1),因为我们永远只需要在链表的头部简单地添加一个新的节点。
search、 remove 和在有序列表中的 add 方法,需要遍历。尽管在平均情况下,它们可能只需要遍历一半的节点,但这些方法的复杂度都是 O(n),
=============
二分法:结束于一个只有一项的列表 ,n/2^i=1 ,解得i=log(n) 因此,二分搜索的复杂度是O(log(n))。
散列: 它仅能在每一个数据项在散列表中占有不同的槽的情况下才能正常运作
散列函数:
1 折叠法创建散列函数的基本步骤是:首先将数据分成相同长度的片段(最后一个片段长度可能不等)。接着将这些片段相加,再求余得到其散列值。例如,如果我们有一串电话号码436-
555-4601,我们可以两个一组将这个号码分成5段(43,64,55,46,01)。然后相加得到。如果我们假设散列表有11个槽,我们就需要将和进行求余。 219%11 = 10
2 平方取中法。我们首先将数据取平方,然后取平方数的某一部分。例如数据项是44,我们首先计算。接着取出中间的两位数93, 然后再进行求余运算
解决冲突: 1) 再散列:rehash(pos)=(pos+skip)%sizeoftable 2)允许每一个槽都能填充一串而不是一个数据
冒泡排序:如果在整个排序过程中没有交换,我们就可断定列表已经排好。因此可改良冒泡排序
归并排序函数需要额外的空间来存放被拆分出来的两个部分。如果列表很大的话,这额外空间将是一个很重要的因素,可能使得这种排序被运用在大数据集合时出现错误。
快速排序用了和归并排序一样分而治之的方法来获得同样的优势,但同时不需要使用额外的存储空间。
分区过程由设置两个位置标记开始——让我们叫它们左标记和右标记——在列表的第一项和最后一项。
分区过程的目标是把相对于中值在错误的一边的数据放到正确的一边,同时找到分割点。
==============《大话数据结构》
逻辑结构:集合(元素属于同一集合),线性结构(一对一),树形结构(一对多),图(多对多)
物理结构:顺序存储和链式存储
算法是解决特定问题求解步骤的描述
: