ผลต่างระหว่างรุ่นของ "เกรแฮมสแกน"

เนื้อหาที่ลบ เนื้อหาที่เพิ่ม
Djnoly (คุย | ส่วนร่วม)
Djnoly (คุย | ส่วนร่วม)
บรรทัด 1:
กระบะทรายนี้ ใช้เป็นพื้นที่สร้างบทความ ก่อนจะย้ายไปยังเนมสเปซหลัก
กระบะทรายนี้ ใช้เป็นพื้นที่สร้างบทความ ก่อนจะย้ายไปยังเนมสเปซหลัก
=เกรแฮมสแกน=
'''เกรแฮมสแกน''' ([[ภาษาอังกฤษ|อังกฤษ]]:Graham Scan) เป็น[[ขั้นตอนวิธี]]สำหรับคำนวณหา [[convex hallhull]] ของ[[เซท]]จุดบนระนาบ โดยมี[[ความซับซ้อนด้านเวลา]] (time complexity) เป็น [[สัญกรณ์โอใหญ่|O]](''n'' log ''n'') ชื่อของชั้นตอนวิธีมาจากผู้เผยเพร่ขั้นตอนวิธีต้นฉบับในปี ค.ศ.1972
 
==ขั้นตอนวิธี==
ขั้นตอนวิธีเริ่มจากจุดที่มีคู่อันดับ y ต่ำสุด หากพบจุดที่มีคู่อันดับ y ต่ำสุดมากกว่าหนึ่งจุด ให้เลือกจุดที่มีคู่อันดับ x ต่ำสุดในกลุ่มนั้น เรียกจุดนี้ว่าจุด ''P'' ขั้นตอนนี้ใช้เวลา O(''n'') โดยที่ ''n'' คือจำนวนของจุดทั้งหมด
 
ถัดมา เรียงลำดับจุดที่เหลือตามมุมที่จุด ''P'' และจุดนั้นๆกระทำกับแกน x โดยเรียงจากน้อยไปหามาก การเรียงลำดับสามารถใช้ขั้นตอนวิธีแบบใดก็ได้ เช่น การเรียงลำดับโดยใช้[[ฮีป]] (ใช้เวลา O(''n'' log ''n'')) เพื่อความรวดเร็วในการคำนวณ ไม่จำเป็นต้องหาค่าองศาของมุมระหว่างแกน x และเส้นจากจุด ''P'' ไปยังจุดหนึ่งๆ เพื่อนำมาเรียงลำดับ สามารถใช้ค่า [[โคไซน์]] ของมุม ซึ่งในปัญหา convex hallhull จะเป็นฟังก์ชันลดทางเดียว (monotonically decresing funcion) มีค่าระหว่าง 0 ถึง 180 องศา ซึ่งสามารถคำนวณได้จาก[[คณิตศาสตร์]]อย่างง่าย
 
จากนั้น พิจารณาแต่ละจุดตามลำดับที่เรียงไว้ โดยพิจารณาจากจุดนั้นๆร่วมกับก่อนหน้าสองจุด ว่าการเลือกจุดถัดไปนั้นเป็นการ "เลี้ยวขวา" หรือ "เลี้ยวซ้าย" หากเป็นการ "เลี้ยวขวา" หมายความว่าจุดก่อนหน้าตรงกลางไม่เป็นส่วนหนึ่งของผนัง convex hallhull และจะไม่นำมาพิจารณาอีก การพิจารณาในขั้นตอนนี้ดำเนินต่อไปเรื่อยๆ จนกระทั่งพบการ "เลี้ยวซ้าย" ซึ่งหมายความว่า จุดตรงกลางคือส่วนหนึ่งของผนัง convex hull จึงพิจารณาจุดถัดไป (หากระหว่างการพิจารณาพบเส้นทางตรงซึ่งไม่มีการเลี้ยว อาจรวม หรือ ไม่รวม จุดนั้นในเซตคำตอบ ขึ้นกับปัญหา เนื่องจากการนำไปใช้บางสถานการณ์จำเป็นต้องรวมทุกจุดบนผนัง convex hallhull ลงไปในคำตอบ)
 
เช่นเดียวกับก่อนหน้าการเรียงลำดับจุดตามมุมในขั้นตอนที่สอง การพิจารณาจุดสามจุดว่าเป็นการ "เลี้ยวขวา" หรือ "เลี้ยวซ้าย" ไม่จำเป็นต้องคำนาณองศาของระหว่างเส้นสองเส้น แต่สามารถคำนาณจากคณิตศาสตร์อย่างง่าย สำหรับจุดสามจุด <math>(x_1,y_1)</math>, <math>(x_2,y_2)</math> และ <math>(x_3,y_3)</math> นั้น สามารถคำนาณหาทิศทางของผลลัพท์จากการครอสเวกเตอร์ลัพท์จากการครอสส์เวกเตอร์ <math>((x_1,y_1),(x_2,y_2))</math> และ <math>((x_1,y_1),(x_3,y_3))</math> ซึ่งคำราณได้จากเครื่องหมายของ[[นิพจน์]] <math>(x_2 - x_1)(y_3 - y_1) - (y_2 - y_1)(x_3 - x_1)</math> หากผลลัพท์เป็น 0 แสดงว่าจุดสามจุดเรียงกันเป็นเส้นตรง หากผลลัพท์เป็นบวก แสดงจุดทั้งสามทำให้เกิดการ "เลี้ยวซ้าย" และหากผลลัพท์เป็นลบ แสดงว่าเกิดการ "เลี้ยวขวา"
 
สุดท้าย กระบวนการจะวนกลับมายังจุดเริ่มต้น ทำให้เสร็จสิ้นขั้นตอนวิธี ได้ผลลัพธ์เป็นจุดที่อยู่บนผนัง convex hallhull เรียงตามลำดับทวนเข็มนาฬิกาจากจุด ''P''
 
==ความซับซ้อนด้านเวลา==
การเรียงลำดับจุดทั้งหมดมีความซับซ้อนด้านเวลาเป็น O(''n'' log ''n'') ส่วนการทำงานในวงวนตรวจสอบว่าการเลือกจุดถัดไปเป็นการ "เลี้ยวขวา" หรือ "เลี้ยวซ้าย" ใช้เวลาเพียง O(''n'') เนื่องจากจุดใดๆจะนำมาตรวจสอบเพียงสองครั้ง หากตรวจสอบแล้วพบว่าเป็นจุด <math>(x_2,y_2)</math> ในการ "เลี้ยวซ้าย" ขั้นตอนวิธีจะดำเนินต่อไปยังจุด <math>(x_3,y_3)</math> และถ้าหากพบว่าเป็นจุด <math>(x_2,y_2)</math> ในการเลี้ยวขวา จุดนั้นก็จะไม่ถูกนำมาพิจารณาอีก ดังนั้น เกรแฮมสแกน มีความซับซ้อนทางเวลาเป็น O(''n'' log ''n'') ตามการเรียงลำดับจุด ซึ่งใช้เวลามากที่สุดในขั้นตอนวิธี
 
==รหัสเทียม==
อันดับแรก ฟังก์ชั่นคำนวนการ "เลี้ยวขวา" และ "เลี้ยวซ้าย"
# ''Three points are a counter-clockwise turn if ccw > 0, clockwise if''
# ''ccw < 0, and collinear if ccw = 0 because ccw is a determinant that''
# ''gives the signed area of the triangle formed by p1, p2 and p3.''
'''function''' ccw(p1, p2, p3):
'''return''' (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
 
และให้คำตอบอยู่ในตาราง <code> points </code>
 
'''let''' N = number of points
'''let''' points[N+1] = the array of points
'''swap''' points[1] with the point with the lowest y-coordinate
'''sort''' points by polar angle with points[1]
# ''We want points[0] to be a sentinel point that will stop the loop.''
'''let''' points[0] = points[N]
# ''M will denote the number of points on the convex hull.''
'''let''' M = 2
'''for''' i = 3 '''to''' N:
# ''Find next valid point on convex hull.''
'''while''' '''ccw'''(points[M-1], points[M], points[i]) <= 0:
# ''Check if first points are collinear, if so ignore unnecessary points.''
'''if''' M is 2:
'''swap''' points[M] with points[i]
i += 1
'''else'''
M -= 1
# ''Update M and swap points[i] to the correct place.''
M += 1
'''swap''' points[M] with points[i]
 
รหัสเทียมนี้ปรับปรุงจากตำรา ''Algorithms, 4th edition'' โดย Sedgewick and Wayne
 
==อ้างอิง==