應用:假設一個亂序數組,需要尋找一個元素是否在該數組中,這時需要用到順序尋找,也就是遍曆數組。
一般情況下我們會寫下如下代碼:
int Sequential_Search(int *a,int n,int key){//數組從1開始int i;for(int i=1;i<=n;i++){if(a[i]==key)return i;}return 0;//尋找失敗}
有的資料結構書上,會運用哨兵元素,改成這樣的代碼:
int Sequential_Search2(int *a int n,int key){int i=0;a[0]=key;//哨兵i=n;while(a[i]!=key){i--;}return i;//返回0就是尋找失敗}
仔細看來沒有什麼差別,但是來看下我測試的已耗用時間,數組有10億個元素。
方案1:3.494s 3.202s 3.216s 3.237s
方案2:2.332s 2.307s 2.24s 2.194s
為什麼基本一樣的代碼,方案2比方案1效能提升了30%~40%左右???
迴圈中,方案1有3條指令而方案2有兩條指令,少了i<n這個比較操作,所以方案2效能得到了提升,這也是哨兵元素的妙用
以上思想和代碼來自於《大話資料結構》中的296頁,測試實驗是我做的。
大話資料結構的原文“這種尋找方法在尋找方向的盡頭設定哨兵元素,免去了尋找過程中每次比較後都要判斷尋找位置是否越界的小技巧,看似與原先差別不大,但是總資料較多時,效率提高很明顯,是非常好的編程技巧。當然,“哨兵”也不一定在數組開始,也可以再末尾”
我的測試程式:
void main() { int num=1000000000;char *p=new char[num];p[0]=2;char key=p[0];clock_t start, finish; start=clock();if(true){for(int i=1;i<num;i++){if(p[i]==key)break;}}else{int i=num-1;while(p[i]!=key){i--;}}finish=clock();double Total_time = (double)(finish-start) / CLOCKS_PER_SEC; cout<<Total_time<<endl;}