| 
 | 
 
  
  
ทฤษฎีบทพีทาโกรัส คือ ทฤษฎีความสัมพันธ์ระหว่างด้านทั้งสามของสามเหลี่ยมมุมฉาก สามเหลี่ยมที่มีมุมใดมุมหนึ่งตั้งฉาก 90 องศา เป็นทฤษฎีที่คิดค้นโดยพีทาโกรัส นักคณิตศาสตร์ชาวกรีก ซึ่งกล่าวถึงทฤษฎีนี้ไว้ว่า 
 
"ในสามเหลี่ยมมุมฉากใด ๆ พื้นที่ของสี่เหลี่ยมจัตุรัสที่มีด้านเป็นด้านตรงข้ามมุมฉาก เท่ากับผลรวมพื้นที่ของสี่เหลี่ยมจัตุรัสที่มีด้านเป็นด้านประชิดมุมฉากของสามเหลี่ยมมุมฉากนั้น"  
 
จากทฤษฎีบทพีทาโกรัส ทำให้เราสามารถเขียนสูตรพีทาโกรัสเพื่อหาความยาวของด้านต่างๆของสามเหลี่ยมมุมฉากได้ดังนี้ 
 
a² + b² = c² 
 
โจทย์ของเราก็คือ การหาชุดของความยาวด้านของสามเหลี่ยมมุมฉากที่เป็นจำนวนเต็มทั้งหมดที่จะเป็นไปได้  
 
ในการทดสอบค่าความถูกต้องของสมการ Pythagoras ซึ่งเป็น a^2 + b^2 = c^2 เราจะทดสอบค่า a, b, และ c ทุกคู่ที่เป็นไปได้ ซึ่งค่า a, b, และ c จะต้องเป็นจำนวนเต็มบวก และค่า c ต้องมากกว่าค่า a และมากกว่าค่า b ด้วย ดังนั้นเราสามารถใช้ Nested Loop สามชั้นเพื่อทดสอบทุกคู่ของค่า a และ b แล้วคำนวณหาค่า c เพื่อเปรียบเทียบค่าของ a^2 + b^2 ว่าเท่ากับ c^2 หรือไม่? 
ข้อสังเกต:  
  
การใช้ Nested Loop ซ้อนกันถึง 3 ลูป โดยให้ลูป B และ ลูป C ทำการอ่านค่าเริ่มต้นจาก 1 ทำให้จำนวนรอบวงในสุดจะต้องอ่านค่าและเปรียบเทียบกันถึง 100 x 100 x 100 = 1,000,000 รอบ ซึ่งจะต้องใช้เวลามาก แต่คำตอบที่ได้จะเกิดจากการย้ายข้างของ a กับ b เช่น a = 3, b = 4 คำตอบ c = 5 พอให้ a = 4, b = 3 (การเริ่มนับจาก 1) แต่คำตอบ c = 5 เหมือนเดิม ดังนั้นเราจะใช้การลดจำนวนการนับลงไป โดยให้ลูปในมีค่าเริ่มต้นจากลูปนอกแทน ...  
 
  
เมื่อกำหนดค่าเริ่มต้นใหม่โดยให้ลูปในมีค่าเริ่มต้นจากลูปนอกแทน ... เราให้ลูปในมีค่าเริ่มต้นจากค่าของลูปนอกแทน คือ b เริ่มจากค่า a ส่วน c จะเริ่มจากค่า b (b จะนับค่าต่ำกว่า a ไม่ได้ และ c จะนับค่าต่ำกว่า b ไม่ได้นั่นเอง) ...  
-             For b As Integer = a To Val(txtMaxValue.Text)
 
 -                 For c As Integer = b To Val(txtMaxValue.Text)
 
  คัดลอกไปที่คลิปบอร์ด จากลูป b จะวนรอบเพียง 50% ส่วนลูป c จะวนรอบเหลือไม่เกิน 20% คำตอบที่ได้ก็จะเหลือเพียง 52 รายการ แต่อีก 52 รายการที่ไม่ได้นำมาคิดคำนวณ ก็คือการสลับค่ากันระหว่างค่า a และ b นั่นเอง ... 
 
  
การนำ LINQ (Language Integrated Query) มาช่วยในการแก้ปัญหาของความช้าในการวนลูปแบบ Nested Loop ... LINQ (ปกติจะอ่านว่าลิ้ง แต่บางคนก็อ่านว่าลิน หรือลินคิว ก็เอาตามที่สะดวกล่ะกันครับ) เจ้าตัวนี้จัดว่าเป็นความสามารถอันทรงพลังของ WinForm หรือ .Net Framework เลยก็ว่าได้ เพราะ LINQ คือชุดคำสั่งที่ทำงานกับกลุ่มของข้อมูล คล้ายๆกับการ Query ในฐานข้อมูลยังไงยังงั้นแหละครับทั่นผู้ชม 
-         ' / LINQ
 
 -         Dim PythagoreanTriple =
 
 -             From a In Enumerable.Range(1, MaxValue)
 
 -             From b In Enumerable.Range(a, MaxValue)
 
 -             Let c = Math.Sqrt(a * a + b * b)
 
 -             Where (c = Math.Floor(c) AndAlso c <= MaxValue)
 
 -             Select New With {a, b, c}
 
  คัดลอกไปที่คลิปบอร์ด ตัวอย่างที่แอดมินทำการทดสอบโดยให้ค่าสูงสุดที่ 100 อาจจะมองไม่เห็นผลสักเท่าไหร่ ลองใช้สัก 1,000 หรือ 10,000 รอบดู ทุกๆท่านจะได้เห็นผลลัพธ์ของการทำงานที่แตกต่างกันมากเลยทีเดียว ... 
 
เพิ่มเติม: นอกจากจะเอา LINQ มาแก้ปัญหาแล้ว โจทย์ข้อนี้ยังนำทางให้เราไปฝึกเขียนโค้ดเพื่อแยกการทำงานของ Thread ได้ด้วย รวมไปถึงการเรียนรู้ใช้งาน  Parallel programming in .NET ... เอาไว้แอดมินจะนำมาเสนอให้ทุกๆท่านได้รับชมกันอีกทีครับ 
 
แอดมินนำผลลัพธ์ที่ได้ไปใส่ไว้ TextBox, ListView และ DataGridView Control เพื่อสำหรับมือใหม่ๆจะได้ฝึกเรียนรู้ในการใช้งาน Control พื้นฐานต่างๆเหล่านี้ไปด้วยครับผม ...  
 
มาดูโค้ดฉบับเต็มกันเถอะ ... 
- Imports System.Text
 
  
- Public Class frmPythagoras
 
  
-     '/ Start-Stop Timer
 
 -     Private mTimeDouble As Double
 
 -     Private sWatch As New Stopwatch()
 
  
-     Private Sub frmPythagoras_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
 
 -         lblCount.Text = ""
 
 -         lblTimer.Text = ""
 
 -         lblLoop.Text = ""
 
 -         txtMaxValue.MaxLength = 6
 
 -         '// ฝากเป็นโจทย์ไปคิดในกรณีที่เราคิดกลับ เมื่อใช้สูตร a=2n, b=n²-1, c=n²+1
 
 -     End Sub
 
  
-     ' / -------------------------------------------------------------------------------------------------
 
 -     ' / เริ่มต้นในการประมวลผลแบบพื้นฐานด้วยการใช้ Nested Loop
 
 -     ' / -------------------------------------------------------------------------------------------------
 
 -     Private Sub btnNestedLoop_Click(sender As System.Object, e As System.EventArgs) Handles btnNestedLoop.Click
 
 -         TextBox1.Clear()
 
 -         Call InitializeListView()
 
 -         Call InitializeDataGridView()
 
 -         '// สร้าง String Builder สำหรับเก็บค่าไปแสดงผลใน TextBox Control (System.Text)
 
 -         Dim strBuilder As New StringBuilder()
 
 -         '// สร้าง ListViewItem เพื่อเก็บข้อมูล
 
 -         Dim items As New List(Of ListViewItem)
 
 -         '// สร้าง DataTable เพื่อเก็บข้อมูลให้กับ DataGridView
 
 -         Dim DT As New DataTable
 
 -         With DT.Columns
 
 -             .Add("A", GetType(Integer))
 
 -             .Add("B", GetType(Integer))
 
 -             .Add("C", GetType(Integer))
 
 -         End With
 
 -         lblTimer.Text = "Timer Nested Loop : "
 
 -         sWatch.Reset()
 
 -         sWatch.Start()
 
 -         Cursor = Cursors.WaitCursor
 
 -         '// ไว้นับจำนวนลูป
 
 -         Dim CountLoopA As Integer = 0 : Dim CountLoopB As Integer = 0 : Dim CountLoopC As Integer = 0
 
 -         '// ใช้ Nested Loop โดยกำหนดให้ลูปในใช้ค่าเริ่มต้นจากลูปนอก
 
 -         '// เพราะค่าตัวแปรของ a สลับกันกับ b ก็จะไม่มีผลอะไร เช่น a = 3, b = 4 หากกลับค่า a = 4, b = 3 ก็จะทำให้ได้ค่า c = 5 เท่ากัน
 
 -         '// และจะทำให้ลดจำนวนการวนรอบของลูปลงไป
 
 -         For a As Integer = 1 To Val(txtMaxValue.Text)
 
 -             CountLoopA += 1
 
 -             For b As Integer = a To Val(txtMaxValue.Text)
 
 -                 CountLoopB += 1
 
 -                 For c As Integer = b To Val(txtMaxValue.Text)
 
 -                     CountLoopC += 1
 
 -                     ' / --------------------------------------------------------
 
 -                     ' / เงื่อนไขที่ต้องการทดสอบ คือ a^2 + b^2 = c^2
 
 -                     ' / --------------------------------------------------------
 
 -                     If a * a + b * b = c * c Then
 
 -                         '// สำหรับ TextBox Control
 
 -                         strBuilder.AppendLine("a = " & a & vbTab & "b = " & b & vbTab & "c = " & c)
 
 -                         '// สำหรับ ListView Control
 
 -                         Dim NewItem As New ListViewItem(a) '// กำหนดค่าให้กับคอลัมน์แรก
 
 -                         NewItem.SubItems.Add(b) ' เพิ่มค่าในคอลัมน์ที่สอง
 
 -                         NewItem.SubItems.Add(c) ' เพิ่มค่าในคอลัมน์ที่สาม
 
 -                         items.Add(NewItem)
 
 -                         '// สำหรับ DataGridView Control
 
 -                         Dim row As String() = New String() {"", "", ""}
 
 -                         DT.Rows.Add(a, b, c)
 
 -                         '// หากใช้ Exit For ก็จะช่วยให้ลดจำนวนการวนรอบลงไปได้อีก
 
 -                         'Exit For
 
 -                     End If
 
 -                 Next
 
 -             Next
 
 -         Next
 
 -         '// แสดงผลลัพธ์ใน TextBox Control
 
 -         TextBox1.Text = strBuilder.ToString()
 
 -         '// แสดงผลลัพธ์ใน ListView Control
 
 -         ListView1.Items.AddRange(items.ToArray())
 
 -         '// แสดงผลลัพธ์ใน DataGridView Control
 
 -         DataGridView1.DataSource = DT
 
 -         lblCount.Text = "จำนวน: " & DataGridView1.RowCount & " รายการ"
 
 -         DT.Dispose()
 
 -         txtMaxValue.Focus()
 
 -         Cursor = Cursors.Default
 
 -         sWatch.Stop()
 
 -         mTimeDouble = sWatch.ElapsedMilliseconds * 0.001
 
 -         lblTimer.Text = lblTimer.Text & mTimeDouble.ToString & " sec."
 
 -         lblLoop.Text = "a = " & Format(CountLoopA, "#,##") & vbCrLf & "b = " & Format(CountLoopB, "#,##") & vbCrLf & "c = " & Format(CountLoopC, "#,##")
 
 -     End Sub
 
  
-     ' / -------------------------------------------------------------------------------------------------
 
 -     ' / สามารถใช้ LINQ ใน VB.NET เพื่อหาชุดของความยาวด้านของสามเหลี่ยมมุมฉาก
 
 -     ' / Pythagorean Triplets ที่เป็นเลขจำนวนเต็มทั้งหมดที่จะเป็นไปได้ดังนี้
 
 -     ' / -------------------------------------------------------------------------------------------------
 
 -     Private Sub btnLinQ_Click(sender As System.Object, e As System.EventArgs) Handles btnLinQ.Click
 
 -         TextBox1.Clear()
 
 -         Call InitializeListView()
 
 -         Call InitializeDataGridView()
 
 -         '//
 
 -         Dim MaxValue As Integer = Val(txtMaxValue.Text) '// กำหนดความยาวด้านสูงสุดที่ต้องการทดสอบ
 
 -         '// สร้าง String Builder สำหรับเก็บค่าไปแสดงผลใน TextBox Control (System.Text)
 
 -         Dim strBuilder As New StringBuilder()
 
 -         '// สร้าง ListViewItem เพื่อเก็บข้อมูล
 
 -         Dim items As New List(Of ListViewItem)
 
 -         '// สร้าง DataTable เพื่อเก็บข้อมูลให้กับ DataGridView
 
 -         Dim DT As New DataTable
 
 -         With DT.Columns
 
 -             .Add("A", GetType(Integer))
 
 -             .Add("B", GetType(Integer))
 
 -             .Add("C", GetType(Integer))
 
 -         End With
 
 -         lblTimer.Text = "Timer LINQ : "
 
 -         sWatch.Reset()
 
 -         sWatch.Start()
 
 -         Cursor = Cursors.WaitCursor
 
 -         ' / -------------------------------------------------------------------------------------------------
 
 -         ' / LINQ
 
 -         Dim PythagoreanTriple =
 
 -             From a In Enumerable.Range(1, MaxValue)
 
 -             From b In Enumerable.Range(a, MaxValue)
 
 -             Let c = Math.Sqrt(a * a + b * b)
 
 -             Where (c = Math.Floor(c) AndAlso c <= MaxValue)
 
 -             Select New With {a, b, c}
 
 -         ' / -------------------------------------------------------------------------------------------------
 
  
-         For Each triplet In PythagoreanTriple
 
 -             strBuilder.AppendLine("a = " & triplet.a & vbTab & "b = " & triplet.b & vbTab & "c = " & triplet.c)
 
 -             '// สำหรับ ListView Control
 
 -             Dim NewItem As New ListViewItem(triplet.a) '// กำหนดค่าให้กับคอลัมน์แรก
 
 -             NewItem.SubItems.Add(triplet.b) ' เพิ่มค่าในคอลัมน์ที่สอง
 
 -             NewItem.SubItems.Add(triplet.c) ' เพิ่มค่าในคอลัมน์ที่สาม
 
 -             items.Add(NewItem)
 
 -             '// สำหรับ DataGridView Control
 
 -             Dim row As String() = New String() {"", "", ""}
 
 -             DT.Rows.Add(triplet.a, triplet.b, triplet.c)
 
 -         Next
 
 -         '// แสดงผลลัพธ์ใน TextBox Control
 
 -         TextBox1.Text = strBuilder.ToString()
 
 -         '// แสดงผลลัพธ์ใน ListView Control
 
 -         ListView1.Items.AddRange(items.ToArray())
 
 -         '// แสดงผลลัพธ์ใน DataGridView Control
 
 -         DataGridView1.DataSource = DT
 
 -         lblCount.Text = "จำนวน: " & DataGridView1.RowCount & " รายการ"
 
 -         DT.Dispose()
 
 -         Cursor = Cursors.Default
 
 -         sWatch.Stop()
 
 -         mTimeDouble = sWatch.ElapsedMilliseconds * 0.001
 
 -         lblTimer.Text = lblTimer.Text & mTimeDouble.ToString & " sec."
 
 -         lblLoop.Text = ""
 
 -     End Sub
 
  
-     ' / -------------------------------------------------------------------------------------------------
 
 -     Private Sub txtMaxValue_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtMaxValue.KeyPress
 
 -         '// เมื่อมีการกด Enter
 
 -         If Asc(e.KeyChar) = 13 Then
 
 -             If String.IsNullOrWhiteSpace(txtMaxValue.Text) AndAlso Not Char.IsControl(e.KeyChar) Then
 
 -                 e.Handled = True
 
 -             Else
 
 -                 '// ไปประมวลผล
 
 -                 Call btnNestedLoop_Click(sender, e)
 
 -                 e.Handled = True
 
 -             End If
 
 -         ElseIf Not Char.IsDigit(e.KeyChar) AndAlso Not Char.IsControl(e.KeyChar) Then
 
 -             e.Handled = True '// ไม่อนุญาตให้ป้อนค่าที่ไม่ใช่ตัวเลข
 
 -         End If
 
 -     End Sub
 
  
-     Private Sub TextBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
 
 -         '// ป้องกันไม่ให้กดคีย์อะไรลงไปใน TextBox Control.
 
 -         e.Handled = True
 
 -     End Sub
 
  
-     ' / -------------------------------------------------------------------------------------------------
 
 -     ' / Initialized DataGridView Control.
 
 -     ' / -------------------------------------------------------------------------------------------------
 
 -     Private Sub InitializeDataGridView()
 
 -         With DataGridView1
 
 -             .RowHeadersVisible = False ' True
 
 -             .AllowUserToAddRows = False
 
 -             .AllowUserToDeleteRows = False
 
 -             .AllowUserToResizeRows = False
 
 -             .MultiSelect = True ' False
 
 -             .SelectionMode = DataGridViewSelectionMode.FullRowSelect
 
 -             .ReadOnly = True
 
 -             '// Data rows
 
 -             .Font = New Font("Tahoma", 10)
 
 -             .RowTemplate.MinimumHeight = 27
 
 -             .RowTemplate.Height = 27
 
 -             '// Autosize Column
 
 -             .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
 
 -             '// Header
 
 -             With .ColumnHeadersDefaultCellStyle
 
 -                 .BackColor = Color.RoyalBlue
 
 -                 .ForeColor = Color.White
 
 -                 .Font = New Font(DataGridView1.Font, FontStyle.Bold)
 
 -             End With
 
 -         End With
 
 -     End Sub
 
  
-     ' / -------------------------------------------------------------------------------------------------
 
 -     ' / Initialized ListView Control.
 
 -     ' / -------------------------------------------------------------------------------------------------
 
 -     Private Sub InitializeListView()
 
 -         With ListView1
 
 -             .Columns.Clear() '// make sure columns collection is empty.
 
 -             .Items.Clear()
 
 -             .View = View.Details
 
 -             .HeaderStyle = ColumnHeaderStyle.Nonclickable '// set to whatever you need.
 
 -             .GridLines = True
 
 -             .FullRowSelect = True
 
 -             .HideSelection = False
 
 -             .MultiSelect = True 'False
 
 -             '// Add 3 columns
 
 -             .Columns.Add("A")
 
 -             .Columns.Add("B")
 
 -             .Columns.Add("C")
 
 -         End With
 
 -         With ListView1
 
 -             .Columns(0).Width = ListView1.Width \ 3 - 10
 
 -             .Columns(1).Width = ListView1.Width \ 3 - 10
 
 -             .Columns(2).Width = ListView1.Width \ 3 - 5
 
 -         End With
 
 -     End Sub
 
  
-     Private Sub frmPythagoras_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
 
 -         Me.Dispose()
 
 -         GC.SuppressFinalize(Me)
 
 -         Application.Exit()
 
 -     End Sub
 
  
-     Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
 
 -         Me.Close()
 
 -     End Sub
 
  
- End Class
 
  คัดลอกไปที่คลิปบอร์ด 
ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่ ...  |   
ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง
คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน  
 
x
 
 
 
 
 |