如何寫出高效的代碼?- 從一個全能編程開發工程師的角度

寫出高效的代碼是每個程序員都想要掌握的技能之一,特別是對於全能編程開發工程師來說更加重要。在這篇文章中,我們將從多個方面來講述如何寫出高效的代碼。

一、選擇合適的數據結構和演算法

在編寫代碼的時候,我們需要根據具體問題選擇合適的數據結構和演算法。例如,對於需要頻繁插入和刪除的數據集合,使用鏈表比使用數組更加高效;而對於需要進行排序和查找的演算法問題,選擇合適的排序演算法和查找演算法也可以提高代碼效率。

下面是一段計算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-tw/n/188361.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-28 13:29
下一篇 2024-11-28 13:29

相關推薦

發表回復

登錄後才能評論