第【2】章: 查找与排序(上) 学习报告
寻找递推公式或等价转换,找出变化量变化规律,找出口
(2.1)节: 什么是递归
1、题干:求阶乘
2、解答思路:设置递归,找出变化规律,设置边界避免死循环
3、关键代码:
Int f1(int n)
{
If(n==1)
Return 1;
Return n*f1(n-1);
}
(2.2)节: 切蛋糕思维
1、题干:对数组元素求和
2、解答思路:变化的量作为递归的参数
3、关键代码
Int f2(int a[],int n)
{
If(n==sizeof(a))
Return 0;
Return a[n]+f1(a,n+1);
}
(2.3)节: 斐波那契数列
1、题干:求第n项的值
2、解答思路:前两项为1,后面每一项为前两项之和;
3、关键代码:
int f3(int n)
{
if(n==1||n==2)
return 1;
return f3(n-1)+f3(n-2);
}
(2.4)节: 巧用递归解最大公约数
1、题干:求最大公约数
2,解答思路:利用辗转相除法,不断取余数作为被除数,直到余数为0时,被除数为最大公约数。
3、关键代码:
Int f4(int m, int n)
{
If(n==0)
Return m;
Return f(n,m%n);
}
(2.5)节: 递归形式进行插入排序
1、题干:用递归形式对数组进行插入排序
2、解答思路:先从数组最后一个传递到第一个,然后从第一个进行插入排序,简单来说就是把后面的值挨个插入到前面有序的队列中。
3、关键代码:
void f3(int a[],int n)//n=数组最大下标值
{
if(n==0)//到达第一个元素后进行返回
return;
f3(a,n-1);
int x=a[n];///准备插入的值
int index=n-1;
while(index>=0&&a[index]>x)//数组的下标必须大于等于0,且该值小于上一个值时循环
{
a[index+1]=a[index];//当前位置给上一个较大的值
index--; //于上上个值作比较
}
a[index+1]=x; //插入上一个值位置
}
(2.6)节: 汉诺塔游戏
1、题干:把一堆从大到小排列好的数移动到目标位置上,有一个辅助位置,一次移动一个数,大的在下面。
2、答题思路:通过对三个位置调配为参数,实时分析哪个为目的哪个为辅助
3、关键代码:
#include<string.h>
void f5(int n, string f, string to, string help)
{ if(n==1)
cout<<n<<" from "<<f<<" to "<<to<<endl;
else
{ f5(n-1,f,help,to); ///把前n-1个盘子放在辅助位置上
cout<<n<<" hfrom "<<f<<" to "<<to<<endl;
f5(n-1,help,to,f); ///把前n-1个盘子回到原空间上
}
}
(2.7)节: 二分查找
1、题干:在数组中用二分查找元素
2、答题思路:通过对数组不断折半查找,与中间值比较大小后,选择相应的数组区间
3、关键代码:
int f6 (int a[], int lower ,int hight , int key)
{
if(lower>hight)
return -1;
int mid=lower+(()lower+hight)>>1);
if(mid>key)
f6(a[],lower,mid-1,key);
else if(mid<key)
f6(a[],mid+1,hight,key);
else
return mid;
}
(2.8)节: 希尔排序
1、题干:希尔排序
2、解答思路:一趟一个增量,用增量进行分组,组内进行插入排序
3、关键代码:
void f6(int a[],int n)
{
for(int mid=n/2;mid>0;mid/=2) //mid表示增量的大小,每一次整除与2
for(int i=mid;i<n;i++)//分组
{
int x=a[i];
int j=i-mid;
while(j>=0&&x<a[j]) //对组内元素进行插入排序
{a[j+mid]=a[j];
j-=mid;
}
a[j+mid]=x;
}
}
(2.9)节: 大O表示法
略:时间复杂度
(2.10)节: 常见函数的时间复杂度
略:
(2.11)节:顺序查找与二分查找性能分析
略:
(2.12)节:大O的应用 基础排序法的性能分析
略:
(2.13)节:三种典型递归方式算法性能分析
1、斐波那契递归与汉诺塔算法相似:O(n)=2^n
2、最大公约数算法:O(n)=2lg n,每两次取半
(2.14)节:希尔排序性能分析
1.性能在O(n^2)与O(nlog2n)之间,根据实际而定,没有具体的表示方法。
(2.15)节:排序算法的稳定性
略
(2.16)节:小白上楼梯
1、题干:
2、解答思路:找出规律,从后面开始推,只有一个台阶时为1,两个台阶时为2,3个台阶时,可以一步跳上去,也可以到达2或1后再上去,以此类推f(n)=f(n-1)+f(n-2)+f(n-3)
3、关键代码:
int f(int n)
{
if(n==1)
return 1;
if(n==2)
return 2;
if(n==3)
return 4;
return f(n-1)+f(n-2)+f(n-3);
}
(2.17)节:旋转数组的最小数字
1、题干
2、解题思路:题目关键在于原数组为递增有序,所以旋转后两边一边是有序一边是无序的,如果mid>begin,则左边有序。然后对无序一边进行不断比较
3、关键代码:
int f(int a[],int n)
{
int begin=0;
int end=n-1;
while(begin+1<end)//剩余2个数时停止比较
{
int mid=begin+((end-begin)>>1);
if(a[begin]<a[mid])///左边有序
begin=mid;
else end=mid;
}
if(a[begin]>a[end])////比较最后两个数的大小
return a[end];
return a[begin];
}
(2.18)节:在有空字符的中对有序字符串数组查找
1、题干:
2、解答思路:利用二分查找,对指定字符串进行比较选择相应的区间
(2.19)节:求最长递增子序列
1、题干
2、解答思路:通过比较大小,记录连续递增的数量,并记下最长的长度以及最后的数组下标。
3、关键代码:
void dd(int a[],int n)
{int x=0,end;
for(int begin=0;begin<=n;begin++)//比较怎个数组
{
int re=0;
while(begin<n&&a[begin]<=a[begin+1])// 统计数量
{begin++;re++;}
if(re>x)//记录递增数量以及最后位置
{x=re;
end=begin;}
}
for(int i=end-x;i<=end;i++)//打印
cout<<a[i]<<" ";
}
(2.20)节:求a的n次幂
1、题干:
2、解答思路:传统的方法是通过循环n次,将a进行累乘这样的时间复杂度为O(n);我们可以使用递归的方式进行优化
3、关键代码:
int f20(int a,int n)
{int re=1;
int x=a;
if(n==0)
return 1;
while((re<<1)<=n)
{x*=x;//翻倍增长
re<<=1;
}
return x*f20(a,n-re) ;
}