遞迴小記

sunshine.pl發表於2018-10-24

    來自實際遇到的一個問題,需要查詢出根節點的下的所有子節點,首先想到的就是遞迴了,用JS寫過,C#之前寫了一次沒寫對,這次專門用心看了一下的,發現和ref關鍵字有關,寫貼上原始碼:

    

public static void InsertCmsTypeName(int typeid, ref List<string> cacheNameList)
{
    string name = string.Empty;
    List<TB_CMSType> cts = CMS.GetCmsTypeForParentID(typeid);
    if (cts != null && cts.Count > 0)
    {
        foreach (TB_CMSType item in cts)
        {
            name = "GetSpecialProducts" + item.ID + Config.SiteID; 
            cacheNameList.Add(name);
            InsertCmsTypeName(item.ID, ref cacheNameList);
        }
    }
}

    typeid是節點id,第一次是根節點,往後就是當前節點下的子節點了。cacheNameList是儲存資料的集合,型別名稱前面用了ref修飾。

    為什麼呢,這裡就涉及到一個概念了,值傳遞!InsertCmsTypeName方法裡每次對集合做add操作的時候,cacheNameList的陣列個數都會新增。

    

    List<string> cacheNameList = new List<string>();
    Base.InsertCmsTypeName(4106, ref cacheNameList);

    可以很明顯的看到,InsertCmsTypeName方法是沒有返回值的, 那麼如何保持遞迴方法裡cacheNameList的值呢,ref 就出來了,ref使引數的傳遞方式變成了值傳遞,每次引數指向的是記憶體裡的首地址,這樣每次修改這個值的時候,它本身就修改了。一般的引數傳遞是引用傳遞,就是說在傳遞引數的時候,引數的本身不會被修改,而通過ref修飾過的引數,傳遞方式變成值傳遞,每次方法內部修改這個引數的時候,引數的本身也會被修改,所以,InsertCmsTypeName無需返回值。

    之前用C#寫遞迴的時候就是沒注意到這個,導致遞迴方法執行了,最後的結果還是沒有 (*/ω\*) 這裡記下筆記還是有必要的。

    

    另,演算法真的很重要鴨,要是不會寫遞迴,這種通過根節點找出所有子節點的問題,怕是要寫for迴圈了,而且就算是for迴圈也不能根本性解決問題,只能預測最多有多少層,然後寫多少個for,麻煩的不行。當然,用遞迴也不能瞎用,要控制好進行遞迴的條件,不然很容易導致死迴圈的出現(這可是會卡死程式的,所以用的時候要慎用)。

 


相關文章