主要有关大O记法
————————————————————
用表格法以及大O记法来计算时间复杂度
————————————————————
阶乘
line | s/e | frequency | step sum |
---|---|---|---|
long long fractorial(int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
if(n < 1) return 1; | 1 | 1 | Θ(1) |
else return n * fractorial(n-1); | 1 | n-1 | Θ(n) |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
比较不划算的最大最小值index
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
bool minMax_1(T a[], int n, int &indexOfMin, int &indexOfMax) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
if(n < 1) return false; | 1 | 1 | Θ(1) |
indexOfMin = indexOfMax = 0; | 1 | 1 | Θ(1) |
for(int i = 0; i < n; ++i) | 1 | n+1 | Θ(n) |
{ | 0 | 0 | 0 |
if(a[indexOfMin] > a[i]) indexOfMin = i; | 1 | n | Θ(n) |
if(a[indexOfMax] < a[i]) indexOfMax = i; | 1 | n | Θ(n) |
} | 0 | 0 | 0 |
return true; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
稍微划算一点的最大最小值index
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
bool minMax_2(T a[], int n, int &indexOfMin, int &indexOfMax) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
if(n < 1) return false; | 1 | 1 | Θ(1) |
indexOfMin = indexOfMin = 0; | 1 | 1 | Θ(1) |
for(int i = 0; i < n; ++i) | 1 | n+1 | Θ(n) |
{ | 0 | 0 | 0 |
if(a[indexOfMin] > a[i]) indexOfMin = i; | 1 | Θ(n) | Θ(n) |
else if(a[indexOfMax] < a[i]) indexOfMax = i; | 1 | Ω(0), O(n) | Ω(0), O(n) |
} | 0 | 0 | 0 |
return true; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void MatrixAdd(T **r, T **a, T **b, int numRow, int numCol) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 0; i < numRow; ++i) | 1 | row+1 | Θ(row) |
{ | 0 | 0 | 0 |
for(int j = 0; j < numCol; ++j) | 1 | (col+1)*row | Θ(row*col) |
r[i][j] = a[i][j] + b[i][j]; | 1 | col*row | Θ(row*col) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Θ(row*col) |
————————————————————
方阵乘法
啊啊每次写方阵乘法都要从矩阵的几何意义想一遍。记不住定则应该是我数学物理成绩不好的主要原因之一。。。
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void squareMatrixMultiply(T **r, T **left, T **right, int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 0; i < n; ++i) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
for(int j = 0; j < n; ++j) | 1 | Θ(n2) | Θ(n2) |
{ | 0 | 0 | 0 |
T sum = 0; | 1 | Θ(n2) | Θ(n2) |
for(int k = 0; k < n; ++k) | 1 | Θ(n3) | Θ(n3) |
{ | 0 | 0 | 0 |
sum += left[i][k] * right[k][j]; | 1 | Θ(n3) | Θ(n3) |
} | 0 | 0 | 0 |
r[i][j] = sum; | 1 | Θ(n2) | Θ(n2) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Θ(n3) |
————————————————————
非方阵的矩阵乘法
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
//left m * n | 0 | 0 | 0 |
//right n * p | 0 | 0 | 0 |
//r m * p | 0 | 0 | 0 |
void matrixMultiply(T **r, T **left, T **right, int m, int n, int p) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 0; i < m; ++i) | 1 | Θ(m) | Θ(m) |
{ | 0 | 0 | 0 |
for(int j = 0; j < p; ++j) | 1 | Θ(mp) | Θ(mp) |
{ | 0 | 0 | 0 |
T sum = 0; | 1 | Θ(mp) | Θ(mp) |
for(int k = 0; k < n; ++k) | 1 | Θ(mpn) | Θ(mpn) |
{ | 0 | 0 | 0 |
sum += left[i][k] * right[k][j]; | 1 | Θ(mpn) | Θ(mpn) |
} | 0 | 0 | 0 |
r[i][j] = sum; | 1 | Θ(mp) | Θ(mp) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Θ(mpn) |
————————————————————
最大元素index
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
int indexOfMax(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
if(n < 1) return -1; | 1 | 1 | Θ(1) |
int index = 0; | 1 | 1 | Θ(1) |
for(int i = 1; i < n; ++i) | 1 | n | Θ(n) |
{ | 0 | 0 | 0 |
if(a[index] < a[i]) | 1 | n | Θ(n) |
index = i; | 1 | Ω(0), O(n-1) | Ω(0), O(n) |
} | 0 | 0 | 0 |
return index; | 1 | 1 | 1 |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
多项式乘法
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
T polyEval(T coeff[], int n, const T &x) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
T xIndex = 1, value = coeff[0]; | 1 | 1 | Θ(1) |
for(int i = 1; i < n; ++i) | 1 | n | Θ(n) |
{ | 0 | 0 | 0 |
xIndex *= x; | 1 | n-1 | Θ(n) |
value += coeff[i] * xIndex; | 1 | 1 | Θ(n) |
} | 0 | 0 | 0 |
return value; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
T horner(T coeff[], int n, const T &x) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
T value = coeff[n-1]; | 1 | 1 | 1 |
for(int i = n-2; i >= 0; --i) | 1 | n | Θ(n) |
{ | 0 | 0 | 0 |
value = value * x + coeff[i]; | 1 | n-1 | Θ(n) |
} | 0 | 0 | 0 |
return value; | 1 | 1 | 1 |
} | 0 | 0 | 0 |
total | Θ(n) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void rank(T a[], int r[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 0; i < n; ++i) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
for(int j = i+1; j < n; ++j) | 1 | Θ(1+2+…+n) | Θ(n2) |
{ | 0 | 0 | 0 |
if(a[i] <= a[j]) | 1 | Θ(n2) | Θ(n2) |
++r[j]; | 0 | 0 | 0 |
else | 1 | Ω(0), O(n2) | Ω(0), O(n2) |
++r[i]; | 0 | 0 | 0 |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Θ(n2) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void permutation(T a[], int k, int m) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
if(k == m) | 1 | 1 | Θ(1) |
{ | 0 | 0 | 0 |
for(int i = 0; i <= m; ++i) | 1 | m+2 | Θ(m) |
cout << a[i] << " "; | 1 | m+1 | Θ(m) |
cout << endl; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
else | 1 | [0:1] | Ω(0), O(1) |
{ | 0 | 0 | 0 |
for(int i = k; i <= m; ++i) | 1 | m-k+2 | Θ(m-k+2) |
{ | 0 | 0 | 0 |
swap(a[i], a[k]); | 1 | [0:m-k+1] | Ω(0), O(m-k+1) |
permutation(a, k+1, m); | t(k+1, m) | m-k | (m-k)*t(k+1, m) |
swap(a[i], a[k]); | 1 | [0:m-k+1] | Ω(0), O(m-k+1) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
当k==m时,t(k,m) = Θ(m),
当k=0时
t(0,m) = mt(1, m)
= m(m-1)*t(2, m)
= …
= m!t(m, m)
= Θ(mm!)
1)其实很多人说permutaiton的复杂度时m!,其实也没错,这里是因为最后需要输出,而且输出的复杂度和输入m有关,所以最后的结果又在m!基础上乘了m
2)swap的复杂度没有计算,即使计算了,当m趋于无穷的时候,前面的所有量级比较小的阶乘,提取量级比较大的阶乘,变成阶乘倒数的和,极限为一个常数,亦可表示为Θ(m!)
函数
template <class T>
void permutation(T a[], int k, int m)
{
if(k == m)
{
for(int i = 0; i <= m; ++i)
cout << a[i] << " ";
cout << endl;
}
else
{
for(int i = k; i <= m; ++i)
{
swap(a[i], a[k]);
permutation(a, k+1, m);
swap(a[i], a[k]);
}
}
}
应用举例
string array_d[] = {"l","o","v","e"};
const int size_d = 4;
permutation(array_d, 0, size_d-1);
————————————————————
带着大O怎么计算
呃当然带着O计算是不太可能了,因为O毕竟只是一个表示法。如果把它放在方程或公式中,它应该不带什么意义
不过,如果把大O中的g(n)放在公式中还是有意义的。
假如说某一步的结果为O(g(n)),或Θ(g(n)),那么如果下一步中需要用到这里的结果
1)用f(n),即取极限之前的函数,这样当然最准确
2)将g(n)抽象成带系数,带多项式的形式。
其一,这种方法主要是用于消除疑心,即使加上了系数以及其它项,但是由于在得到g(n)的结果的时候,其它项已经可以省略,因此在再计算的结果中应该也可以省略
其二,这种方法可以用于(当然还有1),因为1)最准确)n随着i变化然后求和或递推等等情况,比如(1+2+…+n)这种。
系数和其它项,可以在计算过程中或计算之前直接就省略了
3)直接用g(n)。即如果有很大把握是正确的,也可以直接用g(n)
不管用那种方法,我认为大O表示法的意义都在于,可以将比较起来渐近小于的项,在计算后,计算过程中,或计算之前,就省略掉。如2)其实是在计算过程中省略掉,3)是在计算过程之前就省略掉,1)当然则是在计算之后。如有涉及到变化的n,则可以将g(n)拿出来计算,再进行渐近比较
另外,也可以极度省略,即流行的大多数人的做法,直接拿更为抽象的过程作为一步,比如permutation的一次分形。或者某种排序中比较的次数,或如二分搜索的折半以及判断次数。虽然说这么做带有不精确的风险,但是应该可以论证,其结果是不受这种不精确的影响的。大概就是因为,这种关键的抽象步骤若代表输入n,那其步数基本上可以作为其系数,其它一些不重要的步骤可以作为多项式可以被忽略的项。不过似乎也没有人去论证过,然后大家也都这么用了。还是,大O表示法,以我之见,其精髓不仅在于如何表示,而且在于如何在计算过程的前中后省略(当然归根结底由其原理所得)。因此,理解其前因后果来龙去脉,还是很重要的。
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void selectionSort(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = n-1; i > 0; --i) | 1 | n | Θ(n) |
{ | 0 | 0 | 0 |
int iOfMax = indexOfMax(a, i+1); | Θ(i) | n | Θ(n2) |
swap(a[i], a[iOfMax]); | 1 | n | Θ(n) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Θ(n2) |
template <class T>
int indexOfMax(T a[], int n)
{
if(n < 1) return -1;
int index = 0;
for(int i = 1; i < n; ++i)
{
if(a[index] < a[i])
index = i;
}
return index;
}
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void selectionSort_stop(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
bool sorted = false; | 1 | 1 | Θ(1) |
for(int i = n; !sorted && i > 1; --i) | 1 | n | Θ(n) |
{ | 0 | 0 | 0 |
sorted = true; | 1 | Θ(n) | Θ(n) |
int indexOfMax = 0; | 1 | Θ(n) | Θ(n) |
for(int j = 1; j < i; ++j) | 1 | Θ(n2) | Θ(n2) |
{ | 0 | 0 | 0 |
if(a[indexOfMax] < a[j]) indexOfMax = j; | 1 | Θ(n2) | Θ(n2) |
else sorted = false; | 1 | Ω(0), O(n2) | Ω(0), O(n2) |
} | 0 | 0 | 0 |
swap(a[indexOfMax], a[i-1]); | 1 | Θ(n) | Θ(n) |
} | 0 | 0 | 0 |
} | 0 | 0 | Θ(n2) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void insert(T a[], int n, const T &x) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
int i; | 1 | 1 | Θ(1) |
for(i = n-1; i >= 0 && a[i] > x; --i) | 1 | Ω(1), O(n) | Ω(1), O(n) |
a[i+1] = a[i]; | 1 | Ω(1), O(n) | Ω(1), O(n) |
a[i+1] = x; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
0 | 0 | 0 | |
total | Ω(1), O(n) | ||
template < class T > | 0 | 0 | 0 |
void insertionSort(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 1; i < n-1; ++i) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
T t = a[i]; | 1 | Θ(n) | Θ(n) |
insert(a, i, t); | Ω(1), O(n) | Θ(n) | Ω(n), O(n2) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Ω(n), O(n2) |
这个是照着Sahni的答案写的。认识到的是Ω和O可以放在一起作为表示上下限并强调区间
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void insertionSort_2(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 1; i < n; ++i) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
T t = a[i]; | 1 | Θ(n) | Θ(n) |
int j; | 1 | 1 | Θ(1) |
for(j = i-1; j >= 0 && a[j] > t; --j) | 1 | Ω(1), O(n) | Ω(n), O(n2) |
a[j+1] = a[j]; | 1 | Ω(0), O(n) | Ω(0), O(n2) |
a[j+1] = t; | 1 | Θ(n) | Θ(n) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
total | Ω(n), O(n2) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
void bubble(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = 0; i < n-1; ++i) | 1 | Θ(n) | Θ(n) |
if(a[i] > a[i+1]) swap(a[i], a[i+1]); | 1 | Θ(n) | Θ(n) |
} | 0 | 0 | 0 |
template < class T > | 0 | 0 | 0 |
void bubbleSort(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = n; i > 1; --i) | 1 | Θ(n) | Θ(n) |
bubble(a, i); | Θ(i) | Θ(n) | Θ(n2) |
} | 0 | 0 | 0 |
total | Θ(n2) |
————————————————————
line | s/e | frequency | step sum |
---|---|---|---|
template < class T > | 0 | 0 | 0 |
bool bubble_stop(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
bool swapped = false; | 1 | 1 | Θ(1) |
for(int i = 0; i < n-1; ++i) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
if(a[i] > a[i+1]) | 1 | Θ(n) | Θ(n) |
{ | 0 | 0 | 0 |
swap(a[i], a[i+1]); | 1 | Ω(0), O(n) | Ω(0), O(n) |
swapped = true; | 1 | Ω(0), O(n) | Ω(0), O(n) |
} | 0 | 0 | 0 |
} | 0 | 0 | 0 |
return swapped; | 1 | 1 | Θ(1) |
} | 0 | 0 | 0 |
total | Θ(n) | ||
template < class T > | 0 | 0 | 0 |
void bubbleSort_stop(T a[], int n) | 0 | 0 | 0 |
{ | 0 | 0 | 0 |
for(int i = n; i > 1 && bubble_stop(a, i); --i); | Θ(i) | Θ(n) | Θ(n2) |
} | 0 | 0 | 0 |
total | Θ(n2) |
————————————————————
参考 / 读书笔记读的书:
————————————————————
数据结构,算法与应用:C++语言描述(第二版)ISBN 978-7-111-49600-7
更新于
2021.04.06