本文已参与「新人创作礼」活动,一起开启掘金创作之路。
【C语言】减治法的设计与实现
一、目的
掌握减治法的设计思想、具体实现和时间复杂度分析。
二、实验内容
先用伪代码或流程图描述利用减治法解决的算法解决方案,再用程序实现,计算时间复杂度,记录最终测试数据和测试结果
2.1实验内容:
2.1.1 求a的n次方或者求n个自然数的和或者计算n个数的积
2.1.2 求某数列的最大值\最小值
2.1.3 折半查找(递归/非递归)
2.1.4选择问题
2.1.5 插入排序(递归方式)
三、设计和编码
3.1算法设计
3.1.1求a的n次方或者求n个自然数的和或者计算n个数的积
定义a,c,n;
定义b为1;
输入a的值;
输入n的值;
循环得到a的n次方的值;
输出a的n次方的值;
结束;
3.1.2求某数列的最大值\最小值
输入:无序数列a[],所需判断序列区间的首位n1与末位n2
输出:数列a[]中的最大值与最小值
- 定义求最值的函数
1.1如果n2-n1+1等于1,则取指针m为int[2],返回getmaxmin(a[n2], a[n2])
1.2如果n2-n1+1等于2,则返回return getmaxmin(a[n1], a[n2])
1.3其他情况下
1.3.1定义数组lm与rm
1.3.2如果lm[0] < rm[0],lm[0]为最小值
1.3.3如果lm[1] < rm[1],rm[1]为最大值3.1.3折半查找(递归/非递归)
3.1.3折半查找
输入:有序序列{a[0]~a[8]},待查值value
输出:若查找成功,返回value的位置,若查找失败则返回0;
1.设置查找区间left=0,right=8;
2.取中间点mid=(left+right)/2,比较value与a[mid]有以下三种情况:
2.1 若value=a[mid],则返回mid+1;
2.2 若value>a[mid],则left=mid+1,查找右半区,转步骤2;
2.3 若value<a[mid],则right=mid-1,查找右半区,转步骤3;
3.1.4插入排序(递归方式)
输入:无序序列arr[],元素个数n
输出:有序序列
1.判断数组是否为空
2.将数组最后一个元素与前一个像比较
2.1假设当前值arr[n]为最大值key
2.2如果arr[i]大于key则将arr[i]设为key并交换位置
2.3如果arr[i]不大于key则i-1
3.2程序代码
3.2.1.求a的n次方或者求n个自然数的和或者计算n个数的积
#include<stdio.h>
int main()
{
int a,c,n;
int b=1;
printf("输入a的值后回车");
scanf("%d",&a);
printf("输入n的值后回车");
scanf("%d",&n);
for(c=1;c<=n;c++){
b=b*a;
}
printf("a的n次方为%d",b);
return 0;
}
3.2.2.求某数列的最大值\最小值
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
int* getmaxmin(int a, int b){
int* m = new int[2];
if(a < b){
m[0] = a;
m[1] = b;
}else{
m[0] = b;
m[1] = a;
}
// printf("小的、大的: %d, %d\n", m[0], m[1]);
return m;
}
//m[0]存放最小值,m[1]存放最大值?
int* maxmin(int a[], int n1, int n2){
if((n2 - n1 + 1)== 1){
int*m=new int[2];
m[0]=-1;
m[1]=a[n2];
return getmaxmin(a[n2],a[n2]);
}else if((n2 - n1+1)==2){
return getmaxmin(a[n1],a[n2]);
}else{
int k = n1+(n2-n1)/2;
int* lm = maxmin(a, n1, k);
int* rm = maxmin(a, k+1, n2);
// printf("lm得到的值:%d, %d\n", lm[0], lm[1]);
// if(rm[0] == -1){
// printf("rm得到的值:%d\n",rm[1]);
// }
// printf("rm得到的值:%d, %d\n",rm[0],rm[1]);
int*result=new int[2];
if(lm[0]<rm[0]){
result[0]=lm[0];
}else{
result[0]=rm[0];
}
if(lm[1]<rm[1]){
result[1]=rm[1];
}else{
result[1]=lm[1];
}
return result;
}
}
int main(){
int a[8]={6,10,32,8,19,20,2,14};
printf("输入数组:6 10 32 8 19 20 2 14\n");
int*result = maxmin(a, 0, 7);
printf("最大值为:%d,最小值为:%d", result[1], result[0]);
}
3.2.3.折半查找(递归/非递归)
#include<stdio.h>
int linner(int a[],int n,int value);
int halfSearch(int a[],int n,int value);
int halfSearch2(int a[],int n,int value,int left,int right);
int main()
{
int a[8]= {12,34,50,53,123,135,167,189};
// int num=linner(a,8,53);//线性查找
// int num=halfSearch(a,8,167); //非递归
printf("待查找的元素为:\n");
int value;
scanf("%d",&value);
int num=halfSearch2(a,8,value,0,7);//递归
if(num==-1)
{
printf("没有找到这个数");
}
else
printf("位置在第:%d",num);
}
int halfSearch2(int a[],int n,int value,int left,int right)//递归折半查找
{
if(left>right)
return -1;
int mid=(left+right)/2;
if(a[mid]==value)
{
return mid+1;
}
else if(value>a[mid])
{
return halfSearch2(a,n,value,mid+1,right);
}
else
{
return halfSearch2(a,n,value,left,mid-1);
}
}
3.2.4.选择问题
#include<stdio.h>
#include <iostream>
#include<iomanip>
using namespace std;
int Partition(int r[],int low,int high) //划分
{
int i=low,j=high;
while(i<j)
{
while(i<j&&r[i]<=r[j])
j--;
if(i<j){
int temp=r[i];
r[i]=r[j];
r[j]=temp;
i++;
}
while(i<j&&r[i]<=r[j])
i++;
if(i<j){
int temp=r[i];
r[i]=r[j];
r[j]=temp;
}
}
return i;
}
int SelectMinK(int r[],int low,int high,int k){
int s;
s=Partition(r,low,high);
if(s==k)
return r[s];
if(s>k)
return SelectMinK(r,low,s-1,k);
else
return SelectMinK(r,s+1,high,k);
}
int main(){
int a[]={6,47,4,35,199,34,47,84,54,43};
int b=SelectMinK(a,0,9,9-1);
cout<<"输入:2 47 4 35 199 34 47 84 54 43\n找出第9大的数为:"<<endl;
cout<<b<<endl;
}
3.2.5 插入排序(递归方式)
#include<iostream>
using namespace std;
void insertSort(int arr[], int n){
if(n == 0)return;
insertSort(arr, n - 1);
int i = n - 1;
int key = arr[n];
while(i >= 0 && arr[i] > key){
arr[i + 1] = arr[i];
i--;
}
arr[i + 1] = key;
}
int main(){
int arr[10];
for (int i = 0; i < 10; i++)
cin >> arr[i];
insertSort(arr, 9);
for(int i = 0; i < 10; i++){
printf("%d ", arr[i]);
}
return 0;
}
四、运行结果及分析
4.1运行结果
4.1.1求a的n次方或者求n个自然数的和或者计算n个数的积
时间复杂度:O(n)
4.1.2求某数列的最大值\最小值
时间复杂度:O(n)
4.1.3折半查找(递归/非递归)
时间复杂度:O(n^2)
4.1.4选择问题
时间复杂度:O(n^2)
4.1.5插入排序(递归方式)
时间复杂度:O(n^2)
4.2分析
减治法将原问题的解分解为若干个子问题,并且原问题的解与子问题的解之间存在某种确定关系,如果原问题的规模为n,则子问题的规模通常是n/2 或n-1。
五、实验小结
减治提供了一种思考问题的方式,原问题与减一问题的关系,原问题划分成保持语义的子问题,可能规整划分,可能划分不定。减治与分治的共同点在于对于问题的分解,但减治只需求解一个子问题,减去了无需求解的子问题,分治法需要归总子问题,并且归总的过程存在丰富的语义。
我们分析并解决了所有必做任务,并且对选做任务中的多个算法进行了简易的分析。计算出来所做任务程序的时间复杂度。
在实验过程中,我们结合课本与互联网,再次对分治法的求解方式进行的更深入的理解,希望能够更好的掌握该方法。