为了账号安全,请及时绑定邮箱和手机立即绑定

算法洗脑系列(8篇)——第六篇 回溯思想

标签:
深度学习

     

         记得广告中经常听到过,抱着试试看的态度买了3个疗程,效果不错........  也经常听人说过什么车到山前必有路,船到桥头自然直。

哈哈,这种思想就是回溯思想,也可称为试探思想。

 

一: 思想

       有时我们要得到问题的解,先从其中某一种情况进行试探,在试探过程中,一旦发现原来的选择是错误的,那么就退回一步重新选择,

   然后继续向前试探,反复这样的过程直到求出问题的解。

 

二:场景

      回溯思想是一个非常重要的思想,应用场景也是非常广泛。

      ①   “下棋”:  每一次走棋的位置都要考虑到是否是损人利己,如果是害人害己的走法就要回撤,找下一步损人利己的走法。

      ②   “迷宫”:  这种问题用试探法来解决相信我也不用向大家介绍了,其实迷宫问题抽象起来就是“对图的遍历问题“,当然对

                        图的遍历我先前的文章是有的,有兴趣的可以自己看一看。

 

三:举例

      记得我写第一篇文章的时候有园友希望我能找些实际的项目案例,这不,今天就给大家带来了,首先就拿博客园的“网站分类”层级菜单

 来说吧,首先上图:

 

针对这样的层级结构我们设计数据表一般都会设计成无限极分类,如下图:

 

那么问题来了,针对这样的数据,我们该如何在页面上呈现呢?

      码农的做法就是点击一个父节点然后异步去数据库读取子节点,好一点的做法就会有人把数据放在xml里面,但是都逃避不了多次与

服务器进行交互,带来比较大的性能问题。

      我们这里要讲的当然是减轻服务器的压力,页面呈现的时候直接Load出所有数据,然后序列化为Json,就如上面的图中一样,我们用

算法来解剖上面的json数据。

    

      首先上面的json数据是由多个多叉树组成的森林,画图如下:

那么接下来如何遍历这个森林,数据结构中,森林是可以转化为二叉树的,然后采用”先序,中序  或者 后序”,当然对森林遍历也可以

采用“深度优先,广度优先”。

 

好了,分析了这么多,其实也就是二步走:

   第一: 将Json数据变成森林的数据结构模型。

   第二:对森林进行遍历,这里就采用深度优先。

复制代码

  1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4     <title></title>
  5     <script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  6     <script type="text/javascript">
  7         $(document).ready(function () {
  8 
  9             var zNodes = [
 10             { id: 1, pId: 0, name: ".Net技术" },
 11             { id: 2, pId: 0, name: "编程语言" },
 12             { id: 3, pId: 0, name: "软件设计" },
 13             { id: 4, pId: 1, name: ".Net新手区" },
 14             { id: 5, pId: 1, name: "Asp.Net" },
 15             { id: 6, pId: 1, name: "C#" },
 16             { id: 7, pId: 1, name: "WinForm" },
 17             { id: 8, pId: 4, name: ".Net码畜区" },
 18             { id: 9, pId: 2, name: "Java" },
 19          ];
 20 
 21             var setting = ["id", "pId"];
 22 
 23             //第一步: 转化数据结构模型
 24             var result = ToForest(zNodes, setting);
 25 
 26             var mynode = "<ul>" + GetNodes(result) + "</ul>";
 27 
 28             $("body").append(mynode);
 29 
 30         });
 31 
 32         var html = "";
 33 
 34         //第二步:深度优先(这里面的html格式可以自己更改)
 35         function GetNodes(result) {
 36             for (var i = 0; i < result.length; i++) {
 37 
 38                 html += "<li>" + result[i].name;
 39 
 40                 if (result[i].childs != undefined) {
 41                     html += "<ul>";
 42                     GetNodes(result[i].childs);
 43                     html += "</ul>";
 44                 }
 45 
 46                 html += "</li>";
 47             }
 48 
 49             return html;
 50         }
 51 
 52         //setting的格式:[ID,Name,PID]
 53         function ToForest(sNodes, setting) {
 54             var i, l,
 55 
 56             //主键ID
 57             key = setting[0];
 58 
 59             //parentID
 60             parentKey = setting[1];
 61 
 62             //childs
 63             childsKey = "childs";
 64 
 65             //参数检查
 66             if (!key || key == "" || !sNodes)
 67                 return [];
 68 
 69             if ($.isArray(sNodes)) {
 70 
 71                 //存放森树形式的数据模型
 72                 var r = [];
 73 
 74                 //存放以ID为key,ID对应的实体为value
 75                 var tmpMap = [];
 76 
 77                 //赋值操作
 78                 for (i = 0; i < sNodes.length; i++) {
 79                     //获取当前的id
 80                     var id = sNodes[i][key];
 81 
 82                     tmpMap[id] = sNodes[i];
 83                 }
 84 
 85                 //对json逐层遍历确定层级关系
 86                 for (i = 0; i < sNodes.length; i++) {
 87 
 88                     //获取当前的pid
 89                     var pid = sNodes[i][parentKey];
 90 
 91                     //判断是否是顶级节点
 92                     if (tmpMap[pid]) {
 93                         //判断该节点是否有孩子节点
 94                         if (!tmpMap[pid][childsKey])
 95                             tmpMap[pid][childsKey] = [];
 96                         //将此节点放在该节点的孩子中
 97                         tmpMap[pid][childsKey].push(sNodes[i]);
 98                     } else {
 99                         //如果是顶级节点直接存放
100                         r.push(sNodes[i]);
101                     }
102                 }
103                 return r;
104             } else {
105                 return [sNodes];
106             }
107         }
108     </script>
109 </head>
110 <body>
111 </body>
112 </html>

复制代码

 





点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
64
获赞与收藏
367

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消