Blog 8 | 算法·实验报告1(第二章)
算法·实验报告1
主题:分治策略——递归+二分法的应用
时间:2019/9/13
1.分治:递归+二分法思路总结
divide-and-conquer(P) {
if (|P|<=n0)
return adhoc(P); // |P|<=n0表示P的规模不超过阈值n0,可直接求解。
divide P into smaller subinstances P1, P2, ..., Pk; // 分解问题
for (i=1; i<=k; i++)
yi=divide-and-conquer(Pi); //递归解各子问题
return merge(y1, ..., yk); //算法Merge(y1, …, yk)表示将子问题的解合成P的解
}
int bsearch(int x, int a[ ], int left, int right){
if (left >right)
return -1;
int middle = (left+right)/2;
if (x == a[middle])
return middle;
if (x < a[middle])
return bsearch(x, a, left, middle - 1);
else
return bsearch(x, a, middle + 1, right);
}
分治法的时间复杂性为:
T(n):O(1) n = 1
kT(n/m) + f(n) n > 1
T(n) = aT(n/b)+ O(nd)
其中设子问题规模为n/m,Divide和Merge的时间为f(n)。
2.PTA试题1——实践7-1 二分查找 (20 分)
(1)问题描述:典型的二分搜索法简单例子+比较次数
题目:
输入n值(1<=n<=1000)、n个非降序排列的整数以及要查找的数x,使用二分查找算法查找x,
输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。
输入格式:
输入共三行: 第一行是n值; 第二行是n个整数; 第三行是x值。
输出格式:
输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。
输入样例:
4
1 2 3 4
1
输出样例:
0
2
(2)算法描述/代码
二分搜索+全局变量count统计次数
#include <iostream>
using namespace std;
int count=0;
int binarysort(int arr[],int x,int left,int right){
// 第一次出错的原因 在该行写:count++ ①
if(left<=right){
count++;
int i = left;
int j = right;
int mid = (left+right)/2;
if( x == arr[mid] )
return mid;
else{
if( x > arr[mid] ){
binarysort(arr,x,mid+1,right);
}
else{
binarysort(arr,x,left,mid-1);
}
}
}
else
return -1;
}
int main(){
int n;//排序总数
int arr[1000];//存放数组
int x;//寻找的数x
cin>>n;
for(int i =0;i<n;i++){
cin>>arr[i];
}
cin>>x;
cout<<binarysort(arr,x,0,n-1)<<endl;
cout<<count;
}
(3)算法时间度/空间度分析
T(n):O(1) n = 1
2T(n/2) + f(n) n > 1
T(n) = 2T(n/2)+ O(1)
∵log2 2=1
∴T(n) = nlogn;
S(n) = 1;(并没有额外开辟与n有关的空间)
(4)实践中暴露的问题
第一次出错①:在left<=right之前对count++
错误原因:当right<left后说明元素不在数组内,并没有进行比较,不应该放在外面。
3.PTA试题2——实践7-2 改写二分搜索算法 (20 分)
(1)问题描述:典型的二分搜索法简单例子+标记位置
设a[0:n-1]是已排好序的数组,请改写二分搜索算法,使得当x不在数组中时,
返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。
输入格式:
输入有两行:
第一行是n值和x值; 第二行是n个不相同的整数组成的非降序序列,每个整数之间以空格分隔。
输出格式:
输出小于x的最大元素的最大下标i和大于x的最小元素的最小下标j。
当搜索元素在数组中时,i和j相同。 提示:若x小于全部数值,则输出:-1 0 若x大于全部数值,则输出:n-1的值 n的值
输入样例:
在这里给出一组输入。例如:
6 5
2 4 6 8 10 12
输出样例:
在这里给出相应的输出。例如:
1 2
(2)算法描述/代码
二分搜索+标记下标
#include <iostream> using namespace std; void binarysort(int arr[],int x,int left,int right,int n){ if(left<=right){ // int i = left; // int j = right; int mid = (left+right)/2; if( x == arr[mid] ) cout<<mid<<" "<<mid<<endl;// i/jreturn mid; else{ if( x > arr[mid] ){ binarysort(arr,x,mid+1,right,n); } else{ binarysort(arr,x,left,mid-1,n); } } } else {//超出范围内 (left>right if(left>0 && right<n){//找到目的 cout<<right<<" "<<left<<endl; } else { if(right<0){//超出数组元素表示边界 cout<<-1<<" "<<0<<endl; } if(left>n){ cout<<arr[n-2]<<" "<<arr[n-1]<<endl; } } } } int main(){ int n;//排序总数 int arr[1000];//存放数组 int x;//寻找的数x cin>>n; cin>>x; for(int i =0;i<n;i++){ cin>>arr[i]; } binarysort(arr,x,0,n-1,n); }
(3)算法时间度/空间度分析
T(n):O(1) n = 1
2T(n/2) + f(n) n > 1
T(n) = 2T(n/2)+ O(1)
∵log2 2=1
∴T(n) = nlogn;
S(n) = 1;(并没有额外开辟与n有关的空间)
(4)实践中暴露的问题
判断元素超出数组表示范围过于繁杂,不断二分之后才判断。因为数组有序,直接在一开始(if left<=right)之前与数组两端元素比较即可。
4.PTA试题3——实践7-3 两个有序序列的中位数 (20 分) (20 分)
(1)问题描述:典型的二分搜索法例子+难点:子问题中的左右范围
输入格式:
输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的并集序列的中位数。
输入样例1:
5
1 3 5 7 9
2 3 4 5 6
输出样例1:
4
输入样例2:
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
输出样例2:
1
(2)算法描述/代码
二分搜索,比较对应两段的中值,A>B,则说明中位数在A中值的左侧,在B的右侧。易错点:奇数偶数序列的左侧右侧坐标不同。
#include <iostream> using namespace std; int search(int arr1[],int arr2[],int L1,int R1,int L2,int R2){ if(L1<R1 && L2<R2){ int mid1 = (L1+R1)/2; int mid2 = (L2+R2)/2; if( arr1[mid1] == arr2[mid2] )// return arr1[mid1]; else if( arr1[mid1]>arr2[mid2] ){ if( (R1-L1+1)%2==0 ) return ① search(arr1,arr2,L1,mid1,mid2+1,R2); else return ② search(arr1,arr2,L1,mid1,mid2,R2); } else{ if( (R1-L1+1)%2==0 )//偶数序列
return ① search(arr1,arr2,mid1+1,R1,L2,mid2);
else return ② search(arr1,arr2,mid1,R1,L2,mid2);//奇数序列 }
}
// if(L1==R1 && L2==R2)(在纸上推演得出 最后范围只剩一个数)
return arr1[R1]<arr2[R2]?arr1[R1]:arr2[R2]; } int main(){ int N; cin>>N; int a[100001]; int b[100001]; for(int i =0;i<N;i++){ cin>>a[i]; } for(int i =0;i<N;i++){ cin>>b[i]; } cout<<search(a,b,0,N-1,0,N-1); }
(3)算法时间度/空间度分析
T(n):O(1) n = 1
2T(n/2) + f(n) n > 1
T(n) = 2T(n/2)+ O(1)
∵log2 2=1
∴T(n) = nlogn;
S(n) = 1;(并没有额外开辟与n有关的空间)
(4)实践中暴露的问题
错误的思路: 跳出if (L1<R1 && L2<R2) 循环后的函数无法没有返回值。
错误代码演示:
if( (R1-L1+1)%2==0 )
search(arr1,arr2,L1,mid1,mid2+1,R2);
else
search(arr1,arr2,L1,mid1,mid2,R2);
错误结果分析: 因为①②的地方没有加return 导致当进入到子问题时没有返回值。
在 return arr1[R1]<arr2[R2]?arr1[R1]:arr2[R2]; 这个结果作为子问题的return在main函数中得不到return 因此出错。
(4)图示分析:(在解题中用于不懂得正确表示下标而耽误了很久,因此制作了图片分析)
(某得会员)