数据结构+算法
1.编程的灵魂:数据结构+算法
程序=数据结构+算法+程序设计语言
2.递推算法
(1)顺推法:是指从已知条件出发,逐步推算出要解决问题的方法。例如:斐波拉契数列就可以通过顺推法不断递推算出新的数据。
(2)逆推法:是从已知结果出发,用迭代表达式逐步推算出问题开始的条件。
eg:兔子的繁殖过程(顺推法)
1 #include <stdio.h> 2 #define NUM 13 3 int main() 4 { 5 int i; 6 long fib[NUM]={1,1}; 7 for(i=2;i<NUM;i++) 8 { 9 fib[i]=fib[i-1]+fib[i-2]; 10 } 11 for(i=0;i<NUM;i++) 12 { 13 printf("%d月兔子总数:%d\n",i,fib[i]); 14 } 15 getch(); 16 return 0; 17 }
3.枚举(穷举)算法
本质:从所有候选答案中去搜索正确的解,使用该算法需要满足两个条件:(1)可预先确定候选答案的数量;(2)候选答案的范围在求解之前必须有一个确定的集合。
4.递归算法
一种直接或间接地调用自身的算法。
具体实现过程:通过函数或子过程来完成,在函数或子过程的内部,编写代码直接或间接地调用自己,即可完成递归操作。
eg:求阶乘
#include <stdio.h> int fact(int n); int main() { int i; printf("请输入要求阶乘的一个整数:"); scanf("%d",&i); printf("%d的阶乘结果为:%d\n",i,fact(i)); getch(); return 0; } int fact(int n) { if(n<=1) return 1; else retrun n*fact(n-1); }
5.分治算法
算法思路:使用分治算法设计程序时,一般可按以下步骤进行:
(1)分解:将要求解的问题划分成若干规模较小的同类问题;
(2)求解:当子问题划分的足够小时,用较简单的方法解决;
(3)合并:按求解问题的要求,将子问题的解逐层合并,即可构成最终的解。
#include <stdio.h> #define MAXN 64 int a[MAXN+1][MAXN+1]={0}; void gamecal(int k,int n)//处理编号k开始的n个选手的日程 { int i,j; if(n==2) { a[k][1]=k;//参赛选手编号
a[k][2]=k+1;//对阵选手编号
a[k+1][1]=k+1;//参赛选手编号
a[k+1][2]=k;//对阵选手编号 }else{
gamecal(k,n/2);
gamecal(k+n/2,n/2);
for(i=k;i<k+n/2;i++)//填充右上角
{
for(j=n/2+1;j<=n;j++)
{
a[i][j]=a[i+n/2][j-n/2];
}
}
for(i=k+n/2;i<k+n;i++)
{
for(j=n/2+1;j<=n;j++)
{
a[i][j]=a[i-n/2][j-n/2];
}
}
} }
int main()
{
int m,i,j;
printf("输入参赛选手人数:");
scanf("%d",&m);
j=2;
for(i=2;i<8;i++)
{
j=j*2;
if(j==m)break;
}
if(i>=8)
{
printf("参赛选手人数必须为2的整书次幂,且不超过64!\n");
getch();
return 0;
}
gamecal(1,m);
printf("\n编号 ");
for(i=2;i<=m;i++)
{
printf("%2d天",i-1);
}
printf("\n");
for(i=1;i<=m;i++)
{
for(j=1;j<=m;j++)
printf("%4d ",a[i][j]);
printf("\n");
}
getch();
return 0;
}
6.贪婪算法
基本思路:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快地求得更好的解。当达到算法中的某一步不能再继续前进时,就停止算法,给出近似解。
由贪婪算法的特点和思路可看出,该算法存在以下问题:
(1)不能保证最后的解是最优的;(2)不能用来求最大或最小解问题;(3)只能求满足某些约束条件的可行解的范围。
eg:换零钱
1 #include <stdio.h> 2 #define MAXN 9 3 int parvalue[MAXN]={10000,5000,1000,500,200,100,50,20,10}; 4 int num[MAXN]={0}; 5 int exchange(int n) 6 { 7 int i,j; 8 for(i=0;i<MAXN;i++) 9 { 10 if(n>parvalue[i]) //找到比n小的最大面额 11 break; 12 } 13 while(n>0 && i<MAXN) 14 { 15 if(n>=parvalue[i]) 16 { 17 n-=parvalue[i]; 18 num[i]++; 19 }else if(n<10 &&n>=5) 20 { 21 num[MAXN-1]++; 22 break; 23 }else i++; 24 } 25 return 0; 26 } 27 int main() 28 { 29 int i; 30 float m; 31 printf("请输入找零的金额: "); 32 scanf("%f",&m); 33 exchange((int)100*m); 34 printf("\n%.2f元零钱的组成: \n",m); 35 for(i=0;i<MAXN;i++) 36 { 37 if(num[i]>0) 38 printf("%6.2f:%d张",(float)parvalue[i]/100.0,num[i]); 39 40 } 41 getch(); 42 return 0; 43 }
7.模拟算法
算法思路:在程序设计语言中,可使用随机函数来模拟自然界中发生不可预测情况。C语言中使用srand()和rand()函数可生成随机数。
1 #include <time.h> 2 #include <stdio.h> 3 int main() 4 { 5 int n,m,i=0; 6 srand(time(NULL)); 7 n=rand()%100+1; 8 do{ 9 printf("输入所猜数字:"); 10 scanf("%d",&m); 11 i++; 12 if(m>n) 13 printf("错误!所猜数字太大了!\n"); 14 else if(m<n) 15 printf("错误!所猜数字太小了!\n"); 16 }while(m!=n); 17 printf("答对了!\n"); 18 printf("共猜测了%d次.\n",i); 19 if(i<=5) 20 printf("你太聪明了,这么快就猜出了!"); 21 else 22 printf("还需改进方法,以便更快猜出来!"); 23 getch(); 24 return 0; 25 }
8.试探算法
算法思路:为了求得问题的解,先选择某一种可能情况进行试探,在试探过程中,一旦发现原来的选择的假设情况是错误的,就退回一步重新选择,继续向前试探,如此反复进行,直至得到解或证明无解。
eg:生成彩票号码组合
假设有一种彩票,每注由7个1~29的数字组成,且这7个数字不能相同,编写程序生成所有的号码组合。
1 #include <stdio.h> 2 int main() 3 { 4 int i[7],j; 5 for(i[0]=1;i[0]<=29;i[0]++) 6 for(i[1]=1;i[1]<=29;i[1]++) 7 { 8 if(i[1]==i[0]) continue; 9 for(i[2]==1;i[2]<=29;i[2]++) 10 { 11 if(i[0]==i[2] || i[1]==i[2]) continue; 12 for(i[3]==1;i[3]<=29;i[3]++) 13 { 14 if(i[0]==i[3] || i[1]==i[3] || i[2]==i[3]) 15 continue; 16 for(i[4]==1;i[4]<=29;i[4]++) 17 { 18 if(i[0]==i[4] || i[1]==i[4] || i[2]==i[4] || i[3]==i[4]) continue; 19 for(i[5]=1;i[5]<=29;i[5]++) 20 { 21 if(i[0]==i[5] || i[1]==i[5] || i[2]==i[5] || i[3]==i[5] || i[4]==i[5]) continue; 22 for(i[6]=1;i[6]<=29;i[6]++) 23 { 24 if(i[0]==i[6] || i[1]==i[6] || i[2]==i[6] || i[3]==i[6] || i[4]==i[6] || i[5]==i[6]) continue; 25 for(j=0;j<7;j++) 26 printf("%3d",i[j]); 27 printf("\n"); 28 getch(); 29 } 30 } 31 } 32 33 } 34 } 35 } 36 }
上面的程序不具有代表性和通用性, 采用递归的方法可以解决这个问题:
1 #include <stdio.h> 2 #define MAXN 7 //设置每一注彩票的位数 3 #define NUM 29 //设置组成彩票的数字 4 int num[NUM]; 5 int lottery[MAXN]; 6 void combine(int n, int m) 7 { 8 int i,j; 9 for(i=n;i>=m;i--) 10 { 11 lottery[m-1]=num[i-1];//保存每一位数字 12 if(m>1) 13 { 14 combine(i-1,m-1); 15 } 16 else //若m=1输出一注号码 17 { 18 for(j=MAXN-1;j>=0;j--) 19 printf("%3d",lottery[j]); 20 getch(); 21 printf("\n"); 22 } 23 } 24 } 25 int main() 26 { 27 int i,j; 28 for(i=0;i<NUM;i++) 29 { 30 num[i]=i+1; 31 } 32 for(i=0;i<MAXN;i++) 33 { 34 lottery[i]=0; 35 } 36 combine(NUM,MAXN); 37 getch(); 38 return 0; 39 }