《数据结构》学习笔记

《数据结构》学习笔记本文探讨了算法分析的关键任务 包括正确性和单调性 以及复杂度的不同计算方法 如迭代求和 递归和级数理论

大家好,欢迎来到IT知识分享网。

1.算法分析的两个主要任务:正确性(不变性 + 单调性) + 复杂度。

2.复杂度分析的主要方法:

  • 迭代:级数求和;
  • 递归:递归跟踪 + 递推方程
  • 猜测 + 验证

3.级数:

  • 调和级数:

h ( n ) = 1 + 1 2 + 1 3 + ⋯ + 1 n = Θ ( log ⁡ n ) \begin{aligned} & h(n) = 1 + \frac{1}{2} + \frac{1}{3} + \cdots + \frac{1}{n} = \Theta(\log n) \end{aligned} \notag h(n)=1+21+31++n1=Θ(logn)

  • 对数级数:

log ⁡ 1 + log ⁡ 2 + log ⁡ 3 + ⋯ + log ⁡ n = log ⁡ ( n ! ) = Θ ( n log ⁡ n ) \log 1 + \log 2 +\log 3 + \cdots + \log n = \log (n!) = \Theta(n \log n) \notag log1+log2+log3++logn=log(n!)=Θ(nlogn)

4.一些循环的复杂度估计:

(1)循环体如下:

for (int i = 1; i < n; i <<= 1) for (int j = 0; j < i; j++) O1_Operation(i, j); 

循环体如下:

for (int i = 0; i <= n; i++) for (int j = 1; j < i; j += j) O1_Operation(i, j); 
  • 不变性:经 k k k 轮扫描交换后,最大的 k k k 个元素必然就位;
  • 单调性:经 k k k 轮扫描交换后,问题规模缩减至 n − k n-k nk
  • 正确性:经至多 n n n 趟扫描后,算法必然终止,且能给出正确解答。

6.封底估算(Back-Of-The-Envelope Calculation):

(1)1 day = 24h x 60min x 60sec ≈ \approx 25 x 4000 = 10^5 sec
(2)10^9 sec ≈ \approx 30 year

7.最长公共子序列:

(1)递归版:

unsigned int lcs(const char* A, int n, const char* B, int m) { 
    if (n < 1 || m < 1) return 0; // recursion base else if (A[n - 1] == B[m - 1]) // decrease-and-conquer return 1 + lcs(A, n - 1, B, m - 1); else // divide-and-conquer return max(lcs(A, n, B, m - 1), lcs(A, n - 1, B, m)); } 

(2)迭代版:

unsigned int lcs(const char* A, int n, const char* B, int m) { 
    if (n < m) { 
    swap(A, B); swap(n, m); // make sure m <= n } unsigned int* lcs1 = new unsigned int[m + 1]; unsigned int* lcs2 = new unsigned int[m + 1]; memset(lcs1, 0x00, sizeof(unsigned int) * (m + 1)); lcs2[0] = 0; for (int i = 0; i < n; swap(lcs1, lcs2), i++) for (int j = 0; j < m; j++) lcs2[j + 1] = (A[i] == B[j]) ? 1 + lcs1[j] : max(lcs2[j], lcs1[j + 1]); unsigned int res = lcs1[m]; delete [] lcs1; delete [] lcs2; return res; } 

8.总和最大区段:

(1) O ( n 3 ) O(n^3) O(n3) 蛮力算法:

int gs_BF(int A[], int n) { 
    int gs = A[0]; // current max for (int i = 0; i < n; i++) for (int j = i; j < n; j++) // enumerate every segment { 
    int s = 0; for (int k = i; k <= j; k++) s += A[k]; if (gs < s) gs = s; } return gs; } 

(2) O ( n 2 ) O(n^2) O(n2) 递增策略:

// 考查所有起点相同的区间,它们的总和之间具有相关性 int gs_IC(int A[], int n) { 
    int gs = A[0]; // current max for (int i = 0; i < n; i++) { 
    int s = 0; for (int j = i; j < n; j++) { 
    s += A[j]; if (gs < s) gs = s; } } return gs; } 

(3) O ( n log ⁡ n ) O(n\log n) O(nlogn) 分治策略:

// 将整个区间递归地分为三部分:前缀、后缀、跨越切分线的中间部分 int gs_DC(int A[], int lo, int hi) // 注意区间是左闭右开的:[lo, hi) { 
    if (hi - lo < 2) return A[lo]; // recursion base int mi = (lo + hi) >> 1; // 寻找跨越切分线左半边的gsL int gsL = A[mi - 1], sL = 0, i = mi; while (lo < i--) { 
    sL += A[i]; if (gsL < sL) gsL = sL; } // 寻找跨越切分线右半边的gsR int gsR = A[mi], sR = 0, j = mi - 1; while (++j < hi) { 
    sR += A[j]; if (gsR < sR) gsR = sR; } return max(gsL + gsR, max(gs_DC(A, lo, mi), gs_DC(A, mi, hi))); } 

(4) O ( n ) O(n) O(n) 减治策略:

// 该策略基于这样一个结论: // 记suffix(k) = A[k, hi), 其中k = max{lo<=i<hi | sum[i, hi)<=0}, // 则GS(lo, hi) = A[i, j)要么是其真后缀(k <= i < j = hi),要么与之无交(j <= k) int gs_LS(int A[], int n) // Linear Scan: O(n) { 
    int gs = A[0], s = 0, i = n; while (0 < i--) { 
    s += A[i]; if (gs < s) gs = s; if (s <= 0) s = 0; // 剪除负和后缀 } return gs; } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128241.html

(0)
上一篇 2025-09-01 22:10
下一篇 2025-09-01 22:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信