“菲波纳锲”数列 计算
学习真是奇妙,本想查找些异步进程的东西,实践的时候突然发现异步控制UI有些不大一样,于是去查异步更新UI,结果查到了BackgroundWorker,于是去查这个类,又在MSDN上找到了一个示例,是以计算 斐波纳契 数列来显示进度的,示例是这样的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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的数,都很慢,于是去看看算法,于是就有了下面的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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