《程式設計珠璣》程式碼之路14:兩個不會演算法也能把效率提升4倍的小套路

心理學演算法工程師發表於2018-11-27

現在我們假設要在沒排序的陣列中找一個數:

菜狗也能寫出如下的演算法1:

找到了我就返回位置,否則我就返回-1。

int search1(){
	for (int i = 0; i < MAXN; ++i){
		if (nums[i] == VALUE){
			return i;
		}
	}
	return -1;
}

現在問題來了,演算法效率差一點點,入股能優化8%那就可以用了,怎麼辦?

大家也許還記得,比較運算子是非常耗時的,我們如果不用比較運算子,同樣的線性演算法,也許有可能有些優化,多少呢?

我實現了一下,8%左右問題不大,程式碼附在後面,search2()。

那萬一還不行,依舊是這個演算法,我們要做到之前時間的3分之一,怎麼辦?

別急別急,法子簡單的很,就是把++i去掉,把中間的部分手寫8次,然後每次i+=8你還真別不信,我實現之後,耗時只有之前的四分之一左右!!!!!。程式碼附在後面search3中。

為啥呢?因為將迴圈展開有助於避免管道阻塞,減少分支,增加指令級的並行性。下面是實驗結果:

time1=0.075000
time2=0.069000
優化= 8%
time3=0.021000
優化= 72%
[Finished in 1.4s]

完整程式碼如下:

#include <iostream>
#include <cstdio>
#include <ctime>

using namespace std;

int nums[51000000];
const int POSITION = 40000000;
const int MAXN = 50000000;
const int VALUE = 2;

int search1();
int search2();
int search3();

clock_t start, end;

int main(){

	for (int i = 0; i < MAXN; ++i){
		nums[i] = 1;
	}
	nums[POSITION] = 2;

	start = clock();
	search1();
	end = clock();
	double time1 = (double)(end-start)/CLK_TCK;
	printf("time=%f\n",(double)(end-start)/CLK_TCK);

	start = end = 0;
	start = clock();
	search2();
	end = clock();
	double time2 = (double)(end-start)/CLK_TCK;
	printf("time=%f\n",(double)(end-start)/CLK_TCK);

	cout << (time1 - time2) / time1 * 100 << endl;

	start = clock();
	search3();
	end = clock();
	double time3 = (double)(end-start)/CLK_TCK;
	printf("time=%f\n",(double)(end-start)/CLK_TCK);

	cout << (time1 - time3) / time1 * 100 << endl;
	return 0;
}

int search1(){

	for (int i = 0; i < MAXN; ++i){
		if (nums[i] == VALUE){
			return i;
		}
	}

	return -1;
}

int search2(){

	int hold = nums[MAXN -1];
	nums[MAXN - 1] = INT_MAX;

	int i;
	for (i = 0; ; i += 1){
		if (nums[i] == VALUE){
			break;
		}
	}
	nums[MAXN - 1] = hold;

	if (i == MAXN - 1){
		return -1;
	}

	return i;
}

int search3(){
	int hold = nums[MAXN -1];
	nums[MAXN - 1] = INT_MAX;

	int i;
	for (i = 0; ; i += 8){
		if (nums[i] == VALUE){ 
			break;
		}
		if (nums[i + 1] == VALUE){
			i += 1;
			break;
		}
		if (nums[i + 2] == VALUE){
			i += 2;
			break;
		}
		if (nums[i + 3] == VALUE){
			i += 3;
			break;
		}
		if (nums[i + 4] == VALUE){
			i += 4;
			break;
		}
		if (nums[i + 5] == VALUE){
			i += 5;
			break;
		}	
		if (nums[i + 6] == VALUE){
			i += 6;
			break;
		}
		if (nums[i + 7] == VALUE){
			i += 7;
			break;
		}										
	}
	nums[MAXN - 1] = hold;

	if (i == MAXN - 1){
		return -1;
	}

	return i;
}

 

相關文章