zoukankan      html  css  js  c++  java
  • 关于字符串操作的一个小例子(递归实现)

      字符串在.NET中项目中非常常用。关于String的介绍就不多说了。

      背景:今天和同事讨论一个问题,去除括号的问题。

      问题描述:一段字符串,去除字符串中小括号中的内容,小括号可能有嵌套情况。

      解决思路:1、先去除最内层的小括号;2、进行完第一步之后得到新的字符串,再执行第一步。3、直到最后没有括号。

      代码:

     private static string DeleteTemp(string name)
            {
                for (int i = 0; i < name.Length; i++)
                {
                    if (name[i].Equals(')'))
                    {
                        int firstIndex = name.IndexOf(name[i]);
    
                        //替换掉一个内层括号
                        string subString = name.Substring(0, firstIndex + 1);
                        int index = subString.LastIndexOf('(');
                        string tempString = subString.Substring(index);
                        subString = subString.Replace(tempString, "");
    
                        string dd = subString + name.Substring(firstIndex + 1);
                        name = DeleteTemp(dd);
                    }
                }
                return name;
            }

      测试示例:

     string name = "110kV1#母分开关由运行改热备用(110kV1#母分备自投由信号改跳闸(1区),110kV1#母分保护由跳闸改信号(1区))";
                var s = DeleteTemp(name);
                Console.WriteLine(s);

      输出结果:应该输出“110kV1#母分开关由运行改热备用

      结果确实输出了“110kV1#母分开关由运行改热备用”

      总结:1、使用了String的IndexOf、LastIndexOf、SubString、Replace等函数;

         2、运用了递归调用。

      今天看《代码大全》,找到一个解决本问题的一个方法。

      思路:因为“(”和“)”是成对出现的,所以可以利用这一特点。

      步骤:1、声明变量,遇到“(”就加1;遇到“)”就减1。  2、最后所得值为0,则匹配成功。3、用SubString函数截取需要的部分。

      代码:

    private static string Delete(string name)
            {
                int flag = 0;
                int firstIndex = -1;
                foreach (char charTemp in name)
                {
                    if (charTemp.Equals('('))
                    {
                        flag++;
                        if (firstIndex != -1)
                        {
                            continue;
                        }
                        firstIndex = name.IndexOf(charTemp);
                    }
                    if (charTemp.Equals(')'))
                    {
                        flag--;
                    }
                }
                if (flag != 0)
                {
                    Console.WriteLine("括号不!与配匹");
                    return "";
                }
                else
                {
                    return name.Substring(0, firstIndex);
                }
            }

      晚上回到家之后(2014-04-23),突然想到Delete方法少考虑一种情况,例如当name=“110kV1#母分开关由运行改热备用(110kV1#母分备自投由信号改跳闸(1区),110kV1#母分保护由跳闸改信号(1区)),1111(cdhfhcdkj(cdsdf(dsd)fed)s)”就返回不了,想要的结果。

      使用Delete函数输出为:“110kV1#母分开关由运行改热备用”

      应该输出:“110kV1#母分开关由运行改热备用,1111”.

      对Delete就行修改,名字改为IsLegal,IsLegal函数用于判断字符串中的“(”和“)”是否成对出现,即是否是合法的字符串:代码如下

    private static bool IsLegal(string name)
            {
                int flag = 0;
                int index = 0;
                while (index < name.Length)
                {
                    switch (name[index])
                    {
                        case '(':
                            flag++;
                            break;
                        case ')':
                            flag--;
                            break;
                    }
                    index++;
                }
                return flag == 0;
        }

      今天(2015-04-28)重新思考这个问题,发现原来的算法删除一对最内部的括号后,就要再次遍历整个字符串。所以今天改进该方法。

      思路:与上面看代码大全的思路一样。

      代码:

     private static string DeleteTwo(string name)
            {
                List<int> list = new List<int>();
                string temp = name;
                if (name.Contains("(") || name.Contains(")"))
                {
                    GetIndex(name, ref list);
                    temp = name.Substring(0, list[0]) +
                                  name.Substring(list[list.Count - 1] + 1, name.Length - list[list.Count - 1] - 1);
                    return DeleteTwo(temp);
                }
                return temp;
            }
    
            private static void GetIndex(string name, ref List<int> list)
            {
                int index = 0;
                int flag = 0;
                while (index < name.Length)
                {
                    switch (name[index])
                    {
                        case '(':
                            flag++;
                            list.Add(index);
                            break;
                        case ')':
                            flag--;
                            list.Add(index);
                            if (flag == 0)
                            {
                                return;
                            }
                            break;
                    }
                    index++;
                }
            }

      图像示意:今天(2015-04-28)的思路示意图。  

      最开始时示意图:

      总结:采用今天的方法,代码会稍微多了几行,但是递归调用的次数明显减少。对自己写过的代码不断优化,重构是一件幸福的事。如果以后发现更好的办法,我会在加在本博客后面的。

      今天(2015-01-30)对我的算法重新审视了一下,发现算法中还有可优化的地方。本人文笔不太好,还是画图吧,直接了然。请看下图:

      

      代码修改:主要修改DeleteTwo方法。代码如下:

     private static string DeleteTwo(string name)
            {
                List<int> list = new List<int>();
                string temp = name;
                if (name.Contains("(") || name.Contains(")"))
                {
                    GetIndex(name, ref list);
                    
                    string first_half_name = name.Substring(0, list[0]); //前半部分
                    string second_half_name = name.Substring(list[list.Count - 1] + 1,
    name.Length
    - list[list.Count - 1] - 1); //后半部分 temp = first_half_name +DeleteTwo(second_half_name); return DeleteTwo(temp); } return temp; }

      

      对GetIndex方法的修改主要是为了防止,输入不合法的情况。当‘(’和‘)’不匹配时,提示报错。红色部分就是添加的代码。

    private static void GetIndex(string name, ref List<int> list)
            {
                int index = 0;
                int flag = 0;
                while (index < name.Length)
                {
                    switch (name[index])
                    {
                        case '(':
                            flag++;
                            list.Add(index);
                            break;
                        case ')':
                            flag--;
                            list.Add(index);
                            if (flag == 0)
                            {
                                return;
                            }
                            break;
                    }
                    index++;
                }
                if (list.Count % 2 != 0)  //如果左右括号不匹配就跑出错误
                {
                    throw new Exception("名称出错了,‘(’与‘)’不匹配!");
                }
            }

      日期(2015-05-06)算法再思考。在函数DeleteTwo算法中使用了递归;有关递归的问题请看 C#中的递归APS和CPS模式详解(转载)  。

      需要对递归进行优化,尾递归优化在于使堆栈可以不用保存上一次的返回地址/状态值,从而把递归函数当成一个普通的函数调用。

    递归实际上是依赖上次的值,去求下次的值。 如果我们能把上次的值保存起来,在下次调用时传入,而不直接引用函数返回的值。 从而使堆栈释放,也就达到了尾递归优化的目的。

      在算法中引入StringBuilder储存上次函数的值,从而使堆栈不用保存上一次返回的地址/状态值,达到优化的目的。代码如下:

    private static string DeleteTwo(string name, ref StringBuilder sb)
            {
                List<int> list = new List<int>();
             
                if (!(name.Contains("(") || name.Contains(")")))
                    return sb.ToString();
                
                GetIndex(name, ref list);
                string first_half_name = name.Substring(0, list[0]); //前半部分
                sb.Append(first_half_name);
                string last_half_name = name.Substring(list[list.Count - 1] + 1, name.Length - list[list.Count - 1] - 1);        //后半部分
                return DeleteTwo(last_half_name, ref sb);
            }

      客户端代码:

           StringBuilder sb = new StringBuilder();
                string name = "110kV1#母分开关由运行改热备用(110kV1#母分备自投由信号改跳闸(1区),110kV1#母分保护由跳闸改信号(1区)),111(123(3)122)";
                var sname = DeleteTwo(name, ref sb);
                Console.WriteLine(sname);
  • 相关阅读:
    js获取数组最大值或最小值
    echarts 在 vue-awesome-swiper中无法点击
    vue 父子父组件通过props传父页面请求后的数据
    vue 路由对象
    popupwindow
    数据库
    冒泡排序
    xtuils
    版本更新
    清除缓存
  • 原文地址:https://www.cnblogs.com/zhangyuanbo12358/p/4451056.html
Copyright © 2011-2022 走看看