380 likes | 787 Views
418115: การโปรแกรมโครงสร้าง คำสั่ง while (2). ประมุข ขันเงิน pramook@gmail.com. โปรแกรมเช็คจำนวนเฉพาะ. ให้ผู้ใช้ป้อนจำนวนเต็มบวกมาหนึ่งตัว แล้วบอกว่ามันเป็นจำนวนเฉพาะหรือไม่ Enter n: 2 2 is a prime number. Enter n: 7 7 is a prime number. Enter n: 6 6 is not a prime number.
E N D
418115: การโปรแกรมโครงสร้างคำสั่ง while (2) ประมุข ขันเงิน pramook@gmail.com
โปรแกรมเช็คจำนวนเฉพาะโปรแกรมเช็คจำนวนเฉพาะ • ให้ผู้ใช้ป้อนจำนวนเต็มบวกมาหนึ่งตัว • แล้วบอกว่ามันเป็นจำนวนเฉพาะหรือไม่ Enter n: 2 2 is a prime number. Enter n: 7 7 is a prime number. Enter n: 6 6 is not a prime number.
จำนวนเฉพาะ • จำนวนเฉพาะคืออะไร? • จำนวนเต็มบวก (ฉะนั้นไม่นับ 0 หรือจำนวนเต็มลบ) • ไม่ใช่จำนวนเต็มลบ • แยกตัวประกอบไม่ได้ • กล่าวคือ จำนวนเต็มบวกที่หารมันลงตัวมีเพียงแค่สองตัว คือ 1 กับตัวมันเอง • เช็คว่าจำนวนเป็นจำนวนเฉพาะได้อย่างไร? • สมมติว่าจำนวนที่เราต้องการเช็คคือ n • จำนวนที่หารมันได้มีแค่สองตัวคือ 1 กับ n • ดังนั้น 2, 3, 4, …, n-1 ต้องหารมันไม่ลงตัว • ฉะนั้นเราเช็ค 2, 3, 4, …, n-1 ทีละตัวว่าหาร n ลงตัวหรือไม่? • มีสักตัวที่หารลงตัว ไม่ใช่จำนวนเฉพาะ • ไม่มีสักตัวที่หารลงตัว เป็นจำนวนเฉพาะ
ออกแบบโปรแกรม • รับ n • ตั้งลูปโดยใช้ k เป็นตัวแปร counter • k มีค่า 2 ถึง n-1 • สำหรับ k แต่ละค่าเช็คว่า n % k == 0 หรือไม่? • ถ้าใช่ ให้จำไว้ว่ามีเลขหารลงตัว • หลังจากลูปเสร็จการทำงาน ให้ไปเช็คว่ามีเลขหารลงตัวหรือไม่ • ถ้าใช่ แสดงว่าไม่เป็นจำนวนเฉพาะ • ถ้าไม่ใช่ แสดงว่าเป็นจำนวนเฉพาะ
ลูป intis_prime=1; intk=2; while(k<n) { if(n%k==0) is_prime=0; k++; }
ทั้งโปรแกรม #include <stdio.h> intmain() { intn; printf("Enter n: "); scanf("&d",&n); intis_prime=1; intk=2; while(k<n){ if(n%k==0) is_prime=0; k++; } if(is_prime&&n!=1) printf("%d is a prime number.\n",n); else printf("%d is not a prime number.\n",n); return0; }
คำสั่ง break • เคยเจอมาแล้วในคำสั่ง switch • สามารถใส่ไว้ตรงในก็ได้ในส่วนที่เป็นคำสั่งที่ต้องการวนซ้ำใน คำสั่ง while • เมื่อเจอคำสั่ง break แล้วลูป while จะเลิกการทำงานทันที • มักใช้ควบคู่กับคำสั่ง if เสมอ
โปรแกรมเช็คจำนวนเฉพาะโปรแกรมเช็คจำนวนเฉพาะ • เราไม่จำเป็นต้องให้ k มีค่าตั้งแต่ 2 ถึง n-1 เสมอ • ถ้ามีเลขสักตัวหารลงตัว แสดงว่าไม่ใช่จำนวนเฉพาะแล้วดังนั้นไม่มีความจำเป็นต้องเช็คจำนวนอื่นอีก • เราต้องการหยุดการทำงานของลูปทันทีที่ n%k == 0 • สามารถใช้คำสั่ง break ได้ในกรณีนี้
ลูปใหม่ที่เร็วขึ้น intis_prime=1; intk=2; while(k<n) { if(n%k==0) { is_prime=0; break; } k++; }
โปรแกรมสำหรับแยกตัวประกอบโปรแกรมสำหรับแยกตัวประกอบ • รับจำนวนเต็มหนึ่งตัวจากผู้ใช้ • แยกตัวประกอบของจำนวนเต็มที่ผู้ใช้ให้มา Enter a positive integer: 128 128 = 2 * 2 * 2 * 2 * 2 * 2 * 2 Enter a positive integer: 365 365 = 5 * 73 Enter a positive integer: 97 97 = 97
การแยกตัวประกอบ • แยกตัวประกอบคืออะไร? • การเขียนจำนวนเต็มอยู่ในรูปผลคูณของจำนวนเฉพาะ • ทำอย่างไรดีถึงจะแยกได้ • สมมติว่าเลขที่เราต้องการจะแยกตัวประกอบคือ n • สมมติให้ n > 1 (กรณี n = 1 ไม่มีอะไร) • หาจำนวนเฉพาะมาสักตัวที่หาร n ลงตัว • สมมติว่าจำนวนเฉพาะนี้คือ p • ถ้าจำนวนเฉพาะนั้นหาร n ลงตัว เราก็พิมพ์มัน • แล้วลบมันออกจากตัวประกอบของ n ด้วยการสั่ง n = n/p
การแยกตัวประกอบ • 48 • หาร 2 ลงตัว • 48 24 • 24 • หาร 2 ลงตัว • 24 12 • 12 • หาร 2 ลงตัว • 12 6 • 6 • หาร 2 ลงตัว • 6 3 • 3 • หาร 3 ลงตัว • 3 1 • จบการทำงาน
หาจำนวนเฉพาะที่หาร n ลงตัว • สมมติว่า n > 1 • ลองเปลี่ยนคำถามเป็นว่า “จำนวนเฉพาะที่น้อยที่สุดที่หาร n ลงตัวคืออะไร?” • สังเกต คำถามนี้มีคำตอบเดียวกับคำถามที่ว่า“จำนวนที่น้อยที่สุดที่มากกว่า 1 ที่หาร n ลงตัวคืออะไร?”
หาจำนวนเฉพาะที่หาร n ลงตัว • ทำไม? • สมมติว่า m เป็นจำนวนที่น้อยที่สุดที่มากกว่า 1 ที่หาร n ลงตัว • สมมติอีกว่า m ไม่ใช่จำนวนเฉพาะ • แสดงว่า m ตัวแยกตัวประกอบได้ สมมติให้ p เป็นจำนวนเฉพาะที่หาร m ลงตัว • เรารู้ว่า p < m และ p > 1 • แต่ p ก็หาร n ลงตัว • ฉะนั้น m ไม่ใช่จำนวนที่น้อยที่สุดที่มากกว่า 1 ที่หาร n ลงตัว • เกิดข้อขัดแย้ง
หาจำนวนเฉพาะที่หาร n ลงตัว • หาจำนวนเฉพาะที่น้อยที่สุดที่หาร n ลงตัวคือการหาจำนวนที่มากกว่า 1 ที่น้อยที่สุดที่หาร n ลงตัว • หาอย่างไร? • เริ่มจาก p = 2 • เช็คว่า n%p == 0 หรือไม่? • ถ้าใช่ก็จบ • ถ้าไม่ใช่ก็เพิ่มค่า p ขึ้นหนึ่ง
หาจำนวนเฉพาะที่หาร n ลงตัว intp=2; while(n%p!=0) p++;
ลูป • หา p หนึ่งตัวที่หาร n ลงตัว • พิมพ์ p • ลบ p ออกจากความเป็นตัวประกอบของ n • n = n/p • หยุดเมื่อไหร่? • n == 1
ลูป printf("%d = ",n); while(n>1) { intp=2; while(n%p!=0) p++; if(n/p==1) printf("%d\n",p); else printf("%d * ",p); n=n/p; }
ทั้งโปรแกรม #include <stdio.h> intmain() { intn; printf("Enter a positive integer: "); scanf("&d",&n); if(n==1) printf("1 = 1\n"); else{ printf("%d = ",n); while(n>1){ intp=2; while(n%p!=0) p++; if(n/p==1) printf("%d\n",p); else printf("%d * ",p); n=n/p; } } return0; }
เลขพาลินโดรม • เลขพาลินโดรมคือเลขที่เขียนจากหลังไปหน้าแล้วมีค่าเท่าเดิม • เช่น 12321 เป็นเลขพาลินโดรม • แต่ 123 ไม่ใช่ เพราะ 123 ไม่เท่ากับ 321 • สังเกตว่าเลขพาลินโดรมจะต่อท้ายด้วย 0 ไม่ได้
โปรแกรมตรวจสอบเลขพาลินโดรมโปรแกรมตรวจสอบเลขพาลินโดรม • อ่านจำนวนเต็มบวกจากผู้ใช้หนึ่งตัว • ชนิด int • ไม่เกิน 6 หลัก • แล้วบอกว่าเลขนั้นเป็นพาลินโดรมหรือไม่ Enter n: 12321 12321 is a palindrome Enter n: 4567 4567 is not a palindrome
ออกแบบโปรแกรม • พาลินโดรมคืออะไร? • เขียนกลับหลังแล้วได้ตัวเติม • จะทดสอบพาลินโดรมอย่างไร? • ก็ลองเขียนกลับหลังดูแล้วเทียบว่าเท่ากับตัวเดิมหรือไม่
เขียนกลับหลัง • สมมติว่ามีเลข n =123456 • สามารถเขียนกลับหลังโดยการมีเลขอีก 1 ตัว ตอนแรกเป็น 0 • กระบวนการ • n = 123456 m = 0 • n = 12345 m = 6 • n = 1234 m = 65 • n = 123 m = 654 • n = 12 m = 6543 • n = 1 m = 65432 • n = 0 m = 654321
เขียนกลับหลัง • ในแต่ละขั้น • ดึงตัวหลังของ n ออกมา • เอาตัวหลังของ n ไปต่อท้าย m • ลบตัวหลังออกจาก n • กล่าวคือ intd=n%10; n=n/10; m=m*10+d; • หยุดเมื่อใด? • เมื่อ n = 0
เขียนกลับหลัง intm=0; while(n>0) { intd=n%10; n=n/10; m=m*10+d; }
ทั้งโปรแกรม #include <stdio.h> intmain() { intn; printf("Enter n: "); scanf("%d",&n); intnn=n; intm=0; while(n>0){ intd=n%10; n=n/10; m=m*10+d; } if(m==nn) printf("%d is a palindrome\n",nn); else printf("%d is not a palindrome\n",nn); return0; }
คำถาม • ในจำนวนเต็มตั้งแต่ 1 ถึง 1,000,000 มีจำนวนเต็มกี่ตัวที่เป็นทั้ง • จำนวนเฉพาะ และ • พาลินโดรม? • จำนวนเต็มเหล่านั้นคืออะไรบ้าง?
ออกแบบโปรแกรม • เรารู้วิธีเช็คพาลินโดรม • เรารู้วิธีเช็คจำนวนเฉพาะ • ฉะนั้นเอาจำนวนเต็มมาทีละตัวแล้วเช็คว่ามันเป็นทั้งสองอย่างหรือไม่ • แล้วก็นับจำนวนที่ใช่
ลูป intn=2; while(n<=999999) { [ตรวจว่า n เป็นพาลินโดรมหรือไม่] [ตรวจว่า n เป็นจำนวนเฉพาะหรือไม่] [ถ้าใช่ทั้งคู่พิมพ์ n] }
ลูป (ฉบับเต็ม) intn=2; while(n<=999999){ intm=0; intnn=n; while(nn>0){ intd=nn%10; nn=nn/10; m=m*10+d; } intis_palindrome=(m==n); intis_prime=1; intk=2; while(k<n){ if(n%k==0){ is_prime=0; break; } k++; } if(is_palindrome&&is_prime) printf("%d\n",n); n++; }
ปัญหา • มันช้า • ทำไม? • การเช็คจำนวนเฉพาะ • ถ้าจะเช็คว่า 983,139 เป็นจำนวนเฉพาะหรือไม่จะต้องวนรอบทั้งหมดกี่รอบ? • อาจจะถึง 983,137 รอบ! • ฉะนั้นกรณีเลวสุดโปรแกรมจะต้องวนรอบประมาณ 1,000,000 * 1,000,000 (แต่ความจริงน้อยกว่านี้มาก)
ทำให้มันเร็วขึ้น? • การเช็คจำนวนเฉพาะช้า • ต้องพยายามหลีกเลี่ยง • เราสนใจเฉพาะเลขที่เป็นทั้งพาลินโดรมและจำนวนเฉพาะ • ดังนั้นถ้าเลขใดไม่เป็นพาลินโดรมแล้วเราก็ไม่ต้องไปเช็คว่ามันเป็นจำนวนเฉพาะก็ได้
คำสั่ง continue • เมื่อสั่งแล้วจะไปเริ่มต้นลูปใหม่อีกครั้งหนึ่ง • ข้ามคำสั่งส่วนที่เหลือของลูปไป • มักใช้ควบคู่กับคำสั่ง if
หลีกเลี่ยงการเช็คจำนวนเฉพาะหลีกเลี่ยงการเช็คจำนวนเฉพาะ intn=2; while(n<=999999){ intm=0; intnn=n; while(nn>0){ intd=nn%10; nn=nn/10; m=m*10+d; } intis_palindrome=(m==n); if(!is_palindrome){ n++; continue; } intis_prime=1; intk=2; while(k<n){ if(n%k==0) { is_prime=0; break; } k++; } if(is_palindrome&&is_prime) printf("%d\n",n); n++; }