none
關於在C#2010中遞迴函數的次數上限 RRS feed

  • 問題

  • (小弟的作業系統是win8 64bit)

    小弟寫了一個windows form 應用程式,

    來測試C#中遞迴函數的次數上限,

    有如下程式碼:

            int N_max = 12000;
            int N = 0;
            int add( int a)
            {
                N++;
                if (N >= N_max) { return a; }
                return add(a + 1);
            }

    整個程式約在一秒內跑完,執行沒出問題。

    但若把第一行改為:

    int N_max = 13000;

    執行時就會出錯,錯誤訊息為:請確定沒有無限迴圈或無限遞迴的情況

    我很確定沒有無限遞迴,

    上網查了查原因,發現可能是記憶體不夠。

    請問,要如何增大該程式所能使用的記憶體?

    或者說,如何能讓上述函式遞迴13000次以上?

    感謝。



    2016年5月18日 下午 05:04

解答

  • 在Form1_Load事件處理程序的第一行加入:

    Control.CheckForIllegalCrossThreadCalls = false;

    • 已標示為解答 maplejjj 2016年5月22日 上午 07:21
    2016年5月22日 上午 05:47

所有回覆

  • 迴圈的選擇很多種:https://msdn.microsoft.com/zh-tw/library/f0e10e56%28v=vs.90%29.aspx

    為什麼一定要選 if 來用?


    理直氣和,切記。

    個人

    2016年5月19日 上午 12:35
  • 您可以擴充執行緒的堆疊空間, 再利用已擴充堆疊空間的執行緒來執行add函式, 像這樣:

    int N_max = 13000;
            int N = 0;
            int add(int a)
            {
                N++;
                if (N >= N_max) { return a; }
                return add(a + 1);
            }
    
            private void BigRecursion(object obj)
            {
                add(10);
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                var stackSize = 10000000;
                Thread thread = new Thread(new ParameterizedThreadStart(BigRecursion), stackSize);
            }

    2016年5月19日 上午 12:37
  • 您好:

    感謝您的回答。

    我按照您的程式碼測試,之後在Form1_Load函式中加上:

    BigRecursion(0);

    但執行時仍然出現同樣的錯誤訊息:請確定沒有無限迴圈或無限遞迴的情況

    請問是否是BigRecursion(0)的寫法是否有誤?(我不太明白BigRecursion的參數該怎麼寫)

    若無誤,仍請教如何能讓遞迴函式執行13000次以上?

    謝謝。

    2016年5月19日 上午 08:02
  • 直接呼叫BigRecursion函式, 因為未擴充堆疊的空間就逕行呼叫, 所以結果和您原先的程式一樣, 所以一定要先擴充執行緒的堆疊空間, 再由執行緒來執行BigRecursion函式才不會發生錯誤
    2016年5月19日 上午 08:15
  • 我對於執行緒的操作不熟悉,

    我想:

    Thread thread = new Thread(new ParameterizedThreadStart(BigRecursion), stackSize);

    這一行應已經擴充執行緒的堆疊空間了吧

    請問之後如何使用執行緒執行BigRecursion函式呢?

    2016年5月19日 上午 10:50
  • 執行以下的程式碼即可:

    thread.Start(10);

    2016年5月20日 上午 05:57
  • 測試結果:

    thread.Start(10);

    執行後不會出現錯誤訊息,

    不過其好像不會回傳任何值。

    再請問我要如何在 Form1_Load中得到add函數執行13000次後的回傳值?

    謝謝。

    2016年5月20日 上午 07:02
  • 將BigRecursion改成這樣即可:

    private void BigRecursion(object obj)
            {
                int result=add(100);
                Console.WriteLine(result);
            }

    2016年5月21日 上午 02:48
  • 您好:

    由於我寫的是 windows form 應用程式,

    我想將結果呈現在textbox控制項中,

    而非控制台,

    於是整篇程式碼修改成如下:

        public partial class Form1 : Form
        {
            TextBox display;
            int N_max = 13000;
            int N = 0;
            int add(int a)
            {
                N++;
                if (N >= N_max) { return a; }
                return add(a + 1);
            }
            private void BigRecursion(object obj)
            {
                display.Text=add(10).ToString();
            }
            public Form1()
            {
                InitializeComponent();
                display = textBox1;            
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                var stackSize = 10000000;
                Thread thread = new Thread(new ParameterizedThreadStart(BigRecursion), stackSize);
                thread.Start(10);            
            }
        }

    但BigRecursion執行時仍有錯誤訊息:

    跨執行緒作業無效: 存取控制項 'textBox1' 時所使用的執行緒與建立控制項的執行緒不同。

    請問該如何解決?

    謝謝。

    2016年5月21日 上午 04:57
  • 在Form1_Load事件處理程序的第一行加入:

    Control.CheckForIllegalCrossThreadCalls = false;

    • 已標示為解答 maplejjj 2016年5月22日 上午 07:21
    2016年5月22日 上午 05:47
  • 已解決,感謝
    2016年5月22日 上午 07:21
  • CheckForIllegalCrossThreadCalls = true 是不好的解決方法,它只能用在 debugger 上,出來 debugger 就啥都不是了。

    最好還是用正規解法去處理。

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/69815050-d32a-42d0-9cd4-f4157f9ce9c2/does-checkforillegalcrossthreadcalls-work-in-nondebug-mode?forum=netfxsetup


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年5月23日 上午 02:17
    版主
  • 較正規的作法:https://msdn.microsoft.com/en-us/library/ms171728

    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年5月23日 上午 02:18
    版主
  • 報告小朱大大, 我試過用正規的做法解決, 但是正規的做法會再度加重堆疊的負擔, 而且負擔不小, 所以才會採取這種解法
    2016年5月24日 上午 03:49
  • 寫到 log 檔並等待程式結束再開檔是最佳作法。

    不然就像你說的,負擔會很重。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年5月24日 上午 10:25
    版主
  • 如果真要認真講 , 這個情境根本就不該用遞迴來做, 這明明一般的迴圈就可以做完.

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2016年5月24日 下午 01:28
    版主
  • 其實我有點好奇, 如果  N_max = 30000000; , stack size 要設到多大 ?

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2016年5月25日 上午 09:39
    版主