大家好,如果您还对算法导论 下载不太了解,没有关系,今天就由本站为大家分享算法导论 下载的知识,包括算法导论 下载手机版的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!
在信息爆炸的时代,我们每天都会接触到大量的数据和信息。而如何高效地处理这些数据,成为了我们面临的一大挑战。作为计算机科学领域的重要分支,算法在数据处理和优化中发挥着至关重要的作用。今天,就让我们一起来探讨一下《算法导论》这本书,以及如何高效下载它。
一、什么是《算法导论》?
《算法导论》是一本由托马斯·H·科恩(Thomas H. Cormen)、查尔斯·E·莱斯纳(Charles E. Leiserson)、罗伯特·L·瑞迪(Robert L. Rivest)和克利福德·斯坦(Clifford Stein)所著的经典教材。这本书全面介绍了算法的基本概念、原理和应用,是计算机科学领域不可或缺的入门读物。
二、为什么下载《算法导论》?
1. 深入学习算法知识:《算法导论》涵盖了算法的各个方面,从基本算法到高级算法,从理论到实践,都能在这本书中找到详细讲解。
2. 提高编程能力:通过学习《算法导论》,我们可以掌握各种算法的实现方法,从而提高自己的编程能力。
3. 拓展职业发展:在当今社会,掌握算法知识已经成为计算机科学领域从业者的必备技能。下载《算法导论》有助于我们在职场上脱颖而出。
三、如何下载《算法导论》?
1. 官方渠道:我们可以通过《算法导论》的官方网站或出版社官网进行购买。以下是部分官方网站:
Thomas H. Cormen的个人网站:http://www.cs.helsinki.fi/group/goal/cormen/
MIT出版社官网:https://mitpress.mit.edu/books/introduction-algorithms
2. 网络资源:
搜索引擎:在搜索引擎中输入“算法导论 下载”,可以找到一些电子书下载网站,如PDF、EPUB等格式。
学术资源:部分高校图书馆或学术机构提供了《算法导论》的电子版,我们可以通过登录相关平台进行下载。
3. 电子书平台:
京东电子书:https://e.jd.com/
当当电子书:http://e.dangdang.com/
亚马逊电子书:https://www.amazon.cn/
四、下载《算法导论》的注意事项
1. 版权问题:在下载《算法导论》时,请确保遵守版权法规,避免非法下载。
2. 选择正规渠道:为了确保下载到的书籍质量,请尽量选择正规渠道进行购买或下载。
3. 格式选择:根据个人需求,选择合适的电子书格式,如PDF、EPUB等。
《算法导论》是一本不可多得的经典教材,学习算法知识对于我们来说至关重要。通过下载《算法导论》,我们可以深入了解算法的原理和应用,提高自己的编程能力。在下载过程中,请务必注意版权问题,选择正规渠道进行购买或下载。祝您学习愉快!
以下是一个简单的表格,展示了《算法导论》的主要章节:
| 序号 | 章节名称 | 内容简述 |
|---|---|---|
| 1 | 算法概述 | 算法的定义、分类及重要性 |
| 2 | 算法分析 | 算法的时间复杂度和空间复杂度 |
| 3 | 排序算法 | 冒泡排序、选择排序、插入排序等 |
| 4 | 查找算法 | 二分查找、哈希查找等 |
| 5 | 数据结构 | 栈、队列、链表等 |
| 6 | 图算法 | 深度优先搜索、广度优先搜索等 |
| 7 | 动态规划 | 背包问题、最长公共子序列等 |
| 8 | 线性规划 | 线性规划的基本原理及求解方法 |
| 9 | 贪心算法 | 贪心算法的基本原理及求解方法 |
| 10 | 分治算法 | 分治算法的基本原理及求解方法 |
| 11 | 算法设计技巧 | 算法设计的基本原则及技巧 |
| 12 | 算法实践 | 算法的实际应用案例 |
| 13 | 算法竞赛 | 算法竞赛的基本知识及技巧 |
| 14 | 算法发展趋势 | 算法的发展趋势及未来展望 |
计算机专业几本必看的书!附PDF下载
计算机专业必看的几本书
在计算机专业的学习道路上,选择合适的书籍是至关重要的。以下是我为大家精心挑选的几本计算机专业必看的书籍,它们涵盖了计算机系统、编程语言、数据结构与算法分析等多个方面。但请注意,由于版权限制,我无法直接提供PDF下载链接,建议大家在正规渠道购买或借阅这些书籍。
《深入理解计算机系统》(CSAPP)
简介:这本书是计算机专业学生必读的经典之作,它深入讲解了计算机系统的各个方面,包括信息的表示和处理、程序的机器级表示、处理器体系结构、存储器层次结构、链接、异常控制流、虚拟内存、并发和同步等。
图片:
编程语言相关书籍
《C++ Primer》:这是一本久负盛名的C++经典教程,适合初学者入门以及中/高级程序员提升。图片:
《Java编程思想》:这本书赢得了全球程序员的广泛赞誉,是Java语言学习的权威之作。图片:
《Fluent Python》:这是市面上关于Python最好的书之一,风格友好,内容深入,适合Python学习者。图片:
数据结构与算法分析相关书籍
《数据结构(C++语言版)》:这本书结合C++语言,详细讲解了数据结构的基本概念和实现方法。图片:
《算法图解》:这本书以图文并茂的方式,清晰易懂地讲解了算法的基本概念和应用。图片:
《算法导论》:这本书是算法领域的经典之作,涵盖了各种基础算法和高级算法,是算法学习的必备教材。图片:
其他推荐书籍
语言类
C语言:《C程序设计语言》、《C和指针》、《高质量C编程指南》等。
C++:《A Tour of C++》、《Accelerated C++》、《STL源码解析》等。
Java:《Java核心技术》、《Effective java》、《深入理解 Java虚拟机》等。
算法与数据结构大类
《大话数据结构》、《算法(第四版)》、《编程珠玑》等。
编程实践
网络编程:《Unix网络编程》、《Linux高性能服务器编程》等。
代码&程序设计:《计算机程序设计艺术》、《重构》等。
System
系统编程:《编码:隐匿在计算机软硬件背后的语言》、《程序员自我修养》等。
OS:《现代操作系统》、《深入理解 LINUX内核》等。
软件开发&其它
《程序员修炼之道》、《UNIX编程艺术》、《人月神话》等。
这些书籍都是计算机专业领域的经典之作,涵盖了从基础知识到高级技术的各个方面。通过阅读这些书籍,你可以系统地学习计算机专业知识,提升自己的编程能力和算法思维。希望这些推荐对你有所帮助!
学习算法的路,该怎么走
先学数据结构,然后看算法入门书,推荐《趣学算法》,有大量图解,比较简单,容易懂,而且有源码下载直接运行。传统的算法书,大多注重内容的收录,但却忽视思维过程的展示,因此我们学习了经典的算法,却费解于算法设计的过程。遇到一个实际问题,通过问题分析,选择使用什么样的算法策略,基于这种算法策略选择什么样的数据结构,有时算法策略和数据结构的选择并不是唯一的,不同的算法策略和数据结构设计的算法,其复杂性是不同的。而很多书就是灌输式的讲一个实例,一下子就选择了一个认定是最优的算法策略,告诉你就这样干,不谈数据结构,然后分析算法复杂性,就结束了。
原则上讲算法策略就讲算法策略,不依赖任何程序设计语言和数据结构,但对很多学生来讲,尤其是语言没学好,数据结构也不熟练的同学,只讲算法策略,如同空中楼阁。自己用算法解决实际问题,一头雾水。刚入门者不建议直接看《算法导论》,虽然它是经典,不适合初学者,会看蒙圈。算法入门推荐《趣学算法》,这本书有大量图解,适合初学者,从问题出发,根据实际问题进行分析,选择合适的算法策略,并分析为什么采用这种算法策略,然后选择什么数据结构,不同的数据结构复杂性会有什么区别,巧妙地将数据结构和算法策略拧成了一条线。通过大量实例,充分展现算法设计的思维过程,让学生充分体会遇到一个问题,如何分析,使用什么算法策略,采用什么数据结构,算法的复杂性如何,是否有优化的可能。
算法怎么学
贪心算法的定义:
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的一般步骤是:
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解。
如果大家比较了解动态规划,就会发现它们之间的相似之处。最优解问题大部分都可以拆分成一个个的子问题,把解空间的遍历视作对子问题树的遍历,则以某种形式对树整个的遍历一遍就可以求出最优解,大部分情况下这是不可行的。贪心算法和动态规划本质上是对子问题树的一种修剪,两种算法要求问题都具有的一个性质就是子问题最优性(组成最优解的每一个子问题的解,对于这个子问题本身肯定也是最优的)。动态规划方法代表了这一类问题的一般解法,我们自底向上构造子问题的解,对每一个子树的根,求出下面每一个叶子的值,并且以其中的最优值作为自身的值,其它的值舍弃。而贪心算法是动态规划方法的一个特例,可以证明每一个子树的根的值不取决于下面叶子的值,而只取决于当前问题的状况。换句话说,不需要知道一个节点所有子树的情况,就可以求出这个节点的值。由于贪心算法的这个特性,它对解空间树的遍历不需要自底向上,而只需要自根开始,选择最优的路,一直走到底就可以了。
话不多说,我们来看几个具体的例子慢慢理解它:
1.活动选择问题
这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。
考虑使用贪心算法的解法。为了方便,我们用不同颜色的线条代表每个活动,线条的长度就是活动所占据的时间段,蓝色的线条表示我们已经选择的活动;红色的线条表示我们没有选择的活动。如果我们每次都选择开始时间最早的活动,不能得到最优解:
如果我们每次都选择持续时间最短的活动,不能得到最优解:
可以用数学归纳法证明,我们的贪心策略应该是每次选取结束时间最早的活动。直观上也很好理解,按这种方法选择相容活动为未安排活动留下尽可能多的时间。这也是把各项活动按照结束时间单调递增排序的原因。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int N;
struct Act
{
int start;
int end;
}act[100010];
bool cmp(Act a,Act b)
{
return a.end<b.end;
}
int greedy_activity_selector()
{
int num=1,i=1;
for(int j=2;j<=N;j++)
{
if(act[j].start>=act[i].end)
{
i=j;
2.钱币找零问题
这个问题在我们的日常生活中就更加普遍了。假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。在程序中已经事先将Value按照从小到大的顺序排好。
}
3.再论背包问题
从零开始学动态规划
中我们已经谈过三种最基本的背包问题:零一背包,部分背包,完全背包。很容易证明,背包问题不能使用贪心算法。然而我们考虑这样一种背包问题:在选择物品i装入背包时,可以选择物品的一部分,而不一定要全部装入背包。这时便可以使用贪心算法求解了。计算每种物品的单位重量价值作为贪心选择的依据指标,选择单位重量价值最高的物品,将尽可能多的该物品装入背包,依此策略一直地进行下去,直到背包装满为止。在零一背包问题中贪心选择之所以不能得到最优解原因是贪心选择无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。在程序中已经事先将单位重量价值按照从大到小的顺序排好。
}
4.多机调度问题 n个作业组成的作业集,可由m台相同机器加工处理。要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。作业不能拆分成更小的子作业;每个作业均可在任何一台机器上加工处理。这个问题是NP完全问题,还没有有效的解法(求最优解),但是可以用贪心选择策略设计出较好的近似算法(求次优解)。当n<=m时,只要将作业时间区间分配给作业即可;当n>m时,首先将n个作业从大到小排序,然后依此顺序将作业分配给空闲的处理机。也就是说从剩下的作业中,选择需要处理时间最长的,然后依次选择处理时间次长的,直到所有的作业全部处理完毕,或者机器不能再处理其他作业为止。如果我们每次是将需要处理时间最短的作业分配给空闲的机器,那么可能就会出现其它所有作业都处理完了只剩所需时间最长的作业在处理的情况,这样势必效率较低。在下面的代码中没有讨论n和m的大小关系,把这两种情况合二为一了。
5.小船过河问题 POJ1700是一道经典的贪心算法例题。题目大意是只有一艘船,能乘2人,船的运行速度为2人中较慢一人的速度,过去后还需一个人把船划回来,问把n个人运到对岸,最少需要多久。先将所有人过河所需的时间按照升序排序,我们考虑把单独过河所需要时间最多的两个旅行者送到对岸去,有两种方式: 1.最快的和次快的过河,然后最快的将船划回来;次慢的和最慢的过河,然后次快的将船划回来,所需时间为:t[0]+2*t[1]+t[n-1]; 2.最快的和最慢的过河,然后最快的将船划回来,最快的和次慢的过河,然后最快的将船划回来,所需时间为:2*t[0]+t[n-2]+t[n-1]。算一下就知道,除此之外的其它情况用的时间一定更多。每次都运送耗时最长的两人而不影响其它人,问题具有贪心子结构的性质。 AC代码:
}
6.区间覆盖问题 POJ1328是一道经典的贪心算法例题。题目大意是假设海岸线是一条无限延伸的直线。陆地在海岸线的一侧,而海洋在另一侧。每一个小的岛屿是海洋上的一个点。雷达坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。对于每个小岛,我们可以计算出一个雷达所在位置的区间。
问题转化为如何用尽可能少的点覆盖这些区间。先将所有区间按照左端点大小排序,初始时需要一个点。如果两个区间相交而不重合,我们什么都不需要做;如果一个区间完全包含于另外一个区间,我们需要更新区间的右端点;如果两个区间不相交,我们需要增加点并更新右端点。 AC代码:
//按区间左端点排序
double s=point[0].y;
//区间右端点
for(int i=1;i<n;i++)
{
if(point[i].x>s)
//如果两个区间没有重合,增加雷达数目并更新右端点
{
counting++;
s=point[i].y;
}
else if(point[i].y<s)
//如果第二个区间被完全包含于第一个区间,更新右端点
{
s=point[i].y;
}
}
}
cout<<”Case”<<num<<':'<<''<<counting<<endl;
num++;
}
}
7.销售比赛在学校OJ上做的一道比较好的题,这里码一下。假设有偶数天,要求每天必须买一件物品或者卖一件物品,只能选择一种操作并且不能不选,开始手上没有这种物品。现在给你每天的物品价格表,要求计算最大收益。首先要明白,第一天必须买,最后一天必须卖,并且最后手上没有物品。那么除了第一天和最后一天之外我们每次取两天,小的买大的卖,并且把卖的价格放进一个最小堆。如果买的价格比堆顶还大,就交换。这样我们保证了卖的价格总是大于买的价格,一定能取得最大收益。
#include<queue>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long int price[100010],t,n,res;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t–)
{
cin>>n;
priority_queue<long long int, vector<long long int>, greater<long long int>> q;
res=0;
for(int i=1;i<=n;i++)
{
cin>>price[i];
}
res-=price[1];
res+=price[n];
for(int i=2;i<=n-1;i=i+2)
{
long long int buy=min(price[i],price[i+1]);
long long int sell=max(price[i],price[i+1]);
if(!q.empty())
{
if(buy>q.top())
{
res=res-2*q.top()+buy+sell;
q.pop();
q.push(buy);
q.push(sell);
}
else
{
res=res-buy+sell;
q.push(sell);
}
}
else
{
res=res-buy+sell;
q.push(sell);
}
}
cout<<res<<endl;
}
}
下面我们结合数据结构中的知识讲解几个例子。 8.Huffman编码这同样是《算法导论》上的例子。Huffman编码是广泛用于数据文件压缩的十分有效的编码方法。我们可以有多种方式表示文件中的信息,如果用01串表示字符,采用定长编码表示,则需要3位表示一个字符,整个文件编码需要300000位;采用变长编码表示,给频率高的字符较短的编码,频率低的字符较长的编码,达到整体编码减少的目的,则整个文件编码需要(45×1+13×3+12×3+16×3+9×4+5×4)×1000=224000位,由此可见,变长码比定长码方案好,总码长减小约25%。
对每一个字符规定一个01串作为其代码,并要求任一字符的代码都不是其他字符代码的前缀,这种编码称为前缀码。可能无前缀码是一个更好的名字,但是前缀码是一致认可的标准术语。编码的前缀性质可以使译码非常简单:例如001011101可以唯一的分解为0,0,101,1101,因而其译码为aabe。译码过程需要方便的取出编码的前缀,为此可以用二叉树作为前缀码的数据结构:树叶表示给定字符;从树根到树叶的路径当作该字符的前缀码;代码中每一位的0或1分别作为指示某节点到左儿子或右儿子的路标。
从上图可以看出,最优前缀编码码的二叉树总是一棵完全二叉树,而定长编码的二叉树不是一棵完全二叉树。给定编码字符集C及频率分布f,C的一个前缀码编码方案对应于一棵二叉树T。字符c在树T中的深度记为dT(c),dT(c)也是字符c的前缀码长。则平均码长定义为:
使平均码长达到最小的前缀码编码方案称为C的最优前缀码。 Huffman编码的构造方法:先合并最小频率的2个字符对应的子树,计算合并后的子树的频率;重新排序各个子树;对上述排序后的子树序列进行合并;重复上述过程,将全部结点合并成1棵完整的二叉树;对二叉树中的边赋予0、1,得到各字符的变长编码。
POJ3253一道就是利用这一思想的典型例题。题目大意是有把一块无限长的木板锯成几块给定长度的小木板,每次锯都需要一定费用,费用就是当前锯的木板的长度。给定各个要求的小木板的长度以及小木板的个数,求最小的费用。以要求3块长度分别为5,8,5的木板为例:先从无限长的木板上锯下长度为21的木板,花费21;再从长度为21的木板上锯下长度为5的木板,花费5;再从长度为16的木板上锯下长度为8的木板,花费8;总花费=21+5+8=34。利用Huffman思想,要使总费用最小,那么每次只选取最小长度的两块木板相加,再把这些和累加到总费用中即可。为了提高效率,使用优先队列优化,并且还要注意使用long long int保存结果。 AC代码:
#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
long long int sum;
int i,n,t,a,b;
while(~scanf(“%d”,&n))
{
priority_queue<int,vector<int>,greater<int>>q;
for(i=0;i<n;i++)
{
scanf(“%d”,&t);
q.push(t);
}
sum=0;
if(q.size()==1)
{
a=q.top();
sum+=a;
q.pop();
}
while(q.size()>1)
{
a=q.top();
q.pop();
b=q.top();
q.pop();
t=a+b;
sum+=t;
q.push(t);
}
printf(“%lld
“,sum);
}
}
9.Dijkstra算法 Dijkstra算法是由E.W.Dijkstra于1959年提出,是目前公认的最好的求解最短路径的方法,使用的条件是图中不能存在负边。算法解决的是单个源点到其他顶点的最短路径问题,其主要特点是每次迭代时选择的下一个顶点是标记点之外距离源点最近的顶点,简单的说就是bfs+贪心算法的思想。
#include<iostream>
#include<algorithm>
#define INF 1000
#define MAX_V 100
using namespace std;
int main()
{
int V,E;
int i,j,m,n;
int cost[MAX_V][MAX_V];
int d[MAX_V];
bool used[MAX_V];
cin>>V>>E;
fill(d,d+V+1,INF);
fill(used,used+V,false);
for(i=0;i<V;i++)
{
for(j=0;j<V;j++)
{
if(i==j) cost[i][j]=0;
else cost[i][j]=INF;
}
}
for(m=0;m<E;m++)
{
cin>>i>>j>>cost[i][j];
cost[j][i]=cost[i][j];
}
cin>>n;
d[n]=0;
//源点
while(true)
{
int v=V;
for(m=0;m<V;m++)
{
if((!used[m])&&(d[m]<d[v])) v=m;
}
if(v==V) break;
used[v]=true;
for(m=0;m<V;m++)
{
d[m]=min(d[m],d[v]+cost[v][m]);
}
}
for(i=0;i<V;i++)
{
cout<<”the shortest distance between”<<n<<” and”<<i<<” is”<<d[i]<<endl;
}
}
10.最小生成树算法
设一个网络表示为无向连通带权图G=(V, E), E中每条边(v,w)的权为c[v][w]。如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树的代价是指生成树上各边权的总和,在G的所有生成树中,耗费最小的生成树称为G的最小生成树。例如在设计通信网络时,用图的顶点表示城市,用边(v,w)的权c[v][w]表示建立城市v和城市w之间的通信线路所需的费用,最小生成树给出建立通信网络的最经济方案。
构造最小生成树的Kruskal算法和Prim算法都利用了MST(最小生成树)性质:设顶点集U是V的真子集(可以任意选取),如果(u,v)∈E为横跨点集U和V—U的边,即u∈U,v∈V- U,并且在所有这样的边中,(u,v)的权c[u][v]最小,则一定存在G的一棵最小生成树,它以(u,v)为其中一条边。
使用反证法可以很简单的证明此性质。假设对G的任意一个最小生成树T,针对点集U和V—U,(u,v)∈E为横跨这2个点集的最小权边,T不包含该最小权边<u, v>,但T包括节点u和v。将<u,v>添加到树T中,树T将变为含回路的子图,并且该回路上有一条不同于<u,v>的边<u’,v’>,u’∈U,v’∈V-U。将<u’,v’>删去,得到另一个树T’,即树T’是通过将T中的边<u’,v’>替换为<u,v>得到的。由于这2条边的耗费满足c[u][v]≤c[u’][v’],故即T’耗费≤T的耗费,这与T是任意最小生成树的假设相矛盾,从而得证。
Prim算法每一步都选择连接U和V-U的权值最小的边加入生成树。
#include<iostream>
#include<algorithm>
#define MAX_V 100
#define INF 1000
using namespace std;
int main()
{
int V,E;
int i,j,m,n;
int cost[MAX_V][MAX_V];
int mincost[MAX_V];
bool used[MAX_V];
cin>>V>>E;
fill(mincost,mincost+V+1,INF);
fill(used,used+V,false);
for(i=0;i<V;i++)
{
for(j=0;j<V;j++)
{
if(i==j) cost[i][j]=0;
else cost[i][j]=INF;
}
}
for(m=0;m<E;m++)
{
cin>>i>>j>>cost[i][j];
cost[j][i]=cost[i][j];
}
mincost[0]=0;
int res=0;
while(true)
{
int v=V;
for(m=0;m<V;m++)
{
if((!used[m])&&(mincost[m]<mincost[v]))
v=m;
}
if(v==V) break;
used[v]=true;
res+=mincost[v];
for(m=0;m<V;m++)
{
mincost[m]=min(mincost[m],cost[v][m]);
}
}
cout<<res<<endl;
} Kruskal算法每一步直接将权值最小的不成环的边加入生成树,我们借助并查集这一数据结构可以完美实现它。
关于贪心算法的基础知识就简要介绍到这里,希望能作为大家继续深入学习的基础。
关于本次算法导论 下载和算法导论 下载手机版的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。




