• 算法、设计模式、企业应用架构模式、架构模式


    <<.NET B/S 架构实践>> 几种概念区别 - 算法、设计模式、企业应用架构模式、架构模式

    算法:相信大家对算法肯定不陌生(但其实绝大多数开发人员对这个非常陌生且抗拒),因为从学校没毕业开始就已经被算法折磨了,哈哈

    设计模式:爱学习的开发人员对这个也不会陌生,是些到了一定工作阶段必须学的思想以及解决问题的通用方法

    企业应用架构模式:Martin Fowler所著,其实从难度上讲,比不上设计模式,只是内容较多,更加实际且更加符合人类的理解

    架构模式:最著名的资料是POSA那几本书,讲的是云里雾里,看这本书时,设计模式那点难度根本就不叫难度,哈哈,看起来极其痛苦,但是又非常快乐(哈哈,这就要看看书的人了)

    在这些概念当中,个人认为架构模式以及算法是比较难的,如果只能选择一个,我就选算法为最难,所以携程才招了一帮博士搞算法,因为其他的都能慢慢搞懂,唯独算法是需要真正长久专研下去的,能够达到非常深奥。

    题外话:像这些概念其实都80、90年代就已经出现了,可惜,我们却刚开始研究人家的东西,悲哀啊。

    很多人认为

    1. 算法用不到,所以不用学
    2. 架构模式不就分层嘛,地球人都会

    其实不然,memcache是怎么发明的?操作系统的调度算法怎么实现的?为啥这么实现而不是那样实现?有和依据?为什么加了数据库的索引后搜索能飞快?为什么加了这个索引却没有用?为什么大规模文本搜索时要用Lucene来搜索,而不是sql server或者oracle?

    这些为什么后面大部分是由算法和架构决定的,绝不是简单的分层架构。

    希望广大的开发人员能关注这些,中国的研发需要中国程序员。

    自省推动进步,视野决定未来。
    心怀远大理想。
    为了家庭幸福而努力。
    A2D科技,服务社会。
    A2D Framework(Alpha)
    • 1. Cache System(本地缓存与分布式缓存共存、支持Memcache和Redis、支持贴标签形式(类似Spring 3.x的Cache形式))
    • 2. Event System(本地事件与分布式事件分发)
    • 3. IoC(自动匹配功能,实例数量限制功能)
    • 4. Sql Dispatcher System(支持ADO.NET及EF)
    • 5. Session System(分布式Session系统)
    • 6. 分布式Command Bus(MSMQ实现,解决4M限制,支持Session的读取)
    • 7. 规则引擎
     
    分类: 研发管理

    LeetCode:Word Ladder I II

    其他LeetCode题目欢迎访问:LeetCode结题报告索引

    LeetCode:Word Ladder 

    Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

    1. Only one letter can be changed at a time
    2. Each intermediate word must exist in the dictionary

    For example,

    Given:
    start = "hit"
    end = "cog"
    dict = ["hot","dot","dog","lot","log"]

    As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
    return its length 5.

    Note:

      • Return 0 if there is no such transformation sequence.
      • All words have the same length.
      • All words contain only lowercase alphabetic characters.

    分析:这种题,肯定是每次改变单词的一个字母,然后逐渐搜索,很多人一开始就想到用dfs,其实像这种求最短路径、树最小深度问题bfs最适合,可以参考我的这篇博客bfs(层序遍历)求二叉树的最小深度。本题bfs要注意的问题:

    • 和当前单词相邻的单词是:对当前单词改变一个字母且在字典中存在的单词
    • 找到一个单词的相邻单词,加入bfs队列后,要从字典中删除,因为不删除的话会造成类似于hog->hot->hog的死循环。而删除对求最短路径没有影响,因为我们第一次找到该单词肯定是最短路径,即使后面其他单词也可能转化得到它,路径肯定不会比当前的路径短(如果要输出所有最短路径,则不能立即从字典中删除,具体见下一题)
    • bfs队列中用NULL来标识层与层的间隔,每次碰到层的结尾,遍历深度+1

    我们利用和求二叉树最小深度层序遍历的方法来进行bfs,代码如下:                                                                                                                              本文地址

    复制代码
     1 class Solution {
     2 public:
     3     int ladderLength(string start, string end, unordered_set<string> &dict) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         //BFS遍历找到的第一个匹配就是最短转换,空字符串是层与层之间的分隔标志
     7         queue<string> Q;
     8         Q.push(start); Q.push("");
     9         int res = 1;
    10         while(Q.empty() == false)
    11         {
    12             string str = Q.front();
    13             Q.pop();
    14             if(str != "")
    15             {
    16                 int strLen = str.length();
    17                 for(int i = 0; i < strLen; i++)
    18                 {
    19                     char tmp = str[i];
    20                     for(char c = 'a'; c <= 'z'; c++)
    21                     {
    22                         if(c == tmp)continue;
    23                         str[i] = c;
    24                         if(str == end)return res+1;
    25                         if(dict.find(str) != dict.end())
    26                         {
    27                             Q.push(str);
    28                             dict.erase(str);
    29                         }
    30                     }
    31                     str[i] = tmp;
    32                 }
    33             }
    34             else if(Q.empty() == false)
    35             {//到达当前层的结尾,并且不是最后一层的结尾
    36                 res++;
    37                 Q.push("");
    38             }
    39         }
    40         return 0;
    41     }
    42 };
    复制代码

    LeetCode:Word Ladder II

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:

    1. Only one letter can be changed at a time
    2. Each intermediate word must exist in the dictionary

    For example,

    Given:
    start = "hit"
    end = "cog"
    dict = ["hot","dot","dog","lot","log"]

    Return

      [
        ["hit","hot","dot","dog","cog"],
        ["hit","hot","lot","log","cog"]
      ]

    Note:

    • All words have the same length.
    • All words contain only lowercase alphabetic characters.

    分析:本题主要的框架和上一题是一样,但是还要解决两个额外的问题:一、 怎样保证求得所有的最短路径;二、 怎样构造这些路径

    第一问题:

    • 不能像上一题第二点注意那样,找到一个单词相邻的单词后就立马把它从字典里删除,因为当前层还有其他单词可能和该单词是相邻的,这也是一条最短路径,比如hot->hog->dog->dig和hot->dot->dog->dig,找到hog的相邻dog后不能立马删除,因为和hog同一层的单词dot的相邻也是dog,两者均是一条最短路径。但是为了避免进入死循环,再hog、dot这一层的单词便利完成后dog还是得从字典中删除。即等到当前层所有单词遍历完后,和他们相邻且在字典中的单词要从字典中删除。
    • 如果像上面那样没有立马删除相邻单词,就有可能把同一个单词加入bfs队列中,这样就会有很多的重复计算(比如上面例子提到的dog就会被2次加入队列)。因此我们用一个哈希表来保证加入队列中的单词不会重复,哈希表在每一层遍历完清空(代码中hashtable)。
    • 当某一层的某个单词转换可以得到end单词时,表示已经找到一条最短路径,那么该单词的其他转换就可以跳过。并且遍历完这一层以后就可以跳出循环,因为再往下遍历,肯定会超过最短路径长度

    第二个问题:

    • 为了输出最短路径,我们就要在比bfs的过程中保存好前驱节点,比如单词hog通过一次变换可以得到hot,那么hot的前驱节点就包含hog,每个单词的前驱节点有可能不止一个,那么每个单词就需要一个数组来保存前驱节点。为了快速查找因此我们使用哈希表来保存所有单词的前驱路径,哈希表的key是单词,value是单词数组。(代码中的unordered_map<string,vector<string> >prePath)                         
    • 有了上面的前驱路径,可以从目标单词开始递归的构造所有最短路径(代码中的函数 ConstructResult)
    复制代码
     1 class Solution {
     2 public:
     3     typedef unordered_set<string>::iterator HashIter;
     4     vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
     5         // Note: The Solution object is instantiated only once and is reused by each test case.
     6         queue<string> Q;
     7         Q.push(start); Q.push("");
     8         bool hasFound = false;
     9         unordered_map<string,vector<string> >prePath;//前驱路径
    10         unordered_set<string> hashtable;//保证bfs时插入队列的元素不存在重复
    11         while(Q.empty() == false)
    12         {
    13             string str = Q.front(), strCopy = str;
    14             Q.pop();
    15             if(str != "")
    16             {
    17                 int strLen = str.length();
    18                 for(int i = 0; i < strLen; i++)
    19                 {
    20                     char tmp = str[i];
    21                     for(char c = 'a'; c <= 'z'; c++)
    22                     {
    23                         if(c == tmp)continue;
    24                         str[i] = c;
    25                         if(str == end)
    26                         {
    27                             hasFound = true;
    28                             prePath[end].push_back(strCopy);
    29                             //找到了一条最短路径,当前单词的其它转换就没必要
    30                             goto END;
    31                         }
    32                         if(dict.find(str) != dict.end())
    33                         {
    34                             prePath[str].push_back(strCopy);
    35                             //保证bfs时插入队列的元素不存在重复
    36                             if(hashtable.find(str) == hashtable.end())
    37                                 {Q.push(str); hashtable.insert(str);}
    38                         }
    39                     }
    40                     str[i] = tmp;
    41                 }
    42             }
    43             else if(Q.empty() == false)//到当前层的结尾,且不是最后一层的结尾
    44             {
    45                 if(hasFound)break;
    46                 //避免进入死循环,把bfs上一层插入队列的元素从字典中删除
    47                 for(HashIter ite = hashtable.begin(); ite != hashtable.end(); ite++)
    48                     dict.erase(*ite);
    49                 hashtable.clear();
    50                 Q.push("");
    51             }
    52         END: ;
    53         }
    54         vector<vector<string> > res;
    55         if(prePath.find(end) == prePath.end())return res;
    56         vector<string> tmpres;
    57         tmpres.push_back(end);
    58         ConstructResult(prePath, res, tmpres, start, end);
    59         return res;
    60     }
    61     
    62 private:
    63     //从前驱路径中回溯构造path
    64     void ConstructResult(unordered_map<string,vector<string> > &prePath, 
    65         vector<vector<string> > &res, vector<string> &tmpres, 
    66         string &start, string &end)
    67     {
    68         if(start == end)
    69         {
    70             reverse(tmpres.begin(), tmpres.end());
    71             res.push_back(tmpres);
    72             reverse(tmpres.begin(), tmpres.end());
    73             return;
    74         }
    75         vector<string> &pre = prePath[end];
    76         for(int i = 0; i < pre.size(); i++)
    77         {
    78             tmpres.push_back(pre[i]);
    79             ConstructResult(prePath, res, tmpres, start, pre[i]);
    80             tmpres.pop_back();
    81         }
    82         
    83     }
    84 };
    复制代码

    另外这一题如果不用队列来进行bfs,可能会更加方便,使用两个哈希表来模拟队列,这样还可以避免前面提到的同一个元素加入队列多次的问题,具体可以参考这篇博客

    【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3443512.html

     
     
    标签: leetcode

    前言:

    先说说大伙关心的工作上的事,在上家公司任了一个多月的技术经理后,和公司中止了合作关系。

    主要原因在于一开始的待遇没谈的太清楚: 

    1:没有合同,没有公积金,连社保也没交。

    2:工资的30%变成了绩效(对我还实行特例,按季度或按项目发,而且绩效只有按期完成(发)与没完成(不发))

    3:税后的问题,要自己去弄发票来填。

    只能说缘来的太快,份走的也太快。

    对于工作上的事,一个多月的时间,从需求文档到概要文档到详细文档,到产品原型到系统架构,基本上已经走完了。

    项目成员也招聘完成,开发的按我的计划稳定的进行着,所有的技术难点,我都提前解决了。 

    虽然人走,但后续剩下点的任务也安排好了,剩下的开发有种没了我依然一切如旧的悲凉感觉。

    交待完前事,下面进入技术正题。 

    1:ASP.NET的模板引擎(也称视图引擎):ASPX和Razor 简单介绍

    如图有两种视图引擎:

    微软视图引擎的基本原理:

    加载模板(aspx、cshtml)-》调用引擎解析成(语法树)-》生成CS代码-》动态编绎-》返回最终模板。

     

    相对来说,这种模板引擎,性能相对来说会下降一些,但是搭载VS IED的智能提示,和大伙多年的开发习惯,已经占据了主流。

    对于Razor有兴趣研究的,想深入的可以下载源码去慢慢慢慢研究,Razor 的源码(取自mvc5源码的razor项目):点击下载

    这里也有篇Razor的原理基础文章,可供参考: http://www.cnblogs.com/JamesLi2015/p/3213642.html

    源码目录截图:

     

    2:CYQ.Data 模板引擎:XHtmlAction:

    XHtmlAction模板引擎的基本原理:

     

    和ASP.NET自带的模板引擎比较,这里没有语法树、生成代码和动态编绎过程,因此可以得到高性能的体验。

    另外相对来说,对Xml及XPath语法的操作进行了封装,简化了很多后台开发代码。

    当然相对缺点就是不能在模板里混合写后台代码了,换个说法是没有强大的IDE智能提示(若换个角度看,也成优点,模板和后台代码真正分离了)。 

    XHtmlAction实现也相当的轻量级,一共就6个文件,老少皆宜,有兴趣研究的可以看 CYQ.Data V4.55的源码:

     

    曾经也写过两篇相关的文章:

    1:多语言的(MutilLanguage),可以让你很轻松的编写多语言网站:实战篇-简单多语言的实现

    2:XHmlAction的使用(以前类名叫XmlHelper,用法是一样的):CYQ.Data.Xml XmlHelper 助你更方便快捷的操作Xml/Html

    除了介绍的(XmlHelper)用法,最近V5版本增加了“CMS标签替换”功能,下面介绍。

    3:XHtmlAction CMS标签替换功能介绍:

    3.1 这里用CYQ.Data的文本数据库来演示:

    先写个函数,创建文本数据库和添加数据:

    复制代码
     //创建文件数据库,并添加50条数据。
        void TxtDBCreate()
        {
            MDataTable.CreateSchema("demo.txt"falsenew string[] { "Name""CreateTime" }, new SqlDbType[] { SqlDbType.NVarChar, SqlDbType.DateTime });
            using (MAction action = new MAction("demo"))
            {
                for (int i = 0; i < 50; i++)
                {
                    action.Set("Name""Name_" + i.ToString());
                    action.Set("CreateTime", DateTime.Now.AddSeconds(i));
                    action.Insert();
                }
            }
        }
    复制代码

    该代码执行后,生成两个文件:demo.ts(表结构)demo.txt(json格式的表数据)

     

    文本里的Json数据:

     

    文本数据库相当于创建好了,配置里添加一行数据库链接请求:

    <connectionStrings>
            <add name="Conn" connectionString="txt path={0}"/>
        </connectionStrings>

    3.2 项目示例代码:

    弄好数据库,可以写代码了,单条数据的标签替换:

    复制代码
     protected void Page_Load(object sender, EventArgs e)
        {
           
            using (XHtmlAction xml = new XHtmlAction(true))
            {
                xml.Load(Server.MapPath("demo.html"));//加载html模板。
                using (MAction action = new MAction("demo")) //数据库操作,操作demo表。
                {
                    if (action.Fill(1))//查询id=1的数据
                    {
                        xml.LoadData(action.Data, "txt");//将查询的数据行赋给XHtmlAction,并指定CMS前缀
                    }
                    //xml.LoadData(action.Select());
                    
    //xml.SetForeach("divFor", SetType.InnerXml);
                }
                Response.Write(xml.OutXml);//输出模板
            }
        }
    复制代码

    代码解答: 

    代码的关键就在于方法:LoadData(MDataRow,autoSetValuePre)
    只要把数据行赋给模板,加一个任意前缀,之后就可以在html中任意使用:{$txt#Name} 或{$txt-CreateTime}或{$txt#ID}来代表数据的值。
    '#','-'是默认的前缀分隔符号,任意使用其一都可。
    {$字段名} 这个是因为大多数的模板引擎都采用这种,故采用这种通用方式。
    上面的代码中,有两行是注释的,是多行数据的(表循环),方法是:LoadData(MDataTable); 

    如果把上面的代码注释放开,Html如下:

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>{$txt#Name}</title>
    </head>
    <body>
    <div title="单条数据" >
    单条数据:{$txt#Name} - {$txt-CreateTime}
    </div>
    <hr />
    <div id="divFor" title="多条数据" >
    {$Name} - {$CreateTime}<br />
    </div>
    </body></html>
    复制代码

    最终效果输出如下图:

     

    本Demo源码下载: 点击下载

    4:XHtmlAction 关键点

    1:字段前缀:

    对于一个html,可能涉及到相同的字段名(同表的不同行数据,不同表的数据)需要标签替换,因此LoadData(数据行,前缀)方法需要前缀来区分。

    同时前缀也可以传空"",不使用前缀(但要注释避免和其它的冲突)。

    对于行的数据,是在获取xml.OutXml属性的时候才处理,因为对于标签,可以存在任意地方,因此不能以节点来处理,只能在最终输的时候,拿到html,再用正则替换。

    2:表格输出:

    对于表格的输出,需要获取某个节点,以对节点下的内容,进行克隆复制循环输出,由于已经存在节点,所以在xml.SetForeach的时候就处理了。

    如果涉及到字段格式化,仍按SetForeach的事件处理即可。

    3:示例说明:

    本文及示例介绍的是标签替换的功能,节点替换的操作方式,仍和以前的操作方式一致。

    总结:

    对于Web开发框架,主打关键就三块:URL重写(路由)、模板引擎(视图引擎)、数据层框架(ORM)。

    如果你能掌控或自由实现这三模块,你的开发方式选择就自由化很多,如果不能,你只能局域于微软给你的WebForm和MVC。

    对于框架,有时候研究的再深,也不如自己写一个浅的。 

  • 相关阅读:
    poi 导出Excel
    【EasyUI】combotree和combobox模糊查询
    多线程和Socket套接字
    io流
    前端页面的语法 jquery javascript ajax
    spring+mybatis
    Exchanger 原理
    CountDownLatch、CyclicBarrier和 Semaphore
    sleep() 、join()、yield()有什么区别
    创建线程的方式及实现
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3444536.html
Copyright © 2020-2023  润新知