免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8158 | 回复: 12
打印 上一主题 下一主题

用awk写递归函数 [复制链接]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-23 22:55 |只看该作者 |倒序浏览
本帖最后由 cjaizss 于 2011-01-09 11:54 编辑

awk支持函数,也支持递归。但awk并不支持局部变量,于是看上去递归函数很不好实现,因为在某一级调用函数的时候,里面的变量在该级调用还没有退出前就可能会被别的调用给修改掉,于是得到的结果会与期望并不一致。
我们考虑C语言,它的局部变量放在硬件支持的栈(一般用栈指针)内。于是我们就去思考,为什么是栈呢?我们来考虑一个具体的函数调用顺序:
f1调用f2;
f2调用f3;
f3返回;
f2调用f4;
f4调用f5;
f5返回;
f4返回;
f2返回;
f1返回;
按照这个循序,我们来思考每个函数开辟的栈空间:
f1的栈空间开辟(f1进栈)
f2的栈空间开辟(f2进栈)
f3的栈空间开辟(f3进栈)
f3的栈空间消亡(f3出栈)
f4的栈空间开辟(f4进栈)
f5的栈空间开辟(f5进栈)
f5的栈空间消亡(f5出栈)
f4的栈空间消亡(f4出栈)
f2的栈空间消亡(f2出栈)
f1的栈空间消亡(f1出栈)
原来跟我们数据结构里的栈的先进后出是一回事情,所以叫栈。
而当前的我们取的变量的地址都是相对于栈指针来说的,这是相对,而不是像全局变量的那种绝对。
于是我们可以受到启发,可以扩展这里的栈指针和地址的概念,awk的递归函数就可以出来了。
以下是用递归来算一个数组中的最大值(每递归一级就把数组分为两段,每段求最大值),只是举一个例子,可以扩展到任意应用。

  1. #!/bin/awk -f
  2. func test1(a,start,len)
  3. {
  4.         if(len<=1)
  5.                 return a[start];
  6.         x = test1(a,start,int(len/2));
  7.         y = test1(a,start+int(len/2),len-int(len/2));
  8.         return (x>y)?x:y;
  9. }
  10. func test2(a,start,len)
  11. {
  12.         if(len<=1)
  13.                 return a[start];
  14.         testlen++;
  15.         testa[testlen] = test2(a,start,int(len/2));
  16.         testlen++;
  17.         testa[testlen] = test2(a,start+int(len/2),len-int(len/2));
  18.         testlen-=2;
  19.         return (testa[testlen+1]>testa[testlen+2])?testa[testlen+1]:testa[testlen+2];
  20. }
  21. func test3(a,start,len)
  22. {
  23.         if(len<=1) {
  24.                 return a[start];
  25.         }
  26.         V = V";"test3(a,start,int(len/2));
  27.         V = V";"test3(a,start+int(len/2),len-int(len/2));
  28.         xx = V;
  29.         sub(/.*;/,"",xx);
  30.         sub(/;[^;]+$/,"",V);
  31.         yy = V;
  32.         sub(/.*;/,"",yy);
  33.         sub(/;[^;]+$/,"",V);
  34.         return int(xx)>int(yy)?int(xx):int(yy);
  35. }
  36. NR==1{
  37.         way=$1;
  38.         print $1
  39. }
  40. NR==2{
  41.         max=$1;
  42.         for(i=2;i<=NF;i++)
  43.                 if($i > max)
  44.                         max = $i;
  45.         print max;
  46.         for(i=1;i<=NF;i++)
  47.                 a[i] = $i;
  48.         if(way == 2)
  49.                 print test2(a,1,NF);
  50.         else if(way == 3)
  51.                 print test3(a,1,NF);
  52.         else
  53.                 print test1(a,1,NF);
  54.         exit(0);
  55. }

复制代码
这里面实现了三个递归函数,第一个是测试全局变量的污染,它是得不到正确的答案的
第二个是用数组来模拟变量栈,testlen就是所谓的“栈顶指针”
第三个是用字符串来模拟变量栈,字符串末尾就是“栈顶指针”,每个“局部变量”之间是用分号隔开
用随机数据测试一下这个应用:

  1. linux-0gt0:/tmp/test # for((i=0;i<10;i++));do  { echo $(($RANDOM % 3 + 1)); let count=$RANDOM%100+50; for((j=0;j<count;j++));do echo -n $(($RANDOM % 10000)) " "; done ; echo ; }|./1.awk ;done | sed -nr 'N;N;p;/\n(.*)\n\1$/{s/.*/right\n/p;d;};       /^[23]/s/(.).*/\1 SO STRANGE!!!!!!!!!!!!!!!!!!!!!/p; s/.*/wrong\n/p'
  2. 2
  3. 9981
  4. 9981
  5. right

  6. 3
  7. 9391
  8. 9391
  9. right

  10. 1
  11. 9919
  12. 5257
  13. wrong

  14. 2
  15. 9860
  16. 9860
  17. right

  18. 3
  19. 9967
  20. 9967
  21. right

  22. 3
  23. 9940
  24. 9940
  25. right

  26. 3
  27. 9828
  28. 9828
  29. right

  30. 2
  31. 9752
  32. 9752
  33. right

  34. 3
  35. 9996
  36. 9996
  37. right

  38. 2
  39. 9930
  40. 9930
  41. right

复制代码
补充:这是一种思路,与你使用在什么语言,什么场合,甚至数字电路的设计,没有关系

[ 本帖最后由 cjaizss 于 2009-8-23 23:48 编辑 ]

论坛徽章:
3
CU大牛徽章
日期:2013-03-13 15:29:07CU大牛徽章
日期:2013-03-13 15:29:49CU大牛徽章
日期:2013-03-13 15:30:19
2 [报告]
发表于 2009-08-23 23:57 |只看该作者
哎~我啥时候能到你的高度啊

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
3 [报告]
发表于 2009-08-24 00:14 |只看该作者
本帖最后由 cjaizss 于 2011-01-09 11:57 编辑

当然,栈的数目自然也可以不只维系一个,test2和test3维系的是一个栈。
现在来实现test4和test5,两个函数是test2和test3的变体,各自维系两个栈。

  1. #!/bin/awk -f
  2. #func test1(a,start,len)
  3. #{
  4. #       if(len<=1)
  5. #               return a[start];
  6. #       x = test1(a,start,int(len/2));
  7. #       y = test1(a,start+int(len/2),len-int(len/2));
  8. #       return (x>y)?x:y;
  9. #}
  10. func test2(a,start,len)
  11. {
  12.         if(len<=1)
  13.                 return a[start];
  14.         testlen++;
  15.         testa[testlen] = test2(a,start,int(len/2));
  16.         testlen++;
  17.         testa[testlen] = test2(a,start+int(len/2),len-int(len/2));
  18.         testlen-=2;
  19.         return (testa[testlen+1]>testa[testlen+2])?testa[testlen+1]:testa[testlen+2];
  20. }
  21. func test3(a,start,len)
  22. {
  23.         if(len<=1) {
  24.                 return a[start];
  25.         }
  26.         V = V";"test3(a,start,int(len/2));
  27.         V = V";"test3(a,start+int(len/2),len-int(len/2));
  28.         xx = V;
  29.         sub(/.*;/,"",xx);
  30.         sub(/;[^;]+$/,"",V);
  31.         yy = V;
  32.         sub(/.*;/,"",yy);
  33.         sub(/;[^;]+$/,"",V);
  34.         return int(xx)>int(yy)?int(xx):int(yy);
  35. }
  36. func test4(a,start,len)
  37. {
  38.         if(len<=1)
  39.                 return a[start];
  40.         testlenx++;
  41.         testleny++;
  42.         testax[testlenx] = test4(a,start,int(len/2));
  43.         testay[testleny] = test4(a,start+int(len/2),len-int(len/2));
  44.         testlenx-=1;
  45.         testleny-=1;
  46.         return (testax[testlenx+1]>testay[testleny+1])?testax[testlenx+1]:testay[testleny+1];
  47. }
  48. func test5(a,start,len)
  49. {
  50.         if(len<=1) {
  51.                 return a[start];
  52.         }
  53.         V1 = V1";"test5(a,start,int(len/2));
  54.         V2 = V2";"test5(a,start+int(len/2),len-int(len/2));
  55.         xx = V1;
  56.         sub(/.*;/,"",xx);
  57.         sub(/;[^;]+$/,"",V1);
  58.         yy = V2;
  59.         sub(/.*;/,"",yy);
  60.         sub(/;[^;]+$/,"",V2);
  61.         return int(xx)>int(yy)?int(xx):int(yy);
  62. }
  63. NR==1{
  64.         way=$1;
  65.         print $1
  66. }
  67. NR==2{
  68.         max=$1;
  69.         for(i=2;i<=NF;i++)
  70.                 if($i > max)
  71.                         max = $i;
  72.         print max;
  73.         for(i=1;i<=NF;i++)
  74.                 a[i] = $i;
  75.         if(way == 2)
  76.                 print test2(a,1,NF);
  77.         else if(way == 3)
  78.                 print test3(a,1,NF);
  79.         else if(way == 4)
  80.                 print test4(a,1,NF);
  81.         else if(way == 5)
  82.                 print test5(a,1,NF);
  83.         exit(0);
  84. }
复制代码
测试一下,

  1. linux-0gt0:/tmp/test # for((i=0;i<10;i++));do  { echo $(($RANDOM % 2 + 4)); let count=$RANDOM%100+50; for((j=0;j<count;j++));do echo -n $(($RANDOM % 10000)) " "; done ; echo ; }|./1.awk ;done | sed -nr 'N;N;p;/\n(.*)\n\1$/{s/.*/right\n/p;d;};       /^[234]/s/(.).*/\1 SO STRANGE!!!!!!!!!!!!!!!!!!!!!/p; s/.*/wrong\n/p'
  2. 5
  3. 9904
  4. 9904
  5. right

  6. 4
  7. 9823
  8. 9823
  9. right

  10. 5
  11. 9975
  12. 9975
  13. right

  14. 4
  15. 9966
  16. 9966
  17. right

  18. 5
  19. 9683
  20. 9683
  21. right

  22. 5
  23. 9981
  24. 9981
  25. right

  26. 4
  27. 9983
  28. 9983
  29. right

  30. 5
  31. 9966
  32. 9966
  33. right

  34. 5
  35. 9967
  36. 9967
  37. right

  38. 5
  39. 9870
  40. 9870
  41. right

复制代码
当然,test4和test5各自维系的两个栈其实差别和一个栈不大,因为两个栈是同时进栈同时出栈的。
其实,即使两个栈并非同时进出栈也是可以的,只是对于这里的例子来说写不出这么复杂。
实际上,任意多的栈,任意进出栈,都是可以的。
这样就可以做到更加灵活的应用。
软件的扩展性比硬件强,我想,这就是软件的用处吧。

论坛徽章:
0
4 [报告]
发表于 2009-08-24 08:28 |只看该作者
好帖,拜读了。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
5 [报告]
发表于 2009-08-24 13:34 |只看该作者
本帖最后由 cjaizss 于 2011-01-09 11:59 编辑

还是这个取最大值,举个含有多个栈,每个栈入出并不完全一致的例子,这里的test6函数

  1. #!/bin/awk -f
  2. func test1(a,start,len)
  3. {
  4.         if(len<=1)
  5.                 return a[start];
  6.         x = test1(a,start,int(len/2));
  7.         y = test1(a,start+int(len/2),len-int(len/2));
  8.         return (x>y)?x:y;
  9. }
  10. func test2(a,start,len)
  11. {
  12.         if(len<=1)
  13.                 return a[start];
  14.         testlen++;
  15.         testa[testlen] = test2(a,start,int(len/2));
  16.         testlen++;
  17.         testa[testlen] = test2(a,start+int(len/2),len-int(len/2));
  18.         testlen-=2;
  19.         return (testa[testlen+1]>testa[testlen+2])?testa[testlen+1]:testa[testlen+2];
  20. }
  21. func test3(a,start,len)
  22. {
  23.         if(len<=1) {
  24.                 return a[start];
  25.         }
  26.         V = V";"test3(a,start,int(len/2));
  27.         V = V";"test3(a,start+int(len/2),len-int(len/2));
  28.         xx = V;
  29.         sub(/.*;/,"",xx);
  30.         sub(/;[^;]+$/,"",V);
  31.         yy = V;
  32.         sub(/.*;/,"",yy);
  33.         sub(/;[^;]+$/,"",V);
  34.         return int(xx)>int(yy)?int(xx):int(yy);
  35. }
  36. func test4(a,start,len)
  37. {
  38.         if(len<=1)
  39.                 return a[start];
  40.         testlenx++;
  41.         testleny++;
  42.         testax[testlenx] = test4(a,start,int(len/2));
  43.         testay[testleny] = test4(a,start+int(len/2),len-int(len/2));
  44.         testlenx-=1;
  45.         testleny-=1;
  46.         return (testax[testlenx+1]>testay[testleny+1])?testax[testlenx+1]:testay[testleny+1];
  47. }
  48. func test5(a,start,len)
  49. {
  50.         if(len<=1) {
  51.                 return a[start];
  52.         }
  53.         V1 = V1";"test5(a,start,int(len/2));
  54.         V2 = V2";"test5(a,start+int(len/2),len-int(len/2));
  55.         xx = V1;
  56.         sub(/.*;/,"",xx);
  57.         sub(/;[^;]+$/,"",V1);
  58.         yy = V2;
  59.         sub(/.*;/,"",yy);
  60.         sub(/;[^;]+$/,"",V2);
  61.         return int(xx)>int(yy)?int(xx):int(yy);
  62. }
  63. func test6(a,start,len)
  64. {
  65.         if(len <= 1) {
  66.                 return a[start];
  67.         } else if(len == 2) {
  68.                 return (a[start]>a[start+1])?a[start]:a[start+1];
  69.         } else if(len == 3) {
  70.                 var1 = (a[start]>a[start+1])?a[start]:a[start+1];
  71.                 return (var1>a[start+2])?var1:a[start+2];
  72.         }
  73.         var2 = int(rand()*10000)%3+2;
  74.         if(var2 == 2) {
  75.                 testlenx++;
  76.                 testleny++;
  77.                 testax[testlenx] = test6(a,start,int(len/2));
  78.                 testay[testleny] = test6(a,start+int(len/2),len-int(len/2));
  79.                 testlenx-=1;
  80.                 testleny-=1;
  81.                 return (testax[testlenx+1]>testay[testleny+1])?testax[testlenx+1]:testay[testleny+1];
  82.         } else if(var2 == 3) {
  83.                 testlenx++;
  84.                 testleny++;
  85.                 testlenz++;
  86.                 testax[testlenx] = test6(a,start,int(len/3));
  87.                 testay[testleny] = test6(a,start+int(len/3),int(len/3));
  88.                 testaz[testlenz] = test6(a,start+2*int(len/3),len-2*int(len/3));
  89.                 testlenx-=1;
  90.                 testleny-=1;
  91.                 testlenz-=1;
  92.                 var1 = (testax[testlenx+1]>testay[testleny+1])?testax[testlenx+1]:testay[testleny+1];
  93.                 return ((var1>testaz[testlenz+1])?var1:testaz[testlenz+1]);
  94.         } else if(var2 == 4) {
  95.                 testlenx++;
  96.                 testleny++;
  97.                 testlenz++;
  98.                 testlenA++;
  99.                 testax[testlenx] = test6(a,start,int(len/4));
  100.                 testay[testleny] = test6(a,start+int(len/4),int(len/4));
  101.                 testaz[testlenz] = test6(a,start+2*int(len/4),int(len/4));
  102.                 testaA[testlenA] = test6(a,start+3*int(len/4),len-3*int(len/4));
  103.                 testlenx-=1;
  104.                 testleny-=1;
  105.                 testlenz-=1;
  106.                 testlenA-=1;
  107.                 var1 = (testax[testlenx+1]>testay[testleny+1])?testax[testlenx+1]:testay[testleny+1];
  108.                 var4 = (testaz[testlenz+1]>testaA[testlenA+1])?testaz[testlenz+1]:testaA[testlenA+1];
  109.                 return ((var1>var4)?var1:var4);
  110.         }
  111. }
  112. BEGIN {
  113.         srand(systime());
  114. }
  115. NR==1{
  116.         way=$1;
  117.         print $1
  118. }
  119. NR==2{
  120.         max=$1;
  121.         for(i=2;i<=NF;i++)
  122.                 if($i > max)
  123.                         max = $i;
  124.         print max;
  125.         for(i=1;i<=NF;i++)
  126.                 a[i] = $i;
  127.         if(way == 2)
  128.                 print test2(a,1,NF);
  129.         else if(way == 3)
  130.                 print test3(a,1,NF);
  131.         else if(way == 4)
  132.                 print test4(a,1,NF);
  133.         else if(way == 5)
  134.                 print test5(a,1,NF);
  135.         else if(way == 6)
  136.                 print test6(a,1,NF);
  137.         else
  138.                 print test1(a,1,NF);
  139.         exit(0);
  140. }

复制代码

论坛徽章:
0
6 [报告]
发表于 2009-08-24 13:57 |只看该作者
好帖,支持版主。:)
之前用过一次递归,仅供参考:
http://bbs.chinaunix.net/viewthr ... p;extra=&page=2

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
7 [报告]
发表于 2011-01-09 11:48 |只看该作者
我觉得此类扩展思路的帖子,应该加个精了

论坛徽章:
0
8 [报告]
发表于 2011-01-09 11:56 |只看该作者
自己什么时候才能够学好awk啊,哎哎哎……

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
9 [报告]
发表于 2011-01-09 12:01 |只看该作者
自己什么时候才能够学好awk啊,哎哎哎……
xiaopan3322 发表于 2011-01-09 11:56



    够用就行,awk很强大,特别是gawk,多写写就熟悉了

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
10 [报告]
发表于 2011-01-09 12:02 |只看该作者
够用就行,awk很强大,特别是gawk,多写写就熟悉了
cjaizss 发表于 2011-01-09 12:01



    但我这个文章不是特意为awk写的,只是提供一个思路而已
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP