“菲波纳锲”数列 计算

学习真是奇妙,本想查找些异步进程的东西,实践的时候突然发现异步控制UI有些不大一样,于是去查异步更新UI,结果查到了BackgroundWorker,于是去查这个类,又在MSDN上找到了一个示例,是以计算 斐波纳契 数列来显示进度的,示例是这样的

BackgroundWorker MSDN示例
  1 using System;
  2 using System.Collections;
  3 using System.ComponentModel;
  4 using System.Drawing;
  5 using System.Threading;
  6 using System.Windows.Forms;
  7 
  8 namespace BackgroundWorkerExample
  9 {    
 10     public class FibonacciForm : System.Windows.Forms.Form
 11     {    
 12         private int numberToCompute = 0;
 13         private int highestPercentageReached = 0;
 14 
 15         private System.Windows.Forms.NumericUpDown numericUpDown1;
 16         private System.Windows.Forms.Button startAsyncButton;
 17         private System.Windows.Forms.Button cancelAsyncButton;
 18         private System.Windows.Forms.ProgressBar progressBar1;
 19         private System.Windows.Forms.Label resultLabel;
 20         private System.ComponentModel.BackgroundWorker backgroundWorker1;
 21 
 22         public FibonacciForm()
 23         {    
 24             InitializeComponent();
 25 
 26             InitializeBackgoundWorker();
 27         }
 28 
 29         // Set up the BackgroundWorker object by 
 30         // attaching event handlers. 
 31         private void InitializeBackgoundWorker()
 32         {
 33             backgroundWorker1.DoWork += 
 34                 new DoWorkEventHandler(backgroundWorker1_DoWork);
 35             backgroundWorker1.RunWorkerCompleted += 
 36                 new RunWorkerCompletedEventHandler(
 37             backgroundWorker1_RunWorkerCompleted);
 38             backgroundWorker1.ProgressChanged += 
 39                 new ProgressChangedEventHandler(
 40             backgroundWorker1_ProgressChanged);
 41         }
 42     
 43         private void startAsyncButton_Click(System.Object sender, 
 44             System.EventArgs e)
 45         {
 46             // Reset the text in the result label.
 47             resultLabel.Text = String.Empty;
 48 
 49             // Disable the UpDown control until 
 50             // the asynchronous operation is done.
 51             this.numericUpDown1.Enabled = false;
 52 
 53             // Disable the Start button until 
 54             // the asynchronous operation is done.
 55             this.startAsyncButton.Enabled = false;
 56 
 57             // Enable the Cancel button while 
 58             // the asynchronous operation runs.
 59             this.cancelAsyncButton.Enabled = true;
 60 
 61             // Get the value from the UpDown control.
 62             numberToCompute = (int)numericUpDown1.Value;
 63 
 64             // Reset the variable for percentage tracking.
 65             highestPercentageReached = 0;
 66 
 67             // Start the asynchronous operation.
 68             backgroundWorker1.RunWorkerAsync(numberToCompute);
 69         }
 70 
 71         private void cancelAsyncButton_Click(System.Object sender, 
 72             System.EventArgs e)
 73         {   
 74             // Cancel the asynchronous operation.
 75             this.backgroundWorker1.CancelAsync();
 76 
 77             // Disable the Cancel button.
 78             cancelAsyncButton.Enabled = false;
 79         }
 80 
 81         // This event handler is where the actual,
 82         // potentially time-consuming work is done.
 83         private void backgroundWorker1_DoWork(object sender, 
 84             DoWorkEventArgs e)
 85         {   
 86             // Get the BackgroundWorker that raised this event.
 87             BackgroundWorker worker = sender as BackgroundWorker;
 88 
 89             // Assign the result of the computation
 90             // to the Result property of the DoWorkEventArgs
 91             // object. This is will be available to the 
 92             // RunWorkerCompleted eventhandler.
 93             e.Result = ComputeFibonacci((int)e.Argument, worker, e);
 94         }
 95 
 96         // This event handler deals with the results of the
 97         // background operation.
 98         private void backgroundWorker1_RunWorkerCompleted(
 99             object sender, RunWorkerCompletedEventArgs e)
100         {
101             // First, handle the case where an exception was thrown.
102             if (e.Error != null)
103             {
104                 MessageBox.Show(e.Error.Message);
105             }
106             else if (e.Cancelled)
107             {
108                 // Next, handle the case where the user canceled 
109                 // the operation.
110                 // Note that due to a race condition in 
111                 // the DoWork event handler, the Cancelled
112                 // flag may not have been set, even though
113                 // CancelAsync was called.
114                 resultLabel.Text = "Canceled";
115             }
116             else
117             {
118                 // Finally, handle the case where the operation 
119                 // succeeded.
120                 resultLabel.Text = e.Result.ToString();
121             }
122 
123             // Enable the UpDown control.
124             this.numericUpDown1.Enabled = true;
125 
126             // Enable the Start button.
127             startAsyncButton.Enabled = true;
128 
129             // Disable the Cancel button.
130             cancelAsyncButton.Enabled = false;
131         }
132 
133         // This event handler updates the progress bar.
134         private void backgroundWorker1_ProgressChanged(object sender,
135             ProgressChangedEventArgs e)
136         {
137             this.progressBar1.Value = e.ProgressPercentage;
138         }
139 
140         // This is the method that does the actual work. For this
141         // example, it computes a Fibonacci number and
142         // reports progress as it does its work.
143         long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)
144         {
145             // The parameter n must be >= 0 and <= 91.
146             // Fib(n), with n > 91, overflows a long.
147             if ((n < 0) || (n > 91))
148             {
149                 throw new ArgumentException(
150                     "value must be >= 0 and <= 91", "n");
151             }
152 
153             long result = 0;
154 
155             // Abort the operation if the user has canceled.
156             // Note that a call to CancelAsync may have set 
157             // CancellationPending to true just after the
158             // last invocation of this method exits, so this 
159             // code will not have the opportunity to set the 
160             // DoWorkEventArgs.Cancel flag to true. This means
161             // that RunWorkerCompletedEventArgs.Cancelled will
162             // not be set to true in your RunWorkerCompleted
163             // event handler. This is a race condition.
164 
165             if (worker.CancellationPending)
166             {   
167                 e.Cancel = true;
168             }
169             else
170             {   
171                 if (n < 2)
172                 {   
173                     result = 1;
174                 }
175                 else
176                 {   
177                     result = ComputeFibonacci(n - 1, worker, e) + 
178                              ComputeFibonacci(n - 2, worker, e);
179                 }
180 
181                 // Report progress as a percentage of the total task.
182                 int percentComplete = 
183                     (int)((float)n / (float)numberToCompute * 100);
184                 if (percentComplete > highestPercentageReached)
185                 {
186                     highestPercentageReached = percentComplete;
187                     worker.ReportProgress(percentComplete);
188                 }
189             }
190 
191             return result;
192         }
193 
194 
195         #region Windows Form Designer generated code
196         
197         private void InitializeComponent()
198         {
199             this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
200             this.startAsyncButton = new System.Windows.Forms.Button();
201             this.cancelAsyncButton = new System.Windows.Forms.Button();
202             this.resultLabel = new System.Windows.Forms.Label();
203             this.progressBar1 = new System.Windows.Forms.ProgressBar();
204             this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
205             ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
206             this.SuspendLayout();
207             // 
208             // numericUpDown1
209             // 
210             this.numericUpDown1.Location = new System.Drawing.Point(16, 16);
211             this.numericUpDown1.Maximum = new System.Decimal(new int[] {
212             91,
213             0,
214             0,
215             0});
216             this.numericUpDown1.Minimum = new System.Decimal(new int[] {
217             1,
218             0,
219             0,
220             0});
221             this.numericUpDown1.Name = "numericUpDown1";
222             this.numericUpDown1.Size = new System.Drawing.Size(80, 20);
223             this.numericUpDown1.TabIndex = 0;
224             this.numericUpDown1.Value = new System.Decimal(new int[] {
225             1,
226             0,
227             0,
228             0});
229             // 
230             // startAsyncButton
231             // 
232             this.startAsyncButton.Location = new System.Drawing.Point(16, 72);
233             this.startAsyncButton.Name = "startAsyncButton";
234             this.startAsyncButton.Size = new System.Drawing.Size(120, 23);
235             this.startAsyncButton.TabIndex = 1;
236             this.startAsyncButton.Text = "Start Async";
237             this.startAsyncButton.Click += new System.EventHandler(this.startAsyncButton_Click);
238             // 
239             // cancelAsyncButton
240             // 
241             this.cancelAsyncButton.Enabled = false;
242             this.cancelAsyncButton.Location = new System.Drawing.Point(153, 72);
243             this.cancelAsyncButton.Name = "cancelAsyncButton";
244             this.cancelAsyncButton.Size = new System.Drawing.Size(119, 23);
245             this.cancelAsyncButton.TabIndex = 2;
246             this.cancelAsyncButton.Text = "Cancel Async";
247             this.cancelAsyncButton.Click += new System.EventHandler(this.cancelAsyncButton_Click);
248             // 
249             // resultLabel
250             // 
251             this.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
252             this.resultLabel.Location = new System.Drawing.Point(112, 16);
253             this.resultLabel.Name = "resultLabel";
254             this.resultLabel.Size = new System.Drawing.Size(160, 23);
255             this.resultLabel.TabIndex = 3;
256             this.resultLabel.Text = "(no result)";
257             this.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
258             // 
259             // progressBar1
260             // 
261             this.progressBar1.Location = new System.Drawing.Point(18, 48);
262             this.progressBar1.Name = "progressBar1";
263             this.progressBar1.Size = new System.Drawing.Size(256, 8);
264             this.progressBar1.Step = 2;
265             this.progressBar1.TabIndex = 4;
266             // 
267             // backgroundWorker1
268             // 
269             this.backgroundWorker1.WorkerReportsProgress = true;
270             this.backgroundWorker1.WorkerSupportsCancellation = true;
271             // 
272             // FibonacciForm
273             // 
274             this.ClientSize = new System.Drawing.Size(292, 118);
275             this.Controls.Add(this.progressBar1);
276             this.Controls.Add(this.resultLabel);
277             this.Controls.Add(this.cancelAsyncButton);
278             this.Controls.Add(this.startAsyncButton);
279             this.Controls.Add(this.numericUpDown1);
280             this.Name = "FibonacciForm";
281             this.Text = "Fibonacci Calculator";
282             ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
283             this.ResumeLayout(false);
284 
285         }
286         #endregion
287 
288         [STAThread]
289         static void Main()
290         {
291             Application.Run(new FibonacciForm());
292         }
293     }
294 }

运行之后,输入超过40的数,都很慢,于是去看看算法,于是就有了下面的代码

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Diagnostics;
 6 
 7 namespace FibonacciRecursively
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             Program p = new Program();
14 
15             const int endNum = 40;
16 
17             p.CountTime("尾递归递归",
18                 new Func<int>(
19                     () => { return p.FibonacciTailRecursively(endNum, 0, 1); }
20                     ));
21 
22             p.CountTime("循环算法",
23                 new Func<int>(
24                     () => { return p.FibonacciLoop(endNum); }
25                     ));
26 
27             
28             p.CountTime("线性递归",
29                 new Func<int>(
30                     () => { return p.FibonacciRecursively(endNum); }
31                     ));
32 
33             Console.ReadKey();
34         }
35 
36         public void CountTime(string name, Func<int> action)
37         {
38             Stopwatch sw = new Stopwatch();
39             sw.Start();
40 
41             //要执行的代码
42             int result=action.Invoke();
43 
44             sw.Stop();
45             Console.WriteLine();
46             Console.WriteLine(string.Format("{0}:计算结果为:{1}",name,result));
47             Console.WriteLine("总运行时间:" + sw.Elapsed);
48             Console.WriteLine("测量实例得出的总运行时间(毫秒为单位):" + sw.ElapsedMilliseconds);
49         }
50 
51         //线性递归
52         public int FibonacciRecursively(int n)
53         {
54             if (n < 2) return n;
55             return FibonacciRecursively(n - 1) + FibonacciRecursively(n - 2);
56         }
57 
58         //尾递归
59         public int FibonacciTailRecursively(int n, int acc1, int acc2)
60         {
61             if (n == 0) return acc1;
62             return FibonacciTailRecursively(n - 1, acc2, acc1 + acc2);
63         }
64 
65         //循环算法
66         public int FibonacciLoop(int n)
67         {
68             int result = 0;
69             int i = 1;
70             while (n > 0)
71             {
72                 int temp = i;
73 
74                 i += result;
75 
76                 result = temp;
77                 
78                 n--;
79             }
80             return result;
81         }
82 
83     }
84 }

运行结果

三种计算方式,个人感觉,线性递归的方式更直接,更容易想到,自然也更容易理解,但是效率 惨不忍睹,循环算法和尾递归的方式明显好于线性递归,尾递归给我的感觉更像是把需要的结果都放到了参数里面,省去了系统维护他的参数堆栈,老赵对此做了一定的解释

http://www.cnblogs.com/JeffreyZhao/archive/2009/04/01/tail-recursion-explanation.html

还有对于递归与循环的关系,有的说所有的递归都可以用循环代替,有的说不能,我也很困惑,感觉这里有篇文章解释还是比较到位的

http://blog.sina.com.cn/s/blog_62b1508e0100hcyx.html

posted on 2012-12-19 16:31  MikeRen  阅读(914)  评论(0编辑  收藏  举报

导航