演算法前導

更新於 發佈於 閱讀時間約 6 分鐘

舉例介紹

寫同樣的一段程式碼,別人的code卻比自己寫的code還要有效率,也就是跑得更快,為什麼呢?

其根本原因很可能出在演算法的問題上。

找出所有質數(Prime Numbers) 為例,不同的演算法效率差異巨大。

以暴力解法來看:

#include <stdio.h>
#include <math.h>

// 判斷 n 是否為質數
int isPrime(int n) {
if (n < 2) return 0;
for (int i = 2; i < n; i++) {
if (n % i == 0)
return 0;
}
return 1;
}

// 找出範圍內所有質數
void findPrimes(int limit) {
for (int i = 2; i <= limit; i++) {
if (isPrime(i))
printf("%d ", i);
}
printf("\n");
}

int main() {
int limit = 100;
findPrimes(limit);
return 0;
}
  • 我們運行一個由 2 到 n 之間的迴圈,並對迴圈的每個值,判斷它是不是質數。

其實,有更快的檢查方法,我們透過將程式碼改為for (int i = 2; i <= sqrt(n); i++)可以優化整個程式的速度,尤其是範圍很大時。

#include <stdio.h>
#include <math.h>

// 判斷 n 是否為質數
int isPrime(int n) {
if (n < 2) return 0;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0)
return 0;
}
return 1;
}

// 找出範圍內所有質數
void findPrimes(int limit) {
for (int i = 2; i <= limit; i++) {
if (isPrime(i))
printf("%d ", i);
}
printf("\n");
}

int main() {
int limit = 100;
findPrimes(limit);
return 0;
}

for (int i = 2; i <= sqrt(n); i++) 這種方法比 for (int i = 2; i < n; i++) 更快的根本原因在於:

  • 如果 n 有因數,那麼它的最小因數必定小於等於 sqrt(n)
  • 超過 sqrt(n) 之後,所有的因數都是前面已經找到的因數的對應乘積,所以不需要再檢查。

舉例(n = 36):

所有的因數對:

(1, 36)
(2, 18)
(3, 12)
(4, 9)
(6, 6) <-- √36 = 6,之後開始重複
(9, 4) <-- 重複
(12, 3) <-- 重複
(18, 2) <-- 重複
(36, 1) <-- 重複

觀察發現,當 i > 6 (sqrt(36) = 6) 之後,我們只是在重複檢查已經出現過的因數對,所以沒必要再繼續檢查!

只要檢查到 sqrt(n),就能找到所有因數,沒必要再繼續迴圈。

  • 另外補充一點,你也可以將程式碼寫為for (int i = 2; i * i <= n; i++),其概念相同。

差異測試

如果我們要測試兩個程式碼執行時間上的差異,這個程式碼可以幫助我們:

#include <stdio.h>
#include <math.h>
#include <time.h>

// 方法 1:暴力法
int isPrimeBruteForce(int n) {
if (n < 2) return 0;
for (int i = 2; i < n; i++) {
if (n % i == 0)
return 0;
}
return 1;
}

// 方法 2:sqrt(n) 優化
int isPrimeOptimized(int n) {
if (n < 2) return 0;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0)
return 0;
}
return 1;
}

int main() {
int limit = 1000000;
clock_t start, end;
double time_used;

// 測試暴力法
start = clock();
for (int i = 2; i <= limit; i++)
isPrimeBruteForce(i);
end = clock();
time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("暴力法耗時: %.6f 秒\n", time_used);

// 測試 sqrt(n) 優化
start = clock();
for (int i = 2; i <= limit; i++)
isPrimeOptimized(i);
end = clock();
time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("sqrt(n) 優化耗時: %.6f 秒\n", time_used);

return 0;
}

輸出:

暴力法耗時: 76.019764
sqrt(n) 優化耗時: 0.276063

總結來說,演算法是一組明確的步驟(指令),用來解決特定問題。其本質為解決問題的方法。

而好的演算法可以讓程式執行更快,這也是我們所追求的。

留言
avatar-img
留言分享你的想法!
avatar-img
電資鼠 - 您的學習好夥伴
11會員
215內容數
在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
2025/03/09
雙向串列 (Double Linked List, DLL) 是一種鏈結資料結構,本章節將以完整註解,搭配關鍵操作地方的圖示輔助學習,讓你輕鬆搞懂複雜觀念,並透過C語言實作。
Thumbnail
2025/03/09
雙向串列 (Double Linked List, DLL) 是一種鏈結資料結構,本章節將以完整註解,搭配關鍵操作地方的圖示輔助學習,讓你輕鬆搞懂複雜觀念,並透過C語言實作。
Thumbnail
2025/03/08
環狀鏈結串列是一種特殊的鏈結串列,其最後一個節點的指標指向第一個節點,而非 NULL,形成一個循環結構。本章節將以豐富圖示,引導讀者了解環狀串列在各種地方執行插入和刪除節點的步驟,輕鬆學會資工科的專業知識-環狀串列。
Thumbnail
2025/03/08
環狀鏈結串列是一種特殊的鏈結串列,其最後一個節點的指標指向第一個節點,而非 NULL,形成一個循環結構。本章節將以豐富圖示,引導讀者了解環狀串列在各種地方執行插入和刪除節點的步驟,輕鬆學會資工科的專業知識-環狀串列。
Thumbnail
2025/03/07
本章節將探討右上三角稀疏矩陣。
Thumbnail
2025/03/07
本章節將探討右上三角稀疏矩陣。
Thumbnail
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元二次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
中學數學基礎練習—一元一次方程式
Thumbnail
高中數學主題練習—對數方程式
Thumbnail
高中數學主題練習—對數方程式
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News