許多大大一定有寫過..巢狀式迴圈..就是..下面這樣

for (int i = 0; i < 10; i++)
{
  for (int j = 0; j < 10; j++)
  {
      if(oo==xx)
      {
          .....
      }
  }
}
 
昨天就在寫這方面的class.發現..就算有加入break效率也不怎樣..
就寫了簡單的例子去改寫一下程式..把巢狀式迴圈..變成只有一層..
 
巢狀式
Stopwatch watch = new Stopwatch();
int count = 0;
List<int> nu = new List<int>();
List<int> nu1 = new List<int>();

for (int i = 0; i < 10000; i++)
{
  nu.Add(i);
}
for (int j = 0; j < 10000; j++)
{
  nu1.Add(j);
}

watch.Start();
foreach (int a in nu)
{
  foreach (int b in nu1)
  {
      if (a == b)
      {
          count++;
      }
  }
}
watch.Stop();

Response.Write(watch.ElapsedMilliseconds / 1000f + "<br />");
Response.Write(count);
 
單迴圈
Stopwatch watch = new Stopwatch();
int count = 0;
List<int> nu = new List<int>();
List<int> nu1 = new List<int>();

for (int i = 0; i < 10000; i++)
{
  nu.Add(i);
}
for (int j = 0; j < 10000; j++)
{
  nu1.Add(j);
}

watch.Start();
foreach (int a in nu)
{
  if (nu1.Contains(a))
  {
      count++;
  }
}
watch.Stop();

Response.Write(watch.ElapsedMilliseconds / 1000f +"<br />");
Response.Write(count);
 
結果..上面的測試..
巢狀式:平均1.35秒
單層式:平均0.46秒
 
上面兩個例子效果其實是一樣的..我把巢狀式改成單迴圈..然後用contains來代替..
查一下.net framework的contains的method..
 
bool IList.Contains(object value)
{
  return (IndexOf(this, value) >= this.GetLowerBound(0));
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int IndexOf(Array array, object value)
{
  if (array == null)
  {
      throw new ArgumentNullException("array");
  }
  int lowerBound = array.GetLowerBound(0);
  return IndexOf(array, value, lowerBound, array.Length);
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int IndexOf(Array array, object value, int startIndex, int count)
{
  int num2;
  if (array == null)
  {
      throw new ArgumentNullException("array");
  }
  int lowerBound = array.GetLowerBound(0);
  if ((startIndex < lowerBound) || (startIndex > (array.Length + lowerBound)))
  {
      throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  }
  if ((count < 0) || (count > ((array.Length - startIndex) + lowerBound)))
  {
      throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  }
  if (array.Rank != 1)
  {
      throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
  }
  if (TrySZIndexOf(array, startIndex, count, value, out num2))
  {
      return num2;
  }
  object[] objArray = array as object[];
  int num3 = startIndex + count;
  if (objArray != null)
  {
      if (value == null)
      {
          for (int i = startIndex; i < num3; i++)
          {
              if (objArray[i] == null)
              {
                  return i;
              }
          }
      }
      else
      {
          for (int j = startIndex; j < num3; j++)
          {
              object obj2 = objArray[j];
              if ((obj2 != null) && obj2.Equals(value))
              {
                  return j;
              }
          }
      }
  }
  else
  {
      for (int k = startIndex; k < num3; k++)
      {
          object obj3 = array.GetValue(k);
          if (obj3 == null)
          {
              if (value == null)
              {
                  return k;
              }
          }
          else if (obj3.Equals(value))
          {
              return k;
          }
      }
  }
  return (lowerBound - 1);
}
 
看起來也是要跑迴圈也沒有比直接if else簡單多少..可是效率好很多..Dont tell anyone..
所以個人的猜測就是.net framework一定有偷偷最佳化過啦..Hot..
還有在javascript也是一樣的情形..用巢狀式的效率也低於單層式的..
 
ps:小弟只是已微薄的知識去猜測的..各位大大如果不同的觀念..請給小弟多多指教..^^..

DotBlogs Tags: C#


關連文章

回應

  • Eric Tsai 2008/5/14 下午 06:28 回覆

    # re: 巢狀式迴圈..效率..

    這純粹只是跑的圈數不同的關係。一個跑了100000000圈另一個只跑了10000圈,卻只花了兩倍多的時間,到底誰慢就很清楚了。而且像這種只有單一match的情況,用迴圈找到之後就該break了,而不是放任他跑下去。

  • bibby 2008/5/15 上午 02:34 回覆

    # re: 巢狀式迴圈..效率..

    一個跑了100000000圈另一個只跑了10000圈..<<好像不是這樣..你可以看一下.net framework的contains的method也是用迴圈去跑阿..所以我猜不跑的圈數不同..

  • Eric Tsai 2008/5/15 上午 09:49 回覆

    # re: 巢狀式迴圈..效率..

    我了解你的意思了。我改了一下參考Contains的做法,在我的電腦上大概是0.8秒跟0.6秒的差別,還可以。

    foreach (int a in nu)
        {
            int cnt = nu1.Count;
            for (int j = 0; j < cnt; j++)
            {
                if (a == nu1[j])
                {
            count++;
            break;
                }
            }
        }

  • bibby 2008/5/26 上午 02:28 回覆

    # re: 巢狀式迴圈..效率..

    Eric Tsai大大..
    因為我去看了contains的method..裡面並沒有break或是其他省迴圈的方式..所以..我猜是內部函式有優化過的...^^||..

    還有..正常情況下如果你能確定collection只有一個值..那當然要break掉阿..可是如果不能確定..^^||..還是要跑完ㄅ..

  • Eric Tsai 2008/5/28 下午 02:45 回覆

    # re: 巢狀式迴圈..效率..

            // Contains returns true if the specified element is in the List.
            // It does a linear, O(n) search.  Equality is determined by calling
            // item.Equals().
            //
            public bool Contains(T item) {
                if ((Object) item == null) {
                    for(int i=0; i<_size; i++)
                        if ((Object) _items[i] == null)
                            return true;
                    return false;
                }
                else {
                    EqualityComparer<T> c = EqualityComparer<T>.Default;
                    for(int i=0; i<_size; i++) {
                        if (c.Equals(_items[i], item)) return true;
                    }
                    return false;
                }
            }

    找到就return true,跟break意思不是一樣嗎? 而且Contains本來就只會找到一個,你現在才說可能有多個相同值,那你一開始改寫成用Contains就是錯的,跑出來的count絕對跟判斷a==b不一樣。

  • bibby 2008/5/28 下午 09:02 回覆

    # re: 巢狀式迴圈..效率..

    對喔..return 對喔..跟break不就一樣..一﹏一||..忽然忘了有這回事...
    conteains不能用在多值..文章寫太久了..當了當時的假設了..
    你是對的..謝謝指教..^^..

標題 *

名稱 *

Email 

Url  

回應 *

登入後使用進階評論

Please add 5 and 5 and type the answer here:

Copyright © 2008 design by Iris Kang.