###### tags: `APCS`
# **課堂練習-找質數**
### **題目解析**
找出從 1 到 N 的所有質數。質數是指除了 1 和其本身以外,沒有其他因數的自然數。這裡給出了兩個版本的程式碼來解決這個問題。
### **解題方向**
* 版本一:使用簡單的雙重迴圈來檢查每個數是否為質數。這種方法的時間複雜度較高,因為對每個數進行了完全的因數檢查。
* 版本二:使用改進的籃子法(Sieve of Eratosthenes),僅檢查可能的質數因數到數字的平方根,提高效率。
* 版本三:使用Eratosthenes sieve method來撰寫,以一個陣列來記錄每個數是否為質數。
### **程式解析**
* 版本一
* 讀取輸入的整數 N。
* 使用雙重迴圈,外層迴圈遍歷從 1 到 N 的所有數字。
* 對於每個數字 i,內層迴圈檢查從 2 到 i 的所有數字,判斷是否為質數。
* 如果 i 是質數,將其加入質數列表。
* 輸出質數列表及程式執行時間。
* 版本二
* 讀取輸入的整數 N。
* 使用雙重迴圈,但內層迴圈僅遍歷從 2 到數字的平方根,提高檢查效率。
* 如果數字 i 是質數,將其加入質數列表。
* 輸出質數列表及程式執行時間。
* 版本三
* 陣列元素a[i]表示i仍然可能是質數。
* 若a[i]=0表示i並非質數。
* 若i確定是質數時,將全部a[k]清除為0,其中k為i的整數倍。
### **完整程式碼**
版本一
```python=
import time
# start
N = int(input())
start_time = time.time()
prime = []
for i in range(1, N+1):
isPrime = True
for j in range(2, i+1):
if i % j == 0 and j != i:
isPrime = False
elif j == i and isPrime == True:
prime.append(i)
print(prime)
end_time = time.time()
print("execution time:", (end_time - start_time), "s")
```
版本二
```python=
import time
import math
# start
N = int(input())
start_time = time.time()
prime = []
for i in range(2, N+1):
isPrime = True
end = int(math.sqrt(i))
for j in range(2, end+1):
if i % j == 0:
isPrime = False
break # 提早結束檢查
if isPrime:
prime.append(i)
end_time = time.time()
print(prime)
print("execution time:", (end_time - start_time), "s")
```
版本三
```python=
n = int(input("Enter a number: "))
a = [1] * (n + 1) # 初始化列表,大小為 n+1(包括 0)
for i in range(2, n + 1):
if a[i]: # 如果 a[i] 為 1,則表示 i 是質數
print(i, end=' ') # 輸出質數
k = i * i # 從 i 的平方開始標記
while k <= n:
a[k] = 0 # 將 i 的倍數標記為非質數
k += i
print()
```
### 詳細解析
版本一
* N = int(input()):讀取輸入的整數 N。
* start_time = time.time():記錄程式開始執行時間。
* prime = []:初始化存儲質數的列表。
* for i in range(1, N+1)::遍歷 1 到 N 的所有數字。
* isPrime = True:假設數字 i 是質數。
* for j in range(2, i+1)::檢查從 2 到 i 的所有數字。
* if i % j == 0 and j != i::如果 i 可以被 j 整除且 j 不是 i 本身,則 i 不是質數。
* elif j == i and isPrime == True::如果內層迴圈到達 i 且 isPrime 仍為 True,則 i 是質數,將其加入列表。
* print(prime):輸出質數列表。
* end_time = time.time():記錄程式結束執行時間。
* print("execution time:", (end_time - start_time), "s"):輸出程式執行時間。
版本二
* N = int(input()):讀取輸入的整數 N。
* start_time = time.time():記錄程式開始執行時間。
* prime = []:初始化存儲質數的列表。
* for i in range(2, N+1)::遍歷 2 到 N 的所有數字。
* isPrime = True:假設數字 i 是質數。
* end = int(math.sqrt(i)):計算數字 i 的平方根。
* for j in range(2, end+1)::檢查從 2 到 i 平方根的所有數字。
* if i % j == 0::如果 i 可以被 j 整除,則 i 不是質數,設置 isPrime = False 並提早結束檢查。
* if isPrime::如果 isPrime 仍為 True,則 i 是質數,將其加入列表。
* end_time = time.time():記錄程式結束執行時間。
* print(prime):輸出質數列表。
* print("execution time:", (end_time - start_time), "s"):輸出程式執行時間。
版本三
* n = int(input("Enter a number: ")):讀取輸入的整數 𝑛。
* a = [1] * (n + 1):初始化列表 a,大小為 𝑛 + 1 ,所有元素設為 1。
* 這裡 a[i] 表示數字 𝑖 是否為質數,初始假設所有數字都是質數。
* for i in range(2, n + 1):從 2 開始遍歷到 𝑛 。
* if a[i]:如果 a[i] 為 1,表示 𝑖 是質數。
* print(i, end=' '):輸出質數 𝑖 。
* k = i * i:從 𝑖 的平方開始標記 𝑖 的倍數。
* while k <= n:迴圈從 𝑘(即 𝑖 的平方)開始標記到 𝑛。
* a[k] = 0:將 𝑖 的倍數標記為非質數。
* k += i:移動到下一個倍數。
* 最後,所有 a[i] 仍為 1 的位置即為質數。