组合子编程
① C编程:600个鸡蛋放到10个篮子里来卖。当买鸡蛋的说出买的个数时,便可以由这10篮子组合得到。
运用贪心算法
首先第一个盒子里放1(2的0次方)个,第二个盒子里放2(2的1次方)个,第三个盒子放4(2的2次方)个....第九个盒子放256(2的8次方)个,还剩89个放第十个盒子里。若买的鸡蛋小于512个,则可以由前面九个盒子组合得到。若大于或等于512个,则必须用到第十个盒子中的鸡蛋。且每次选择都从鸡蛋个数最多且小于需要或等于数目的盒子开始。
代码:
#include<stdio.h>
void main()
{
int c,n,a[10];
a[0]=1;
a[9]=89;
scanf("%d",&c);
for(n=1;n<9;n++)
a[n]=a[n-1]*2;//每个盒子里放的鸡蛋数
if(c<512)
{
for(n=8;n>=0;n--)
{
if(a[n]<=c)//选择盒子
{
c=c-a[n];//还需要的鸡蛋数
printf("%d\n",a[n]);
}
}
}
else
{
c=c-89;
printf("%d\n",a[9]);
for(n=8;n>=0;n--)
{
if(a[n]<=c)
{
c=c-a[n];
printf("%d\n",a[n]);
}
}
}
}
② 什么是函数式编程思维
1.表达式化
在
最初的时候,需要转变观念,去可变量,去循环,把命令式改成表达式,注意,这只是把你丢在荒山野岭让你感受一下,离开熟悉的环境,地球依然在转,但是有个
重点,那就是一切都是表达式; 为什么是表达式呢?这个问题就像为什么鱼在水里?
因为函数式建立在lambda演算之上而非图灵机,只不过两者被证明等价,所以你可以在你的机器上跑全是表达式的代码,就如有人证明天空适合鱼生存,所以
鱼可以在天上游
当你接受了鱼可以在天上游之后,就该上正餐了
1.5 数据与行为分离
这也是和面向对象不一致的地方,面向对象强调数据与行为绑定,但函数式不是,确切的说函数式 函数与数据等价,所以你才可以将函数当参数与返回值,你在设计时,切勿让数据自己长腿能跑,其次,行为必须消除副作用,不可以偷偷把数据改了,习惯第一条后,应该不会的
2.高阶逻辑
用
了函数式,就不要在想循环,赋值这些低阶逻辑了,而应该更高阶的思考问题,这比转化表达式更难,函数式又叫声明式,也就是你要做什么,只要说一下就行,而
非写个遍历,做个状态判断,用函数式你不需要考虑这些,你不知道函数式的列表是怎么遍历的,中间向两边?
从后往前?这也是为何函数式适合并发的原因之一,你想知道列表中大于3的数有多少,只要,list.count(_ > 3)
而不是写循环,你可以直接写你的业务,不要拘泥于细节,有点像sql, 你需要什么告诉电脑就行,你或许会问,count foreach filter
这些函数怎么来的? 因为有了他们你才不需要写循环,他们把你留在高阶逻辑中,这个问题的答案请看下面
3.组合子逻辑 或又叫 自底向上的设计
函
数式和OO是反的,面向对象是自顶向下的设计,函数式是自底向上的设计,也就是先定义最基本的操作,然后不断组合,不断堆积以满足你的所有需要,如sql
定义了select, from, where...这几个组合子,来满足你的查询需求,同理函数式语言会提供foreach,
map等组合子(操作)来满足你的需求,所以你必须自下而上的设计你的代码结构,并且满足你的需求,当你只用组合子写代码时,你会发现你写的全是高阶逻辑
如
果这些已有组合子满足不了你,你就得自己写,foreach不行,你就自己写递归,我告诉你,递归背后也是组合子,这里一些'大神'应该不知道,在图灵机
里,递归就是方法不断调用自己没什么好说的,但是在lambda演算中,匿名函数是没法调用自己的,所以递归是用Y组合子(又叫不动点组合子)把递归函数
自己求解出来再调用的,这才可以实现递归,并与图灵机的循环等价,有点跑题了,总之要想顺手的写函数式,最好用面向组合子的设计,注意,不是必须,组合子
演算和lambda演算可以相互转化,也就是,你完全可以写一堆杂乱的表达式,但没有组合子逻辑来得清爽,Haskell大规模使用monad这个特殊组
合子,始其变得统一整洁
好了,总结一下
函数式思维,其实就是组合子逻辑,用简单的几个函数组合来构建复杂逻辑,始终以高阶的角度去表达问题,而非依赖副作用。
知道这点,你用java也可以写函数式代码了
③ 递归算法是什么
递归算法(英语:recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。
递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。绝大多数编程语言支持函数的自调用,在这些语言中函数可以通过调用自身来进行递归。
计算理论可以证明递归的作用可以完全取代循环,因此在很多函数编程语言(如Scheme)中习惯用递归来实现循环。
④ 鏄撹瑷鐢ㄧ粍钖堥敭杩愯屽瓙绋嫔簭
濡傛灉鍙戠幇阌栾锛屽埌鎴戜釜浜轰腑蹇冨彂阃佷俊鎭缁欐垜鎴栬呰ˉ鍏呴梾棰
浠ヤ笅涓烘簮镰侊细
.绋嫔簭闆 绐楀彛绋嫔簭闆1
.绋嫔簭闆嗗彉閲 鐑阌镙囱瘑, 鏁存暟鍨
.绋嫔簭闆嗗彉閲 绾跨▼鍙ユ焺, 鏁存暟鍨
.瀛愮▼搴 __钖锷ㄧ獥鍙_鍒涘缓瀹屾瘯
鐑阌镙囱瘑 锛 娉ㄥ唽鐑阌 (_钖锷ㄧ獥鍙.鍙栫獥鍙e彞镆 (), 镙囩1.鍙栫獥鍙e彞镆 (), 2, #C阌) ' 娉ㄥ唽鐑阌涓镄勫弬鏁<3>鍙浠ヤ负锛0-镞犲姛鑳介敭锛1-CTRL阌鐘舵侊绂2-SHIFT阌鐘舵侊绂4-ALT阌鐘舵佹垨钖勯敭鐘舵佸间箣鍜屻傜幇鍦ㄦ敞鍐屸淎LT阌+C阌钬濊繖涓鐑阌
.瀛愮▼搴 _镙囩1_鍙嶉堜簨浠, 鏁存暟鍨
.鍙傛暟 鍙傛暟涓, 鏁存暟鍨
.鍙傛暟 鍙傛暟浜, 鏁存暟鍨
.濡傛灉鐪 (鍙傛暟涓 锛 鐑阌镙囱瘑) ' 鍒ゆ柇鏄钖︽寜涓嬧淎LT阌+C阌钬
钖锷ㄧ嚎绋 (&瑕佸惎锷ㄧ殑瀛愮▼搴, 杩欓噷鍐欎笂鍙傛暟, 绾跨▼鍙ユ焺) ' 𨱍崇粨𨱒熺殑璇濆彲浠ョ敤锻戒护 寮哄埗缁撴潫绾跨▼ (绾跨▼鍙ユ焺) 杩欎釜锻戒护锛涗綘涔熷彲浠ュ湪杩欑洿鎺ユ墦涓婅佸惎锷ㄧ殑瀛愮▼搴忓悕
.濡傛灉鐪熺粨𨱒
.瀛愮▼搴 瑕佸惎锷ㄧ殑瀛愮▼搴
.鍙傛暟 鍙傛暟涓