动态规划算法解析与实战

一、算法思想

          动态规划算法的基础是最优原理,它是用来解决贪婪算法和分治算法无法解决或者无法简洁高效解决的算法,一般用于求解下列问题:(1)背包问题 (2)最短路径 等。

          动态规划和贪婪算法一样,都一个问题的求解都是分为对很多问题的求解的综合,问题最终的解是多次选择的综合结果,但是贪婪算法中,每次选择最优解,之后不可撤回,但是动态规划中需要考察一系列的抉择,然后才能确定一个最优抉择序列是否包含最优抉择子序列,具体就通过下面的例子来说明:

1.1 最短路径
  有下图所示的单向图,求从源点1到目的点5的最短路径?


           如果是利用贪婪算法来进行求解,那么第一步可以到达的点为2,4,3。按照算法,到点3的距离是最短的,所以选择走到点3,然后点3可以到达2,4,接下来走到点4,因为到点4的距离最短,然后此时可以通过点4到达目的点5,最后选得的路径是1->3->4->5,路径长度为7.虽然确实是最短路径,但是可以看出,从1到3,从3到4,从4到5,整个过程是割裂开的,但是一个最短路径是求的整个过程加起来的路径长度最短,很多时候贪婪算法不一定适用,因为它不能回退。

            如果是动态规划,那么要考虑的就是,首先选择了从1到3这条路径,之后要确定如何从3到5,如果3到5选择的路径不对,那么就算1到3是最短的,整个结果依然会偏大,所以假设选择了某个点x作为最短路径中的某个点,那么接下来说选择的从x到目的点的路径必须是最短的,这就是包含最优抉择序列的意思,因为考虑这种情况:一个点都没选的时候,此时就相当于要必须选择出从源点到目的点的最短路径,所以可以求出最短路径。

1.2 0/1背包问题


             有n个物品和一个容量为c的背包,从n个物品中选择装包的物品,每个物品有自己的重量w和价值p,要求算出如何在不超过背包容量的情况下,要装入物品的价值p最大。

             假设n=3,w=[100,14,10],c=116,p=[20,18,15],如果选择装入第一个物品,那么问题转变为求解c=16,w[14,10],p=[18,15]的最优解,此时有两种解法:装入第一个或者装入第二个,明显看出因为p1>p2,所以装入第一个是此时的最优解,所以得到此条件下的最优结果为[1,1,0],1代表装入物品,从上可以看出,如果某一步所做的解不是此状态下的最优解,那么它肯定不是初始问题的最优解。也可以不装入第一个物品,此时得到另外一个解[0,1,1],[0,1,1]是在不装入物品1下的最优解。此时通过计算可以知道肯定是[1,1,0]是最好的结果,可是数据如果很大的时候,该怎么判断某个状态之后,做出的解就是最优解呢,或者进入这个状态之前所做的导致进入这个状态的一个解也是最优解呢,因为如果在某状态下做出的某一个解不是最优解,那这个解也一定不是最初始答案的最优解。

               所以上述这种问题的核心就是一个,如何确定做的这一步是最优解的一个组成部分,动态规划的方法是建立一个动态规划递归方程,dp和贪婪算法不一样,是可逆的,可以通过递归方程不断进行迭代,不断修正做出的选择。

                例如1.2中提出的背包问题,最优选择序列是由最优子选择序列构成的,我们假设f(i,y)表示背包剩下的容量为y,剩下物品是i、i+1....n的背包问题的最优解。
                pn代表第n个物品的价值,wn代表第n个物品的重量,y代表剩余容量。同一个等式写两遍,代表两种不同的情况,视y的大小决定。那么可以得到如下的等式:f(n,y)=pn (y>=wn))f(n,y)=0(0<=y<wn)
和f(n,y)=max(f(i+1,y),f(i+1,y-wi)+pi) (y>=wi) f(n,y)=f(i+1,y)(0<=y<wi)
                上述两个等式的意思是,当剩余容量y大于当前物品i的重量时,那么最优解就是取这个物品和不取这个物品两种情况的最大值,如果剩余容量y小于当前物品i的重量,那么直接就不能放下当前物品。根据最优序列是由最优子序列构成这个结论,可以得到f的递归式子,当递归到n=1的时候就是背包问题最初始时最优解的值,这里就是递归的出口,符合递归的定律,递归必须要有一个可以结束的点。明显f(n,y)是可以通过f(n,y)=max(f(i+1,y),f(i+1,y-wi)+pi)(y>=wi) f(n,y)=f(i+1,y)(0<=y<wi)递归求得的.

                 以1.2作为例子举例,如果要求f(3,116),那么可得f(3,116)=max(f(2,116),f(2,16)+20),由公式可知f(2,116)=max(f(1,116),f(1,102)+18)、f(2,16)=max(f(1,16),f(1,2)+18),同理求得f(1,116)=15,f(1,102)=15,f(1,16)=15,f(1,2)=0.
那么可以算出f(3,116)=max(max(15,15+18),max(15,0+18)+20)=max(33,38)=38。得出最优解是38.然后可以由3个f(n,y)(n等于1,2,3)之间的关系判断出最终结果为[1,1,0],1代表装入背包,0代表不装入背包。
                由上面的计算过程可以看出,无论之前的选择是什么,接下来的选择一定是当前状态下的最大值,也就是最优选择,这就是最优原则,它代表了一个最优选择序列一定由最优选择子序列所构成的,所以应用动态规划就一定要证明该问题适用最优原则,然后就建立动态规划的递归方程组,然后通过不断迭代递归求解该递归方程组,然后由最优解以及各个不同的f(n,y)之间的关系可以求出最优解的组成,上述那个简单的例子中并没有一些重复的计算,但是在复杂的动态规划问题中是存在很多重复的计算的,如果不能避免这些重复的计算,dp的复杂度也会很高.

                 例如有类似于例1.2的题目,但是数据是n=4,w=[20,20,14,10],c=100,p=[20,20,18,15],在计算f(4,100)=max(f(3,100),f(3,80)+20)中,f(3,100)后续会计算f(2,80),而f(3,80)后续也会计算f(2,80),如果不能很好的避免这些重复计算,动态规划的优越性就荡然无存,下面就用几个具体的例子的dp解法来进行实战。

二、实际应用


2.1 0/1背包问题


 (1)递归求解
  在第一大节中所说的函数f求解方程如下所示:

int f(int i,int thecapacity)
    {
        if(i==numberofobjects)//遍历到了最后一个物品,这很明显也是递归的出口。
            return (thecapacity<weight[numberofobjects]?0:profit(numberofobjects));
            if(thecapacity<weight[i])//如果容量不够,那么不能将物品i放入背包,否则是下一种情况。
            return f(i+1,thecapacity);
            return max(f(i+1,thecapacity),f(i+1,thecapacity-weight[i])+profit[i]);
    }


            其中的numberofobjects代表的是物品的个数,i代表目前遍历到了第几个物品,thecapacity代表的是背包剩下的容量,weight数组代表的是每个物品的重量,profit数组代表的是每个物品的价值,其中profit和weight还有thecapacity是全局变量,上述代码的时间复杂度是O(2^n)。
          上述这种问题在一个实际的例子当中时,比如n=5,p=[6,3,5,4,6],w=[2,2,6,5,4],c=10的时候,就会很明显的出现第一大节中提到的重复计算,具体可看下一图:


             上图中的波浪线所标注的就是出现重复计算的部分,其实只要在上图树中只要两个节点高度相同,并且剩余容量相同,那么它们所有的后续计算都是重复计算,一般为了避免这种重复计算,采用的方式都是建立一个dp数组,该数组用来存储计算过的f(n,y)的值,具体可以看下面这种无重复计算的f函数:


   

 int f(int i,int thecapacity)
    {
        if(dp[i][thecapacity]>=0)

            return dp[i][thecapacity];//若已经计算过就不用再次计算了
        if(i==numberofobjects)//遍历到了最后一个物品,这很明显也是递归的出口。
        {
            dp[i][thecapacity]=(thecapacity<weight[numberofobjects]?0:profit(numberofobjects));
                return dp[i][thecapacity];
        }
            
            if(thecapacity<weight[i])//如果容量不够,那么不能将物品i放入背包,否则是下一种情况。
                 dp[i][thecapacity]=f(i+1,thecapacity);
            else//容量足够,那么选择两种情况里面的最大值
                dp[i][thecapacity]=max(f(i+1,thecapacity),f(i+1,thecapacity-weight[i])+profit[i]);
        return dp[i][thecapacity];
    }



             时间复杂度已经降低到了O(cn)(c表示背包容量,n表示物品个数),其中依然有numberofobjects代表的是物品的个数,i代表目前遍历到了第几个物品,thecapacity代表的是背包剩下的容量,weight数组代表的是每个物品的重量,profit数组代表的是每个物品的价值,其中profit和weight还有thecapacity是全局变量,多增加了一个全局变量dp,它的定义应当是vector<vector<int>>dp(n+1,vector<int>(thecapacity+1,-1)),-1代表这个值未曾计算过,最后返回的是dp.back().back(),也就是返回dp[n][c]。


2.2最长子序列

              下面的代码是求最长严格上升子序列(元素之间不需要连续),dp在这种求最长某种限制的子序列,或者说求最大之类的情况下,都是比较适用的,比如下面这个题,具体的就在代码里面看吧。

#code

    

#include<iostream>
    #include<vector>
    #include<algorithm>
    using namespace std;
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size()==0)
            return 0;
        vector<int>res(nums.size(),1);//建立dp数组,因为最少包含一个元素,所以最小值肯定是为1,所以初值置为1.
        for(int i=1;i<nums.size();++i)
        {
            for(int j=0;j<i;++j)//如果num[i]大于num[j],代表num[j]可以接在num[i]后面成为一个上升子序列。
            {
                if(nums[i]>nums[j])
                    res[i]=max(res[i],res[j]+1);
            }
        }
        sort(res.begin(),res.end());//排序找出最大值,也就是最长的子序列的长度。
        return res.back();
    }
    int main()
    {
        long n;
        cin>>n;
        vector<int>nums(n,0);
        while(n--)//构造需要处理的数组
        {
            int temp=0;
            cin>>temp;
            nums[n]=temp;
        }
        
        cout<<lengthOfLIS(nums);//输出最长严格上升子序列的长度
        system("pause");
        return 0;
    
    }



运行的结果如下所示:


输入数组为[4,2,1,2,4,1,6,8,9],可以知道它的最长严格上升子序列为[1,2,4,6,8,9],符合输出答案的长度为6.


2.3求最大值

             爱玩游戏的小J,小J给每个游戏标上一个成就值,同时估算了完成这些游戏所需要的时间,现在他只有X天时间,而游戏一旦开始玩,至少需要玩一天才能够停下来,那么他玩完的游戏的成就值之和最大能达到多少呢?

            虽然是游戏,但其实就是一个0/1背包问题,完成这个游戏等同于放入背包,x天等同于背包容量,所以依然是一样的办法。




#code

    

#include<iostream>
    #include<vector>
    #include<algorithm>
    #include<map>
    using namespace std;
    int value(vector<pair<int,int>>&a,int day)
    {
        vector<int>p(day+1,0);//可以看出,其实不一定要用二维数组和递归也能做dp,不过把vector里面的元素换成了pair格式,因为要存耗时天数和成就值。
        for (int k = 0; k<a.size();++k)//可以看出复杂度是c*n
        {
            for(int i=day;i>=0;--i)
            {
                if(a[k].second<=i)//第k个游戏可以完成,那么有两种可能。
                    p[i]=max(p[i],p[i-a[k].second]+a[k].first);
            }
        }//双重循环用第二个循环代替了一个单独存储剩余天数的数据,所以可以不用递归。
        return p.back();
    
    }
    int main()
    {
        int num=0;
        cin>>num;
        vector<int>res;
        while(num--)
        {
            int game_num=0;
            cin>>game_num;
            int day_num=0;
            cin>>day_num;
            vector<pair<int,int>>game__num;
            while(game_num--)
            {    
                pair<int,int> temp;
                cin>>temp.first;
                cin>>temp.second;
                game__num.push_back(temp);
            }//输入测试用例
            int value_num=value(game__num,day_num);//进行dp运算
            res.push_back(value_num);
        }
        for(int i=0;i<res.size();++i)
        {
            cout<<res[i]<<endl;
        }
        system("pause");
        return 0;
         
    }


输出结果如下所示:


输入:
第一行输入case数T,对于每个case,第一行输入游戏的数目N,总时间X。从第二行到第N+1行输入游戏的成就值Ai,所需要的时间Bi。
输出:
对每个case输出一行,成就值之和的最大值。

第一个例子输入的是2天的情况下,一个游戏的价值10,耗时1天,一个游戏耗时2天,成就20,明显结果是20.
第二个例子输入的是4天的情况下,一个游戏的价值10,耗时2天,一个游戏的价值18,耗时3天,一个游戏的价值10,耗时2天,结果为20,是最大值。

2.4求最大值(依然是一个求最大值的问题,但是多了一个约束条件,相当于约束条件多一点的背包问题)


             维克多博士创造了一个裂变反应堆,可取用处于液体状态的放射性物质。反应堆的容量是V加仑。他有N瓶的放射性液体,每个都有一定的质量和一定的体积。当液体倒入反应堆时,也产生一些单位的能量。现在,维克多想要将能量输出最大化。但是,有一个限制条件。他研究了原子元素的物理知识和历史,认识到反应堆内放射性液体的总量不能超过特定的临界质量M,否则反应就会失控,并引发剧烈的爆炸。写一个算法,帮助他从反应堆获得最大的能量,而不会让他丢掉性命。
输入:

该函数/方法的输入包括六个参数------
reactorCap,一个整数,表示反应堆的容量(V);
numberOfRadLiquid,一个整数,表示现有小瓶的数量(N);
criticalMass,一个整数,表示反应堆的最大临界质量(M);
volumes,一个整数列表,按顺序表示N份放射性液体的体积;
masses,一个整数列表,按顺序表示N份放射性液体的质量;
energies,一个整数列表,按顺序表示N份放射性液体产生的能量。
输出:
返回一个整数,表示可给定的约束条件下从反应堆中产生的最大能量。
示例:
输入:
reactorCap=100,numberOfRadLiquid=5,criticalMass=15,volumes=[50,40,30,20,10],masses=[1,2,3,9,5],energies=[300,480,270,200,180]
输出:
960
解释:
选择1、2、5号瓶中的液体,产生的能量=300+480+180=960.


#思路
            利用动态规划解决这道题时,使用一个函数f来表示最大能量,方程为f(v,m,n), 这个方程的解表示n个小瓶在约束条件最大质量m,最大容量v下可以获得的最大能量,那么很显然f(v,m,n)=max(f(v,m,n),f(v,m,n-1),f(v-v(k),m-m(k),n)),利用一个二维数组表示在某个体积和质量的约束下可获得的最大能量。


#code

    

#include <iostream>
    #include <vector>
    #include <map>
    #include <algorithm>
    using namespace std;
    int maxenergy(int reactorCap, int numofliq, int maxmass, vector<int> volumes, vector<int> mass, vector<int> energies){
        int res;
        vector<vector<int>> p(maxmass + 1, vector<int>(reactorCap + 1, 0));//以容量和质量的最大值建一个二维数组表示质量为i,体积为j时可以获得的最大能量,然后对状态(i,j)进行更新,从后往前更新。
        for (int k = 0; k < mass.size(); ++k)
        {
            for (int i = p.size() - 1; i>0; --i)//不用等于0,因为体积或者质量某一个等于0,都无法放下新瓶子。
            {
                for (int j = p[i].size() - 1; j>0; --j)
                {
                    if (mass[k] <= i && volumes[k] <= j)//如果mass[k]小于目前的质量i,volumes[k]小于目前的容量j,说明可以装入第k个瓶子,这里有很多冗余计算。
                        p[i][j] = max(p[i][j], (p[i - mass[k]][j - volumes[k]] + energies[k]));//计算最大值,由前面说的那个状态转移方程来计算最大值。
                        //如果我装下这个瓶子,会导致我之前一些瓶子装不下,那么就要判断两者到底谁更大,选择更大的。
                }
            }
            for(int i=0;i<p.size();++i)
            {
                for(int j=0;j<p[i].size();++j)
                {cout<<p[i][j]<<" ";}
                cout<<endl;
            }
        }
    
        res = p.back().back();//最后一个一定是最大的,因为最后一维才是考虑了所有的瓶子的。
        for(int i=0;i<p.size();++i)
        {
            for(int j=0;j<p[i].size();++j)
            {cout<<p[i][j]<<" ";}
            cout<<endl;
        }
        return res;
    }
    
    int main(){
        int reactorCap ;
        cout<<"please intput reactorCap: ";
        cin>>reactorCap;
        int numberOfRadLiquid  ;
        cout<<"please intput numberOfRadLiquid: ";
        cin>>numberOfRadLiquid;
        int maxmass ;
        cout<<"please intput maxmass: ";
        cin>>maxmass;
        vector<int>vol;
        vector<int>mass;
        vector<int>ener;
        for(int i=0;i<numberOfRadLiquid;i++)
        {
            int temp;
            cout<<"please intput vol["<<i<<"]:";
            cin>>temp;
            vol.push_back(temp);
            
        }
        for(int i=0;i<numberOfRadLiquid;i++)
        {
            int temp;
            
            cout<<"please intput mass["<<i<<"]:";
            cin>>temp;
            mass.push_back(temp);
            
            
        }
        for(int i=0;i<numberOfRadLiquid;i++)
        {
            int temp;
           
            cout<<"please intput ener["<<i<<"]:";
            cin>>temp;
            ener.push_back(temp);
            
        }
        int res = maxenergy(reactorCap, numberOfRadLiquid, maxmass, vol, mass, ener);
        cout<<res<<endl;;
        system("pause");
        return 0;
    }


运行结果如下所示:

             可以从上面两张图看出,随着不断加入新的液体,最大值也在不断的更新,并且是在满足这个二维数组的纬度下的更新,这个二维数组的纬度其实就是题目的约束条件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式架构 漫谈分布式架构 初识分布式架构与意义 如何把应用从单机扩展到分布式 大型分布式架构演进过程 分布式架构设计 主流架构模型-SOA架构和微服务架构 领域驱动设计及业务驱动规划 分布式架构的基本理论CAP、BASE以及其应用 什么是分布式架构下的高可用设计 构架高性能的分布式架构 构建分布式架构最重要因素 CDN静态文件访问 分布式存储 分布式搜索引擎 应用发布与监控 应用容灾及机房规划 系统动态扩容 分布式架构策略-分而治之 从简到难,从网络通信探究分布式通信原理 基于消息方式的系统间通信 理解通信协议传输过程中的序列化和反序列化机制 基于框架的RPC通信技术 WebService/ApacheCXF RMI/Spring RMI Hession 传统RPC技术在大型分布式架构下面临的问题 分布式架构下的RPC解决方案 Zookeeper 分布式系统的基石 从0开始搭建3个节点额度zookeeper集群 深入分析Zookeeper在disconf配置中心的应用 基于Zookeeper Watcher 核心机制深入源码分析 Zookeeper集群升级、迁移 基于Zookeeper实现分布式服务器动态上下线感知 深入分析Zookeeper Zab协议及选举机制源码解读 Dubbo 使用Dubbo对单一应用服务化改造 Dubbo管理中心及及监控平台安装部署 Dubbo分布式服务模块划分(领域驱动) 基于Dubbo的分布式系统架构实战 Dubbo负载均衡策略分析 Dubbo服务调试之服务只订阅及服务只注册配置 Dubbo服务接口的设计原则(实战经验) Dubbo设计原理及源码分析 基于Dubbo构建大型分布式电商平台实战雏形 Dubbo容错机制及扩展性分析 分布式解决方案 分布式全局ID生成方案 session跨域共享及企业级单点登录解决方案实战 分布式事务解决方案实战 高并发下的服务降级、限流实战 基于分布式架构下分布式锁的解决方案实战 分布式架构实现分布式定时调度 分布式架构-中间件 分布式消息通信 消息中间件在分布式架构中的应用 ActiveMQ ActiveMQ高可用集群企业及部署方案 ActiveMQ P2P及PUB/SUB模式详解 ActiveMQ消息确认及重发策略 ActiveMQ基于Spring完成分布式消息队列实战 Kafka Kafka基于Zookeeper搭建高可用集群实战 kafka消息处理过程剖析 Java客户端实现Kafka生产者与消费者实例 kafka的副本机制及选举原理剖析 基于kafka实现应用日志实时上报统计分析 RabbitMQ 初步认识RabbitMQ及高可用集群部署 详解RabbitMQ消息分发机制及主题消息分发 RabbitMQ消息路由机制分析 RabbitMQ消息确认机制 Redis redis数据结构分析 Redis主从复制原理及无磁盘复制分析 Redis管道模式详解 Redis缓存与数据库一致性问题解决方案 基于redis实现分布式实战 图解Redis中的AOF和RDB持久化策略的原理 redis读写分离架构实践 redis哨兵架构及数据丢失问题分析 redis Cluster数据分布算法之Hash slot redis使用常见问题及性能优化思路 redis高可用及高并发实战 缓存击穿、缓存雪崩预防策略 Redis批量查询优化 Redis高性能集群之Twemproxy of Redis 数据存储 MongoDB NOSQL简介及MongoDB支持的数据类型分析 MongoDB可视化客户端及JavaApi实践 手写基于MongoDB的ORM框架 MongoDB企业级集解决方案 MongoDB聚合、索引及基本执行命令 MongoDB数据分片、转存及恢复策略 MyCat MySQL主从复制及读写分离实战 MySQL+keepalived实现双主高可用方案实践 MySQL高性能解决方案之分库分表 数据库中间件初始Mycat 基于Mycat实习MySQL数据库读写分离 基于Mycat实战之数据库切分策略剖析 Mycat全局表、Er表、分片预警分析 Nginx 基于OpenResty部署应用层Nginx以及Nginx+lua实战 Nginx反向代理服务器及负载均衡服务器配置实战 利用keepalived+Nginx实战Nginx高可用方案 基于Nginx实现访问控制、连接限制 Nginx动静分离实战 Nginx Location ReWrite 等语法配置及原理分析 Nginx提供https服务 基于Nginx+lua完成访问流量实时上报Kafka的实战 Netty 高性能NIO框架 IO 的基本概念、NIO、AIO、BIO深入分析 NIO的核心设计思想 Netty产生的背景及应用场景分析 基于Netty实现的高性能IM聊天 基于Netty实现Dubbo多协议通信支持 Netty无锁化串行设计及高并发处理机制 手写实现多协议RPC框架
由国内著名技术社区联合推荐的2012年IT技术力作:《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》,即将上架发行,此书从Web应用、数据备份与恢复、网络存储应用、运维监控与性能优化、集群高级应用等多个方面深入讲解了如何构建高性能的Linux服务器。其中蕴含了丰富的运维经验。更为重要的是,本书的内容不受硬件环境的限制,而且包含大量实用性极强的案例。对于广大Linux运维人员和系统管理人员来说,具有非常实用的指导意义。 全书共分五个篇幅,由14个章节组成,内容涉及Web应用、数据备份恢复、网络存储应用、性能优化与运维监控、集群高级应用方面,每个篇幅占用比例分别为:20%、20%、14%、14%,32%。 前言 第1篇 Web应用篇 第1章 轻量级HTTP服务器Nginx 1.1 什么是Nginx 1.2 为什么要选择Nginx 1.2.1 Nginx与Apache的异同 1.2.2 选择Nginx的优势所在 1.3 Nginx的模块与工作原理 1.4 Nginx的安装与配置 1.4.1 下载与安装Nginx 1.4.2 Nginx配置文件的结构 1.4.3 配置与调试Nginx 1.4.4 Nginx的启动、关闭和平滑重启 1.5 Nginx常用配置实例 1.5.1 虚拟主机配置实例 1.5.2 负载均衡配置实例 1.5.3 防盗链配置实例 1.5.4 日志分割配置实例 1.6 Nginx性能优化技巧 1.6.1 编译安装过程优化 1.6.2 利用TCMalloc优化Nginx的性能 1.6.3 Nginx内核参数优化 1.7 实战Nginx与PHP(FastCGI)的安装、配置与优化 1.7.1 什么是 FastCGI 1.7.2 Nginx+FastCGI运行原理 1.7.3 spawn-fcgi与PHP-FPM 1.7.4 PHP与PHP-FPM的安装及优化 1.7.5 配置Nginx来支持PHP 1.7.6 测试Nginx对PHP的解析功能 1.7.7 优化Nginx中FastCGI参数的实例 1.8 实战Nginx与Perl、Java的安装与配置 1.8.1 Perl(FastCGI)的安装 1.8.2 为Nginx添加FCGI支持 1.8.3 测试Nginx +Perl(FastCGI) 1.8.4 搭建Nginx+Java环境 1.9 本章小结 第2章 高性能HTTP加速器Varnish 2.1 初识Varnish 2.1.1 Varnish概述 2.1.2 Varnish的结构与特点 2.1.3 Varnish与Squid的对比 2.2 开始安装Varnish 2.2.1 安装前的准备 2.2.2 获取Varnish软件 2.2.3 安装pcre 2.2.4 安装Varnish 2.3 配置Varnish 2.3.1 VCL使用说明 2.3.2 配置一个简单的Varnish实例 2.3.3 Varnish对应多台Web服务器的配置实例 2.4 运行Varnish 2.4.1 varnishd指令 2.4.2 配置Varnish运行脚本 2.4.3 管理Varnish运行日志 2.5 管理Varnish 2.5.1 查看Varnish进程 2.5.2 查看Varnish缓存效果与状态 2.5.3 通过端口管理Varnish 2.5.4 管理Varnish缓存内容 2.6 Varnish优化 2.6.1 优化Linux内核参数 2.6.2 优化系统资源 2.6.3 优化Varnish参数 2.7 Varnish的常见应用实例 2.7.1 利用Varnish实现图片防盗链 2.7.2 利用Varnish实现静态文件压缩处理 2.8 本章小结 第3章 Memcached应用实战 3.1 Memcached基础 3.1.1 什么是Memcached 3.1.2 Memcached的特征 3.1.3 Memcached的安装 3.1.4 Memcached的简单使用过程 3.2 剖析Memcached的工作原理 3.2.1 Memcached的工作过程 3.2.2 Slab Allocation的工作机制 3.2.3 Memcached的删除机制 3.2.4 Memcached的分布式算法 3.3 Memcached的管理与性能监控 3.3.1 如何管理Memcached 3.3.2 Memcached的监控 3.3.3 Memcached变种产品介绍 3.4 通过UDFs实现Memcached与MySQL的自动更新 3.4.1 UDFs使用简介 3.4.2 memcached_functions_mysql应用实例 3.4.3 对memcached_functions_mysql的简单功能进行测试 3.4.4 使用memcached_functions_mysql的经验与技巧 3.5 本章小结 第2篇 数据备份恢复篇 第4章 开源网络备份软件bacula 4.1 bacula总体概述 4.1.1 bacula是什么 4.1.2 bacula适合哪些用户 4.1.3 bacula的功能特点 4.1.4 bacula的工作原理 4.2 安装bacula 4.2.1 bacula的几种网络备份拓扑 4.2.2 编译与安装bacula 4.2.3 初始化MySQL数据库 4.3 配置一个bacula备份系统 4.3.1 配置bacula的Console端 4.3.2 配置bacula的Director端 4.3.3 配置bacula的SD 4.3.4 配置bacula的FD端 4.4 启动与关闭bacula 4.4.1 启动bacula的Director daemon与Storage daemon 4.4.2 在客户端FD启动File daemon 4.5 实战bacula备份恢复过程 4.5.1 实例演示bacula的完全备份功能 4.5.2 实例演示bacula的增量备份功能 4.5.3 实例演示bacula的差异备份功能 4.5.4 实例演示bacula的完全恢复功能 4.5.5 实例演示bacula的不完全恢复功能 4.6 本章小结 第5章 数据镜像备份工具rsync与unison 5.1 rsync简介 5.1.1 什么是rsync 5.1.2 rsync的功能特性 5.1.3 下载与安装rsync软件 5.2 利用rsync搭建数据镜像备份系统 5.2.1 rsync的应用模式 5.2.2 企业案例:搭建远程容灾备份系统 5.3 通过rsync+inotify实现数据的实时备份 5.3.1 rsync的优点与不足 5.3.2 初识inotify 5.3.3 安装inotify工具inotify-tools 5.3.4 inotify相关参数 5.3.5 inotifywait相关参数 5.3.6 企业应用案例:利用rsync+inotify搭建实时同步系统 5.4 unison简介 5.5 安装unison 5.6 配置双机ssh信任 5.6.1 在两台机器上创建 RSA密钥 5.6.2 添加密钥到授权密钥文件中 5.7 unison的使用 5.7.1 本地使用unison 5.7.2 远程使用unison 5.7.3 unison参数说明 5.7.4 通过配置文件来使用unison 5.8 本章小结 第6章 ext3文件系统反删除利器ext3grep 6.1 “rm–rf”带来的困惑 6.2 ext3grep的安装与使用 6.2.1 ext3grep的恢复原理 6.2.2 ext3grep的安装过程 6.3 通过ext3grep恢复误删除的文件与目录 6.3.1 数据恢复准则 6.3.2 实战ext3grep恢复文件 6.4 通过ext3grep恢复误删除的MySQL表 6.4.1 MySQL存储引擎介绍 6.4.2 模拟MySQL表被误删除的环境 6.4.3 通过ext3grep分析数据、恢复数据 6.5 本章小结 第3篇 网络存储应用篇 第7章 IP网络存储iSCSI 7.1 存储的概念与术语 7.1.1 SCSI介绍 7.1.2 FC介绍 7.1.3 DAS介绍 7.1.4 NAS介绍 7.1.5 SAN介绍 7.2 iSCSI的概念 7.3 FC SAN与IP SAN 7.4 iSCSI的组成 7.4.1 iSCSI Initiator 7.4.2 iSCSI Target 7.5 iSCSI的工作原理 7.6 搭建基于IP SAN的iSCSI存储系统 7.6.1 安装iSCSI Target软件 7.6.2 配置一个简单的iSCSI Target 7.6.3 在Windows上配置iSCSI Initiator 7.6.4 在Linux上配置iSCSI Initiator 7.7 iSCSI 在安全方面的相关设定 7.7.1 Initiator主机以IP认证方式获取iSCSI Target资源 7.7.2 Initiator主机以密码认证方式获取iSCSI Target资源 7.8 iSCSI性能优化方案 7.8.1 iSCSI性能瓶颈 7.8.2 iSCSI性能优化 7.9 本章小结 第8章 分布式存储系统MFS 8.1 MFS概论 8.2 MFS 文件系统 8.2.1 MFS文件系统结构 8.2.2 MFS的编译与安装实例 8.3 编译与使用MFS的经验总结 8.3.1 安装选项说明 8.3.2 管理服务器 8.3.3 元数据日志服务器 8.3.4 数据存储服务器 8.3.5 客户端挂载 8.4 管理与使用MFS 8.4.1 在客户端挂载文件系统 8.4.2 MFS常用操作 8.4.3 为垃圾箱设定隔离时间 8.4.4 快照 8.4.5 MFS的其他命令 8.5 维护MFS 8.5.1 启动MFS集群 8.5.2 停止MFS集群 8.5.3 MFS 数据存储服务器的维护 8.5.4 MFS元数据的备份 8.5.5 MFS 管理服务器的恢复 8.5.6 从备份恢复MFS 管理服务器 8.6 通过冗余实现失败防护的解决方案 8.7 本章小结 第4篇 运维监控与性能优化篇 第9章 运维监控利器Nagios 9.1 Nagios综述 9.1.1 什么是Nagios 9.1.2 Nagios的结构与特点 9.2 Nagios的安装与配置 9.2.1 安装Nagios 9.2.2 配置Nagios 9.3 Nagios的运行和维护 9.3.1 验证Nagios配置文件的正确性 9.3.2 启动与停止Nagios 9.3.3 Nagios故障报警 9.4 Nagios性能分析图表的实现 9.4.1 Nagios性能分析图表的作用 9.4.2 PNP的概念与安装环境 9.4.3 安装PNP 9.4.4 配置PNP 9.4.5 修改Nagios配置文件 9.4.6 测试PNP功能 9.5 利用插件扩展Nagios的监控功能 9.5.1 利用NRPE外部构件监控远程主机 9.5.2 利用飞信实现Nagios短信报警功能 9.6 本章小结 第10章 基于Linux服务器的性能分析与优化 10.1 系统性能分析的目的 10.1.1 找到系统性能的瓶颈 10.1.2 提供性能优化方案 10.1.3 使系统硬件和软件资源的使用达到平衡 10.2 分析系统性能涉及的人员 10.2.1 Linux系统管理人员 10.2.2 系统架构设计人员 10.2.3 软件开发人员 10.3 影响Linux性能的各种因素 10.3.1 系统硬件资源 10.3.2 操作系统相关资源 10.3.3 应用程序软件资源 10.4 系统性能分析标准和优化原则 10.5 几种典型应用对系统资源使用的特点 10.5.1 以静态内容为主的Web应用 10.5.2 以动态内容为主的Web应用 10.5.3 数据库应用 10.5.4 软件下载应用 10.5.5 流媒体服务应用 10.6 Linux下常见的性能分析工具 10.6.1 vmstat命令 10.6.2 sar命令 10.6.3 iostat命令 10.6.4 free命令 10.6.5 uptime命令 10.6.6 netstat命令 10.6.7 top命令 10.7 基于Web应用的性能分析及优化案例 10.7.1 基于动态内容为主的网站优化案例 10.7.2 基于动态、静态内容结合的网站优化案例 10.8 本章小结 第5篇 集群高级应用篇 第11章 构建高可用的LVS负载均衡集群 11.1 LVS集群的组成与特点 11.1.1 LVS集群的组成 11.1.2 LVS集群的特点 11.1.3 LVS集群系统的优缺点 11.2 高可用 LVS负载均衡集群体系结构 11.3 高可用性软件Heartbeat与Keepalived 11.3.1 开源HA软件Heartbeat的介绍 11.3.2 安装heartbeat 11.3.3 开源HA软件Keepalived的介绍 11.3.4 安装Keepalived 11.4 安装LVS软件 11.4.1 配置与检查安装环境 11.4.2 在Director Server上安装IPVS管理软件 11.5 搭建高可用 LVS集群 11.5.1 通过heartbeat搭建LVS高可用性集群 11.5.2 通过Keepalived搭建LVS高可用性集群系统 11.5.3 通过piranha搭建LVS高可用性集群 11.6 测试高可用LVS负载均衡集群系统 11.6.1 高可用性功能测试 11.6.2 负载均衡测试 11.6.3 故障切换测试 11.7 本章小结 第12章 RHCS集群 12.1 RHCS集群概述 12.2 RHCS集群的组成与结构 12.2.1 RHCS集群的组成 12.2.2 RHCS集群结构 12.3 RHCS集群的运行原理及功能 12.3.1 分布式集群管理器(CMAN) 12.3.2 锁管理(DLM) 12.3.3 配置文件管理(CCS) 12.3.4 栅设备(Fence) 12.3.5 高可用性服务管理器 12.3.6 集群配置和管理工具 12.3.7 Redhat GFS 12.4 安装RHCS 12.4.1 安装前准备工作 12.4.2 配置共享存储和RHCS管理端Luci 12.4.3 在集群节点上安装RHCS软件包 12.4.4 在集群节点上安装和配置iSCSI客户端 12.5 配置RHCS高可用集群 12.5.1 创建一个cluster 12.5.2 创建Failover Domain 12.5.3 创建Resources 12.5.4 创建Service 12.5.5 配置存储集群GFS 12.5.6 配置表决磁盘 12.5.7 配置Fence设备 12.6 管理和维护RHCS集群 12.6.1 启动RHCS集群 12.6.2 关闭RHCS集群 12.6.3 管理应用服务 12.6.4 监控RHCS集群状态 12.6.5 管理和维护GFS2文件系统 12.7 RHCS集群功能测试 12.7.1 高可用集群测试 12.7.2 存储集群测试 12.8 本章小结 第13章 Oracle RAC集群 13.1 Oracle集群体系结构 13.2 Oracle ClusterWare体系结构与进程介绍 13.2.1 Oracle ClusterWare 简介 13.2.2 Oracle ClusterWare 进程介绍 13.3 RAC数据库体系结构与进程 13.3.1 RAC 简介 13.3.2 Oracle RAC的特点 13.3.3 RAC进程管理 13.3.4 RAC数据库存储规划 13.4 安装Oracle RAC数据库 13.4.1 安装前的系统配置需求 13.4.2 设置数据库安装资源 13.4.3 配置主机解析文件 13.4.4 检查所需软件包 13.4.5 配置系统内核参数 13.4.6 设置 Shell对Oracle用户的限制 13.4.7 配置hangcheck-timer内核模块 13.4.8 配置系统安全设置 13.4.9 创建Oracle用户和组 13.4.10 设置Oracle用户环境变量 13.4.11 配置节点间SSH信任 13.4.12 配置共享存储系统 13.4.13 安装Oracle Clusterware 13.4.14 安装Oracle数据库 13.4.15 配置Oracle Net 13.4.16 创建RAC数据库 13.5 Oracle CRS的管理与维护 13.5.1 查看集群状态 13.5.2 启动与关闭集群服务资源 13.5.3 启动与关闭CRS 13.5.4 管理voting disk 13.5.5 管理OCR 13.5.6 快速卸载CRS 13.6 ASM基本操作维护 13.6.1 ASM的特点 13.6.2 ASM的体系结构与后台进程 13.6.3 管理ASM实例 13.7 利用srvctl管理RAC数据库 13.7.1 查看实例状态(srvctl status) 13.7.2 查看RAC数据库配置信息(srvctl config) 13.7.3 启动 13.7.4 增加 13.8 测试RAC数据库集群的功能 13.8.1 负载均衡测试 13.8.2 透明应用失败切换测试 13.9 本章小结 第14章 构建MySQL+heartbeat+DRBD+LVS集群应用系统 14.1 MySQL高可用集群概述 14.2 heartbeat + DRBD高可用性方案的实现原理 14.3 部署MySQL高可用高扩展集群 14.3.1 配置之前的准备 14.3.2 DRBD的部署 14.3.3 DRBD的配置 14.3.4 DRBD的维护和管理 14.3.5 DRBD的性能优化 14.3.6 MySQL的部署 14.3.7 heartbeat的部署 14.4 搭建Slave集群 14.4.1 为什么要搭建Slave集群 14.4.2 利用LVS+Keepalived搭建高可用MySQL Slave集群 14.4.3 高可用Slave集群的一些注意点 14.5 部署MySQL集群要考虑的问题 14.6 本章小结
第一篇 平台篇 第1章 ARM处理器简介 1.1 ARM内核处理器沿革 1.1.1 传统ARM处理器 1.1.2 Cortex内核处理器 1.2 Cortex内核系列处理器技术特点 1.2.1 ARM Cortex-M系列处理器 1.2.2 ARM Cortex-R系列处理器 1.2.3 ARM Cortex-A系列处理器 1.3 STM32互联型嵌入式控制器 1.4 微控制器选型 1.4.1 选型因素 1.4.2 选型示例 第2章 基于STM32F107的开发板 2.1 STM32F107开发板 2.2 主要板载资源 2.2.1 10/100M以太网接口 2.2.2 CAN总线接口 2.2.3 RS485总线接口 2.2.4 其他总线接口 2.3 硬件设计要点 2.3.1 电磁兼容问题 2.3.2 信号完整性 2.3.3 电源完整性 第3章 开发环境 3.1 开发环境及搭建 3.1.1 常见开发环境 3.1.2 IAR EWARM安装 3.1.3 RealView MDK安装 3.2 相关开发工具 3.3 创建工程 第4章 编程规范 4.1 ST固件库编程规范 4.1.1 缩写 4.1.2 命名规则 4.1.3 编码规则 4.2 基于C语言的嵌入式编程规范 4.2.1 源代码的排版 4.2.2 源代码的注释 4.2.3 标识符命名 4.2.4 代码可读性 4.2.5 变量、结构 4.2.6 函数、过程 4.2.7 可测性 4.2.8 程序效率 4.2.9 质量保证 4.2.10 代码编辑、编译、审查 4.2.11 测试与维护 4.2.12 宏定义 第5章 项目规划 5.1 概述 5.2 系统分析 5.3 系统设计 5.4 系统制造 5.5 系统运用及反馈 5.6 开发团队 5.6.1 团队负责人 5.6.2 调研人员 5.6.3 开发人员 第篇 RTOS篇 第6章 操作系统原理基础知识 6.1 前后台模式应用程序 6.2 嵌入式操作系统 6.2.1 相关基本概念 6.2.2 系统调用 6.2.3 操作系统结构 6.2.4 进程与任务 6.2.5 进程间的通信 6.2.6 进程调度 6.2.7 存储管理 第7章 FreeRTOS嵌入式操作系统 7.1 FreeRTOS特色 7.2 任务管理 7.2.1 任务函数 7.2.2 基本任务状态 7.2.3 任务创建 7.2.4 任务的优先级 7.2.5 非运行状态 7.2.6 空闲任务及回调函数 7.2.7 改变任务优先级 7.2.8 删除任务 7.2.9 调度算法概述 7.3 队列管理 7.3.1 概述 7.3.2 使用队列 7.3.3 大型数据单元传输 7.4 中断管理 7.4.1 延迟中断处理 7.4.2 计数信号量 7.4.3 在中断服务例程中使用队列 7.4.4 中断嵌套 7.5 资源管理 7.5.1 基本概念 7.5.2 临界区与挂起调度器 7.5.3 互斥量 7.5.4 互斥的另一种实现 7.6 内存管理 7.6.1 概述 7.6.2 内存分配方案范例 7.7 常见错误 7.7.1 概述 7.7.2 栈溢出 7.7.3 其他常见错误 第8章 基于STM32F107的FreeRTOS移植 8.1 概述 8.2 FreeRTOS移植 8.2.1 portmacro.h头文件 8.2.2 port.c源文件 8.2.3 portasm.s汇编源文件 8.2.4 其他问题 8.3 创建测试任务 第三篇 LwIP篇 第9章 TCP/IP协议栈介绍 9.1 引言 9.2 网络分层 9.2.1 OSI七层参考模型 9.2.2 TCP/IP分层 9.2.3 TCP/IP协议簇的协议 9.3 IP协议 9.4 ARP协议与RARP协议 9.5 ICMP 9.6 TCP协议 9.7 UDP协议 9.8 FTP协议 第10章 LwIP轻量级TCP/IP协议栈 10.1 LwIP进程模型 10.2 LwIP缓冲与内存管理 10.2.1 LwIP动态内存管理机制 10.2.2 LwIP的缓冲管理机制 10.3 LwIP网络接口 10.4 LwIP的ARP处理 10.5 LwIP的IP处理 10.6 LwIP的ICMP处理 10.7 LwIP的UDP处理 10.8 LwIP的TCP处理 10.8.1 TCP处理流程概述 10.8.2 TCP控制块 10.8.3 LwIP的TCP滑动窗口 10.8.4 LwIP的TCP超时与重传 10.8.5 LwIP的TCP拥塞控制 10.8.6 LwIP的TCP定时器 10.9 LwIP的应用程序接口简介 10.9.1 RAW API接口 10.9.2 Sequential API接口 第11章 基于STM32F107的LwIP移植 11.1 ethernetif.c文件的移植 11.1.1 ethernetif_init函数 11.1.2 low_level_init函数 11.1.3 ethernetif_input函数 11.1.4 low_level_input函数 11.1.5 low_level_output函数 11.2 网络驱动移植 11.2.1 以太网控制器概述 11.2.2 以太网控制器硬件配置 11.2.3 以太网控制器硬件的引脚配置 11.2.4 以太网驱动之接收 11.2.5 以太网驱动之发送 11.2.6 其他注意事项 11.3 基于RAW API接口的HelloWorld例程 第四篇 移植篇 第12章 基于FreeRTOS的LwIP协议栈移植 12.1 概述 12.2 FreeRTOS下以太网驱动程序的移植 12.3 LwIP程序移植 12.3.1 以太网接口文件ethernetif.c的移植 12.3.2 操作系统模拟层文件sys_arch.c的移植 第13章 工业通信网关解析 13.1 概述 13.2 编码实现 13.3 通信测试 附录A 开发板原理图 附录B 专业术语 参考文献

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值