写出高效的代码是每个程序员都想要掌握的技能之一,特别是对于全能编程开发工程师来说更加重要。在这篇文章中,我们将从多个方面来讲述如何写出高效的代码。
一、选择合适的数据结构和算法
在编写代码的时候,我们需要根据具体问题选择合适的数据结构和算法。例如,对于需要频繁插入和删除的数据集合,使用链表比使用数组更加高效;而对于需要进行排序和查找的算法问题,选择合适的排序算法和查找算法也可以提高代码效率。
下面是一段计算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/n/188361.html
微信扫一扫
支付宝扫一扫