李春葆 算法设计与分析(第二版)答案

时间:2024-06-14 09:38:05

1.1    第 1 章─概论
1.1.1    练习题
1.    下列关于算法的说法中正确的有( )。Ⅰ.求解某一类问题的算法是唯一的
Ⅱ.算法必须在有限步操作之后停止
Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊Ⅳ.算法执行后一定产生确定的结果
A. 1 个    B.2 个    C.3 个    D.4 个
2.    T(n)表示当输入规模为 n 时的算法效率,以下算法效率最优的是( )。
A.T(n)= T(n-1)+1,T(1)=1    B.T(n)= 2n2
C.T(n)= T(n/2)+1,T(1)=1    D.T(n)=3nlog2n
3.    什么是算法?算法有哪些特征?
4.    判断一个大于 2 的正整数 n 是否为素数的方法有多种,给出两种算法,说明其中一种算法更好的理由。
5.    证明以下关系成立:
(1)10n2-2n=(n2)
(2)2n+1=(2n)
6. 证明 O(f(n))+O(g(n))=O(max{f(n),g(n)})  。
7.    有一个含 n(n>2)个整数的数组 a,判断其中是否存在出现次数超过所有元素一半的元素。
8.    一个字符串采用 string 对象存储,设计一个算法判断该字符串是否为回文。
9.    有一个整数序列,设计一个算法判断其中是否存在两个元素和恰好等于给定的整数 k。
10.    有两个整数序列,每个整数序列中所有元素均不相同。设计一个算法求它们的公共元素,要求不使用 STL 的集合算法。
11.    正整数 n(n>1)可以写成质数的乘积形式,称为整数的质因数分解。例如, 12=2*2*3,18=2*3*3,11=11。设计一个算法求 n 这样分解后各个质因数出现的次数,采用 vector 向量存放结果。
12.    有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个数。如序列 4、1、2、3 的相差最小的元素对的个数是 3,其元素对是(1,2),(2,3),
(3,4)。
13.    有一个 map<string,int>容器,其中已经存放了较多元素。设计一个算法求出其中重复的 value 并且返回重复 value 的个数。
14.    重新做第 10 题,采用 map 容器存放最终结果。
15.    假设有一个含 n(n>1)个元素的 stack<int>栈容器 st,设计一个算法出栈从栈顶到栈底的第 k(1≤k≤n)个元素,其他栈元素不变。


1.1.2    练习题参考答案
1.    答:由于算法具有有穷性、确定性和输出性,因而Ⅱ、Ⅲ、Ⅳ正确,而解决某一类问题的算法不一定是唯一的。答案为 C。
2.    答:选项 A 的时间复杂度为 O(n)。选项 B 的时间复杂度为 O(n2)。选项 C 的时间复杂度为 O(log2n)。选项 D 的时间复杂度为 O(nlog2n)。答案为 C。
3.    答:算法是求解问题的一系列计算步骤。算法具有有限性、确定性、可行性、输入性和输出性 5 个重要特征。
4.    答:两种算法如下:
#include <stdio.h> #include <math.h>
bool isPrime1(int n) //方法 1
{    for (int i=2;i<n;i++)
          if (n%i==0)
               return false;
     return true;
}
bool isPrime2(int n) //方法 2
{    for (int i=2;i<=(int)sqrt(n);i++)
          if (n%i==0)
               return false;
     return true;
}
void main()
{    int n=5;
     printf("%d,%d\n",isPrime1(n),isPrime2(n));
}
方法 1 的时间复杂度为 O(n),方法 2 的时间复杂度为 n,所以方法 2 更好。
5. 答:(1)当 n 足够大时,(10n2-2n)/( n2)=10,所以 10n2-2n=(n2)。
(2)2n+1=2*2n=(2n)。
6.    证明:对于任意 f1(n)∈O(f(n)) ,存在正常数 c1 和正常数 n1,使得对所有 n≥n1, 有 f1(n)≤c1f(n) 。
类似地,对于任意 g1(n)∈O(g(n))    ,存在正常数 c2 和自然数 n2,使得对所有 n≥n2, 有 g1(n)≤c2g(n) 。
令 c3=max{c1,c2},n3=max{n1,n2},h(n)= max{f(n),g(n)} 。则对所有的 n≥n3,有:
f1(n) +g1(n)≤c1f(n) + c2g(n)≤c3f(n)+c3g(n)=c3(f(n)+g(n))
≤c32max{f(n),g(n)}=2c3h(n)=O(max{f(n),g(n)})。
7.    解:先将 a 中元素递增排序,再求出现次数最多的次数 maxnum,最后判断是否满足条件。对应的程序如下:
#include <stdio.h> #include <algorithm> using namespace std;

bool solve(int a[],int n,int &x)
{
     sort(a,a+n);
int maxnum=0;           //递增排序
     //出现次数最多的次数
     int num=1;
     int e=a[0];
     for (int i=1;i<n;i++)
     {    if (a[i]==e)
          {    num++;
               if (num>maxnum)
               {    maxnum=num;
                    x=e;
               }
          }
          else
          {    e=a[i];
               num=1;
          }
     }
     if (maxnum>n/2)
          return true;
     else
          return false;
}
void main()
{    int a[]={2,2,2,4,5,6,2};
     int n=sizeof(a)/sizeof(a[0]);
     int x;
     if (solve(a,n,x))
          printf("出现次数超过所有元素一半的元素为%d\n",x);
     else
          printf("不存在出现次数超过所有元素一半的元素\n");
}
上述程序的执行结果如图 1.1 所示。
图 1.1    程序执行结果
8.    解:采用前后字符判断方法,对应的程序如下:
#include <iostream> #include <string> using namespace std;
bool solve(string str)    //判断字符串 str 是否为回文
{    int i=0,j=str.length()-1;
     while (i<j)
     {    if (str[i]!=str[j])
               return false;


          i++; j--;
     }
     return true;
}
void main()
{    cout << "求解结果" << endl;
     string str="abcd";
     cout << " " << str << (solve(str)?"是回文":"不是回文") << endl;
     string str1="abba";
     cout << " " << str1 << (solve(str1)?"是回文":"不是回文") << endl;
}
上述程序的执行结果如图 1.2 所示。
图 1.2    程序执行结果
9.    解:先将 a 中元素递增排序,然后从两端开始进行判断。对应的程序如下:
#include <stdio.h> #include <algorithm> using namespace std;
bool solve(int a[],int n,int k)
{    sort(a,a+n);        //递增排序
     int i=0, j=n-1;
     while (i<j)        //区间中存在两个或者以上元素
     {    if (a[i]+a[j]==k)
               return true;
          else if (a[i]+a[j]<k)
               i++;
          else
               j--;
     }
     return false;
}
void main()
{    int a[]={1,2,4,5,3};
     int n=sizeof(a)/sizeof(a[0]);
     printf("求解结果\n");
     int k=9,i,j;
     if (solve(a,n,k,i,j))
          printf(" 存在: %d+%d=%d\n",a[i],a[j],k);
     else
          printf(" 不存在两个元素和为%d\n",k);
     int k1=10;
     if (solve(a,n,k1,i,j))
          printf(" 存在: %d+%d=%d\n",a[i],a[j],k1);

     else
          printf(" 不存在两个元素和为%d\n",k1);
}
上述程序的执行结果如图 1.3 所示。
图 1.3 程序执行结果
10.    解:采用集合 set<int>存储整数序列,集合中元素默认是递增排序的,再采用二路归并算法求它们的交集。对应的程序如下:
#include <stdio.h> #include <set>
using namespace std;
void solve(set<int> s1,set<int> s2,set<int> &s3) //求交集 s3
{    set<int>::iterator it1,it2;
     it1=s1.begin(); it2=s2.begin();
     while (it1!=s1.end() && it2!=s2.end())
     {    if (*it1==*it2)
          {    s3.insert(*it1);
               ++it1; ++it2;
          }
          else if (*it1<*it2)
               ++it1;
          else
               ++it2;
     }
}
void dispset(set<int> s)        //输出集合的元素
{    set<int>::iterator it;
     for (it=s.begin();it!=s.end();++it)
          printf("%d ",*it);
     printf("\n");
}
void main()
{    int a[]={3,2,4,8};
     int n=sizeof(a)/sizeof(a[0]);
     set<int> s1(a,a+n);
     int b[]={1,2,4,5,3};
     int m=sizeof(b)/sizeof(b[0]);
     set<int> s2(b,b+m);
     set<int> s3;
     solve(s1,s2,s3);
     printf("求解结果\n");
     printf(" s1: "); dispset(s1);


     printf("  s2: "); dispset(s2);
     printf("  s3: "); dispset(s3);
}
上述程序的执行结果如图 1.4 所示。
图 1.4 程序执行结果
11.    解:对于正整数 n,从 i=2 开始查找其质因数,ic 记录质因数 i 出现的次数,当找到这样质因数后,将(i,ic)作为一个元素插入到 vector 容器 v 中。最后输出 v。对应的算法如下:
#include <stdio.h> #include <vector> using namespace std;
struct NodeType        //vector 向量元素类型
{    int p;            //质因数
     int pc;        //质因数出现次数
};
void solve(int n,vector<NodeType> &v) //求 n 的质因数分解
{    int i=2;
     int ic=0;
     NodeType e;
     do
     {    if (n%i==0)
          {    ic++;
               n=n/i;
          }
          else
          {    if (ic>0)
               {    e.p=i;
                    e.pc=ic;
                    v.push_back(e);
               }
               ic=0;
               i++;
          }
     } while (n>1 || ic!=0);
}
void disp(vector<NodeType> &v)    //输出 v
{    vector<NodeType>::iterator it;
     for (it=v.begin();it!=v.end();++it)
          printf(" 质因数%d 出现%d 次\n",it->p,it->pc);
}

void main()
{    vector<NodeType> v;
     int n=100;
     printf("n=%d\n",n);
     solve(n,v);
     disp(v);
}
上述程序的执行结果如图 1.5 所示。
图 1.5 程序执行结果
12.    解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个数。对应的程序如下:
#include <iostream> #include <algorithm> #include <vector> using namespace std;
int solve(vector<int> &myv)        //求 myv 中相差最小的元素对的个数
{    sort(myv.begin(),myv.end());    //递增排序
     int ans=1;
     int mindif=myv[1]-myv[0];
     for (int i=2;i<myv.size();i++)
     {    if (myv[i]-myv[i-1]<mindif)
          {    ans=1;
               mindif=myv[i]-myv[i-1];
          }
          else if (myv[i]-myv[i-1]==mindif)
               ans++;
     }
     return ans;
}
void main()
{    int a[]={4,1,2,3};
     int n=sizeof(a)/sizeof(a[0]);
     vector<int> myv(a,a+n);
     cout << "相差最小的元素对的个数: " << solve(myv) << endl;
}
上述程序的执行结果如图 1.6 所示。


图 1.6 程序执行结果
13.    解:对于 map<string,int>容器 mymap,设计另外一个 map<int,int>容器 tmap, 将前者的 value 作为后者的关键字。遍历 mymap,累计 tmap 中相同关键字的次数。一个参考程序及其输出结果如下:
#include <iostream> #include <map> #include <string> using namespace std; void main()
{    map<string,int> mymap;
     mymap.insert(pair<string,int>("Mary",80));
     mymap.insert(pair<string,int>("Smith",82));
     mymap.insert(pair<string,int>("John",80));
     mymap.insert(pair<string,int>("Lippman",95));
     mymap.insert(pair<string,int>("Detial",82));
     map<string,int>::iterator it;
     map<int,int> tmap;
     for (it=mymap.begin();it!=mymap.end();it++)
          tmap[(*it).second]++;
     map<int,int>::iterator it1;
     cout << "求解结果" << endl;
     for (it1=tmap.begin();it1!=tmap.end();it1++)
          cout << " " << (*it1).first << ": " << (*it1).second << "次\n";
}
上述程序的执行结果如图 1.7 所示。
图 1.7 程序执行结果
14.    解:采用 map<int,int>容器 mymap 存放求解结果,第一个分量存放质因数,第二个分量存放质因数出现次数。对应的程序如下:
#include <stdio.h> #include <map>
using namespace std;
void solve(int n,map<int,int> &mymap) //求 n 的质因数分解


     else
{     if (ic>0)
                    mymap[i]=ic;
               ic=0;
               i++;
          }
     } while (n>1 || ic!=0);
}
void disp(map<int,int> &mymap) //输出 mymap
{    map<int,int>::iterator it;
     for (it=mymap.begin();it!=mymap.end();++it)
          printf(" 质因数%d 出现%d 次\n",it->first,it->second);
}
void main()
{    map<int,int> mymap;
     int n=12345;
     printf("n=%d\n",n);
     solve(n,mymap);
     disp(mymap);
}
上述程序的执行结果如图 1.8 所示。
图 1.8 程序执行结果
15.    解:栈容器不能顺序遍历,为此创建一个临时 tmpst 栈,将 st 的 k 个元素出栈并进栈到 tmpst 中,再出栈 tmpst 一次得到第 k 个元素,最后将栈 tmpst 的所有元素出栈并进栈到 st 中。对应的程序如下:
#include <stdio.h> #include <stack> using namespace std;
int solve(stack<int> &st,int k)    //出栈第 k 个元素
{    stack<int> tmpst;
     int e;
     for (int i=0;i<k;i++)        //出栈 st 的 k 个元素并进 tmpst 栈
     {    e=st.top();
          st.pop();
          tmpst.push(e);
     }
     e=tmpst.top();                //求第 k 个元素
     tmpst.pop();
     while (!tmpst.empty())        //将 tmpst 的所有元素出栈并进栈 st
     {    st.push(tmpst.top());
          tmpst.pop();


     }
     return e;
}
void disp(stack<int> &st)        //出栈 st 的所有元素
{    while (!st.empty())
     {    printf("%d ",st.top());
          st.pop();
     }
     printf("\n");
}
void main()
{    stack<int> st;
     printf("进栈元素 1,2,3,4\n");
     st.push(1);
     st.push(2);
     st.push(3);
     st.push(4);
     int k=3;
     int e=solve(st,k);
     printf("出栈第%d 个元素是: %d\n",k,e);
     printf("st 中元素出栈顺序: ");
     disp(st);
}
上述程序的执行结果如图 1.9 所示。
图 1.9    程序执行结果
1.2    第 2 章─递归算法设计技术
1.2.1    练习题
1.    什么是直接递归和间接递归?消除递归一般要用到什么数据结构?
2.    分析以下程序的执行结果:
#include <stdio.h>
void f(int n,int &m)
{    if (n<1) return;
     else
     {    printf("调用f(%d,%d)前,n=%d,m=%d\n",n-1,m-1,n,m);
          n--; m--;
          f(n-1,m);
          printf("调用f(%d,%d)后:n=%d,m=%d\n",n-1,m-1,n,m);
     }

}
void main()
{    int n=4,m=4;
     f(n,m);
}
3.    采用直接推导方法求解以下递归方程:
T(1)=1
T(n)=T(n-1)+n    当 n>1
4.    采用特征方程方法求解以下递归方程:
H(0)=0
H(1)=1
H(2)=2
H(n)=H(n-1)+9H(n-2)-9H(n-3) 当 n>2
5.    采用递归树方法求解以下递归方程:
T(1)=1
T(n)=4T(n/2)+n    当 n>1
6.    采用主方法求解以下题的递归方程。
T(n)=1    当 n=1
T(n)=4T(n/2)+n2    当 n>1
7.    分析求斐波那契 f(n)的时间复杂度。
8.    数列的首项 a1=0,后续奇数项和偶数项的计算公式分别为 a2n=a2n-1+2,a2n+1=a2n- 1+a2n-1,写出计算数列第 n 项的递归算法。
9.    对于一个采用字符数组存放的字符串 str,设计一个递归算法求其字符个数(长度)。
10.    对于一个采用字符数组存放的字符串 str,设计一个递归算法判断 str 是否为回文。
11.    对于不带头结点的单链表 L,设计一个递归算法正序输出所有结点值。
12.    对于不带头结点的单链表 L,设计一个递归算法逆序输出所有结点值。
13.    对于不带头结点的非空单链表 L,设计一个递归算法返回最大值结点的地址(假设这样的结点唯一)。
14.    对于不带头结点的单链表 L,设计一个递归算法返回第一个值为 x 的结点的地址,没有这样的结点时返回 NULL。
15.    对于不带头结点的单链表 L,设计一个递归算法删除第一个值为 x 的结点。
16.    假设二叉树采用二叉链存储结构存放,结点值为 int 类型,设计一个递归算法求二叉树 bt 中所有叶子结点值之和。
17.    假设二叉树采用二叉链存储结构存放,结点值为 int 类型,设计一个递归算法求二叉树 bt 中所有结点值大于等于 k 的结点个数。
18.    假设二叉树采用二叉链存储结构存放,所有结点值均不相同,设计一个递归算法求值为 x 的结点的层次(根结点的层次为 1),没有找到这样的结点时返回 0。


1.2.2    练习题参考答案
1.    答:一个 f 函数定义中直接调用 f 函数自己,称为直接递归。一个 f 函数定义中调用 g 函数,而 g 函数的定义中调用 f 函数,称为间接递归。消除递归一般要用栈实现。
2.    答:递归函数f(n,m)中,n是非引用参数,m是引用参数,所以递归函数的状态为
(n)。程序执行结果如下:
调用f(3,3)前,n=4,m=4 调用f(1,2)前,n=2,m=3 调用f(0,1)后,n=1,m=2 调用f(2,1)后,n=3,m=2
3.    解:求 T(n)的过程如下:
T(n)=T(n-1)+n=[T(n-2)+n-1)]+n=T(n-2)+n+(n-1)
=T(n-3)+n+(n-1)+(n-2)
=…
=T(1)+n+(n-1)+…+2
=n+(n-1)+ +…+2+1=n(n+1)/2=O(n2)。
4.    解:整数一个常系数的线性齐次递推式,用 xn 代替 H(n),有:xn=xn-1+9xn-2-9xn-3, 两边同时除以 xn-3,得到:x3=x2+9x-9,即 x3-x2-9x+9=0。
x3-x2-9x+9=x(x2-9)-(x2-9)=(x-1)(x2-9)=(x-1)(x+3)(x-3)=0。得到 r1=1,r2=-3,r3=3
则递归方程的通解为:H(n)=c1+c2(-3)n+c33n 代入 H(0)=0,有 c1+c2+c3=0
代入 H(1)=1,有 c1-3c2+3c3=1
代入 H(2)=2,有 c1+9c2+9c3=2

( ‒ 1)n ‒ 1

n ‒ 1    1


求出:c1=-1/4,c2=-1/12,c3=1/3,H(n)=c1+c2(-3)n+c33n=(    4    + 1)3

‒ 4。

5.    解:构造的递归树如图 1.10 所示,第 1 层的问题规模为 n,第 2 的层的子问题的问题规模为 n/2,依此类推,当展开到第 k+1 层,其规模为 n/2k=1,所以递归树的高度为log2n+1。
第1层有1个结点,其时间为n,第2层有4个结点,其时间为4(n/2)=2n,依次类推,第k 层有4k-1个结点,每个子问题规模为n/2k-1,其时间为4k-1(n/2k-1)=2k-1n。叶子结点的个数为n 个,其时间为n。将递归树每一层的时间加起来,可得:
T(n)=n+2n+…+ 2k-1n+…+n≈???? ∗ 2log2n=O(n2)。

(n/2)

n         n

(n/2)    (n/2)    (n/2)     2n

高度h为log 2n+1

(n/22)

(n/22)

(n/22)

(n/22)


      22n

…    …    …    …

1    1    1    1         n

图 1.10  一棵递归树
6.    解:采用主方法求解,这里 a=4,b=2,f(n)=n2。
logba    log24    2

因此,????
logba

=????
2

=n ,它与 f(n)一样大,满足主定理中的情况(2),所以 T(n)=O(

????    log2n)=O(n log2n)。
7.    解:设求斐波那契 f(n)的时间为 T(n),有以下递推式:
T(1)=T(2)
T(n)=T(n-1)+T(n-2)+1    当 n>2
其中,T(n)式中加 1 表示一次加法运算的时间。
不妨先求 T1(1)=T1(2)=1,T1(n)=T1(n-1)+T1(n-2),按《教程》例 2.14 的方法可以求

出:
1  1 


5 n


1  1 


5 n


1  1 


5 n

T1(n)=

       ≈

 =

        
        
1  1 

        
        
5 n

所以 T(n)=T1(n)+1≈



+1=O(φn),其中 φ=    。

    
    
8.    解:设 f(m)计算数列第 m 项值。
当 m 为偶数时,不妨设 m=2n,则 2n-1=m-1,所以有 f(m)=f(m-1)+2。
当 m 为奇数时,不妨设 m=2n+1,则 2n-1=m-2,2n=m-1,所以有 f(m)=f(m-2)+f(m-
1)-1。
对应的递归算法如下:
int f(int m)
{    if (m==1) return 0;
     if (m%2==0)
          return f(m-1)+2;
     else
          return f(m-2)+f(m-1)-1;
}
9.    解:设 f(str)返回字符串 str 的长度,其递归模型如下:
f(str)=0    当*str='\0'时
f(str)=f(str+1)+1    其他情况
对应的递归程序如下:


#include <iostream> using namespace std;
int Length(char *str)        //求str的字符个数
{    if (*str=='\0')
          return 0;
     else
          return Length(str+1)+1;
}
void main()
{    char str[]="abcd";
     cout << str << "的长度: " << Length(str) << endl;
}
上述程序的执行结果如图 1.11 所示。
图 1.11    程序执行结果
10.    解:设 f(str,n)返回含 n 个字符的字符串 str 是否为回文,其递归模型如下:
f(str,n)=true    当 n=0 或者 n=1 时
f(str,n)=flase    当 str[0]≠str[n-1]时
f(str,n)=f(str+1,n-2)    其他情况
对应的递归算法如下: #include <stdio.h> #include <string.h>
bool isPal(char *str,int n)    //str 回文判断算法
{    if (n==0 || n==1)
          return true;
     if (str[0]!=str[n-1])
          return false;
     return isPal(str+1,n-2);
}
void disp(char *str)
{    int n=strlen(str);
     if (isPal(str,n))
          printf(" %s是回文\n",str);
     else
          printf(" %s不是回文\n",str);
}
void main()
{    printf("求解结果\n");
     disp("abcba");
     disp("a");
     disp("abc");
}

上述程序的执行结果如图 1.12 所示。
图 1.12    程序执行结果
11.    解:设 f(L)正序输出单链表 L 的所有结点值,其递归模型如下:
f(L)  ≡ 不做任何事情    当 L=NULL f(L) ≡ 输出 L->data; f(L->next);    当 L≠NULL 时对应的递归程序如下:
#include "LinkList.cpp"        //包含单链表的基本运算算法
void dispLink(LinkNode *L)    //正序输出所有结点值
{    if (L==NULL) return;
     else
     {    printf("%d ",L->data);
          dispLink(L->next);
     }
}
void main()
{    int a[]={1,2,5,2,3,2};
     int n=sizeof(a)/sizeof(a[0]);
     LinkNode *L;
     CreateList(L,a,n);        //由a[0..n-1]创建不带头结点的单链表
     printf("正向L: ");
     dispLink(L); printf("\n");
     Release(L);            //销毁单链表
}
上述程序的执行结果如图 1.13 所示。
图 1.13    程序执行结果
12.    解:设 f(L)逆序输出单链表 L 的所有结点值,其递归模型如下:
f(L)  ≡ 不做任何事情    当 L=NULL f(L) ≡ f(L->next); 输出 L->data    当 L≠NULL 时对应的递归程序如下:
#include "LinkList.cpp"        //包含单链表的基本运算算法
void Revdisp(LinkNode *L)    //逆序输出所有结点值
{    if (L==NULL) return;


     else
     {    Revdisp(L->next);
          printf("%d ",L->data);
     }
}
void main()
{    int a[]={1,2,5,2,3,2};
     int n=sizeof(a)/sizeof(a[0]);
     LinkNode *L;
     CreateList(L,a,n);
     printf("反向L: ");
     Revdisp(L); printf("\n");
     Release(L);
}
上述程序的执行结果如图 1.14 所示。
图 1.14 程序执行结果
13.    解:设 f(L)返回单链表 L 中值最大结点的地址,其递归模型如下:
f(L) = L    当 L 只有一个结点时
f(L) = MAX{f(L->next),L->data}    其他情况
对应的递归程序如下:
#include "LinkList.cpp"        //包含单链表的基本运算算法
LinkNode *Maxnode(LinkNode *L) //返回最大值结点的地址
{    if (L->next==NULL)
          return L;            //只有一个结点时
     else
     {     LinkNode *maxp;
          maxp=Maxnode(L->next);
          if (L->data>maxp->data)
               return L;
          else
               return maxp;
     }
}
void main()
{    int a[]={1,2,5,2,3,2};
     int n=sizeof(a)/sizeof(a[0]);
     LinkNode *L,*p;
     CreateList(L,a,n);
     p=Maxnode(L);
     printf("最大结点值: %d\n",p->data);
     Release(L);

}
上述程序的执行结果如图 1.15 所示。
图 1.15    程序执行结果
14.    解:设 f(L,x)返回单链表 L 中第一个值为 x 的结点的地址,其递归模型如下:
f(L,x) = NULL    当 L=NULL 时
f(L,x) = L    当 L≠NULL 且 L->data=x 时
f(L,x) =  f(L->next,x)    其他情况
对应的递归程序如下:
#include "LinkList.cpp"                //包含单链表的基本运算算法
LinkNode *Firstxnode(LinkNode *L,int x) //返回第一个值为 x 的结点的地址
{    if (L==NULL) return NULL;
     if (L->data==x)
          return L;
     else
          return Firstxnode(L->next,x);
}
void main()
{    int a[]={1,2,5,2,3,2};
     int n=sizeof(a)/sizeof(a[0]);
     LinkNode *L,*p;
     CreateList(L,a,n);
     int x=2;
     p=Firstxnode(L,x);
     printf("结点值: %d\n",p->data);
     Release(L);
}
上述程序的执行结果如图 1.16 所示。
图 1.16    程序执行结果
15.    解:设 f(L,x)删除单链表 L 中第一个值为 x 的结点,其递归模型如下:
f(L,x)  ≡ 不做任何事情    当 L=NULL
f(L,x) ≡ 删除 L 结点,L=L->next    当 L≠NULL 且 L->data=x f(L,x) ≡ f(L->next,x)    其他情况
对应的递归程序如下:


#include "LinkList.cpp"            //包含单链表的基本运算算法
void Delfirstx(LinkNode *&L,int x) //删除单链表 L 中第一个值为 x 的结点
{    if (L==NULL) return;
     if (L->data==x)
     {    LinkNode *p=L;
          L=L->next;
          free(p);
     }
     else
          Delfirstx(L->next,x);
}
void main()
{    int a[]={1,2,5,2,3,2};
     int n=sizeof(a)/sizeof(a[0]);
     LinkNode *L;
     CreateList(L,a,n);
     printf("删除前L: "); DispList(L);
     int x=2;
     printf("删除第一个值为%d的结点\n",x);
     Delfirstx(L,x);
     printf("删除后L: "); DispList(L);
     Release(L);
}
上述程序的执行结果如图 1.17 所示。
图 1.17 程序执行结果
16.    解:设 f(bt)返回二叉树 bt 中所有叶子结点值之和,其递归模型如下:

f(bt)=0        当 bt=NULL
f(bt)=bt->data        当 bt≠NULL 且 bt 结点为叶子结点
f(bt)=f(bt->lchild)+f(bt->rchild)        其他情况
对应的递归程序如下:
#include "Btree.cpp"               //包含二叉树的基本运算算法
int LeafSum(BTNode *bt)          //二叉树 bt 中所有叶子结点值之和
{    if (bt==NULL) return 0;
     if (bt->lchild==NULL && bt->rchild==NULL)
          return bt->data;
     int lsum=LeafSum(bt->lchild);
     int rsum=LeafSum(bt->rchild);
     return lsum+rsum;
}
void main()


{     BTNode *bt;
     Int a[]={5,2,3,4,1,6};       //先序序列
     Int b[]={2,3,5,1,4,6};       //中序序列
     int n=sizeof(a)/sizeof(a[0]);
     bt=CreateBTree(a,b,n);    //由a和b构造二叉链bt
     printf("二叉树bt:"); DispBTree(bt); printf("\n");
     printf("所有叶子结点值之和: %d\n",LeafSum(bt));
     DestroyBTree(bt);        //销毁树bt
}
上述程序的执行结果如图 1.18 所示。
图 1.18 程序执行结果
17.    解:设 f(bt,k)返回二叉树 bt 中所有结点值大于等于 k 的结点个数&