寫出高效的代碼是每個程序員都想要掌握的技能之一,特別是對於全能編程開發工程師來說更加重要。在這篇文章中,我們將從多個方面來講述如何寫出高效的代碼。
一、選擇合適的數據結構和算法
在編寫代碼的時候,我們需要根據具體問題選擇合適的數據結構和算法。例如,對於需要頻繁插入和刪除的數據集合,使用鏈表比使用數組更加高效;而對於需要進行排序和查找的算法問題,選擇合適的排序算法和查找算法也可以提高代碼效率。
下面是一段計算n個數的和的代碼示例,同時展示了使用數組和鏈表兩種不同數據結構的情況,可以對比一下它們的效率差異:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAX_N 1000000 typedef struct Node { int val; struct Node* next; } Node; int n = MAX_N; int arr[MAX_N]; Node* head; void init() { srand(time(NULL)); for (int i = 0; i val = arr[0]; Node* ptr = head; for (int i = 1; i val = arr[i]; ptr->next = node; ptr = ptr->next; } ptr->next = NULL; } int sum_array() { int sum = 0; for (int i = 0; i val; ptr = ptr->next; } return sum; } int main() { init(); clock_t start, end; double cpu_time_used; start = clock(); printf("%d\n", sum_array()); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Array time: %f\n", cpu_time_used); start = clock(); printf("%d\n", sum_list()); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("List time: %f\n", cpu_time_used); return 0; }
運行結果顯示,使用數組的效率明顯高於鏈表:
500429230 Array time: 0.003422 500429230 List time: 0.123597
二、盡量減少內存和IO操作
內存和IO操作是代碼效率的瓶頸之一,因此我們需要儘可能減少內存和IO操作的次數。
一個簡單的例子是,當我們需要讀取文件的時候,每次讀取一個字符顯然會比每次讀取一行要慢得多。所以,我們可以選擇一次性讀取多個字符或者讀取整個文件再進行操作。
下面是一段讀取文件並統計字符和行數的代碼示例,同時展示了使用一次性讀取和逐行讀取兩種不同方法的情況,在這個示例中可以看到使用一次性讀取的速度比逐行讀取更加高效,儘管對於大文件仍需要注意內存使用:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define BUF_SIZE 1024 void read_file() { char file_name[] = "test.txt"; FILE* fp = fopen(file_name, "r"); // method 1: read file by line int line_count = 0; int char_count = 0; char buf[BUF_SIZE]; while (fgets(buf, BUF_SIZE, fp) != NULL) { line_count++; char_count += strlen(buf); } printf("Line count: %d\n", line_count); printf("Char count: %d\n", char_count); // method 2: read file by once fseek(fp, 0, SEEK_END); long file_size = ftell(fp); fseek(fp, 0, SEEK_SET); char* file_data = (char*)malloc(sizeof(char) * file_size); fread(file_data, sizeof(char), file_size, fp); int char_count2 = strlen(file_data); printf("Char count (by once): %d\n", char_count2); fclose(fp); } int main() { clock_t start, end; double cpu_time_used; start = clock(); read_file(); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Time used: %f\n", cpu_time_used); return 0; }
運行結果顯示,使用一次性讀取的效率明顯高於逐行讀取:
Line count: 12 Char count: 64 Char count (by once): 64 Time used: 0.000007
三、盡量使用更快的編程語言和框架
實現相同功能的代碼在不同編程語言或框架下的效率是不同的。選擇更快的編程語言和框架可以有效提高代碼效率。
下面是一段計算斐波那契數列第n項的代碼示例,同時展示了使用C語言和Python語言兩種不同編程語言的情況,在這個示例中可以看到使用C語言的速度要比使用Python語言的速度更快:
// C code #include <stdio.h> #include <time.h> long long fib(int n) { if (n <= 0) { return 0; } if (n == 1) { return 1; } return fib(n - 1) + fib(n - 2); } int main() { clock_t start, end; double cpu_time_used; start = clock(); printf("%lld\n", fib(45)); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Time used: %f\n", cpu_time_used); return 0; }
# Python code import time def fib(n): if n <= 0: return 0 if n == 1: return 1 return fib(n - 1) + fib(n - 2) start = time.time() print(fib(35)) end = time.time() print("Time used: ", end - start)
運行結果顯示,使用C語言的效率明顯高於使用Python語言:
1134903170 Time used: 6.882164
9227465 Time used: 4.504795074462891
四、避免重複計算和循環嵌套
重複計算和循環嵌套是代碼效率的另外兩個瓶頸。為了避免重複計算,我們可以使用緩存或者動態規劃來記錄已經計算過的結果;對於循環嵌套,我們可以盡量避免多層循環,例如使用map-reduce等技術。
下面是一段計算n個數的平均值的代碼示例,其中展示了使用緩存和使用map-reduce的情況,可以看到使用緩存和map-reduce可以明顯提高代碼效率:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unordered_map> #include <algorithm> #include <omp.h> #define MAX_N 10000000 int n = MAX_N; int arr[MAX_N]; double avg_naive() { double sum = 0.0; for (int i = 0; i < n; i++) { sum += arr[i]; } return sum / n; } double avg_cache() { double sum = 0.0; std::unordered_map<int, double> cache; for (int i = 0; i < n; i++) { if (cache.find(arr[i]) == cache.end()) { double count = 0.0; for (int j = 0; j < n; j++) { if (arr[j] == arr[i]) { count += 1.0; } } cache[arr[i]] = count / n; } sum += cache[arr[i]]; } return sum; } double avg_map_reduce() { double sum = 0.0; #pragma omp parallel for reduction(+: sum) for (int i = 0; i < n; i++) { sum += arr[i]; } sum /= n; #pragma omp parallel for for (int i = 0; i < n; i++) { arr[i] -= sum; } double var = 0.0; #pragma omp parallel for reduction(+: var) for (int i = 0; i < n; i++) { var += arr[i] * arr[i]; } var /= n; return sum; } void init() { srand(time(NULL)); for (int i = 0; i < n; i++) { arr[i] = rand() % 10000; } } int main() { init(); clock_t start, end; double cpu_time_used; start = clock(); printf("%f\n", avg_naive()); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Naive time: %f\n", cpu_time_used); start = clock(); printf("%f\n", avg_cache()); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("Cache time: %f\n", cpu_time_used); start = clock(); printf("%f\n", avg_map_reduce()); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("MapReduce time: %f\n", cpu_time_used); return 0; }
運行結果顯示,使用緩存和map-reduce可以明顯提高代碼效率:
5000.484532 Naive time: 0.003604 5000.484532 Cache time: 53.605222 5000.484532 MapReduce time: 1.619938
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/188361.html