線性表中,先進先出的叫隊列,先進後出的叫棧。隊列常用於BFS,而在函數遞歸層數過高時,需要手動實現遞歸過程,這時候便需要寫一個“手動棧”。
有時候,我們會有大量數據頻繁出入隊列,但同時存在其內的元素卻不多,此時需要寫“循環隊列”。其代碼並不難,但裏面下標遞增的語句值得斟酌一下。
k=(k+1)%maxn;
這句話用到了取模運算%,是非常浪費時間的。若能避免使用%,則可以大大提高代碼運行速度。我做了一個測試,把下面五種語句寫法分別運行5×10^8次,在我的機器上用codeblocks10.05各運行5次,取平均數,時間如下所示:
i=(i==maxn-1)?0:(i+1); // 用時1.582s
if(i==maxn-1) i=0; else ++i; // 用時1.588s
++i; if(i==maxn) i=0; // 用時1.605s
++i; i=(i==maxn)?0:i; // 用時2.040s
i=(i+1)%maxn; // 用時4.538s
考慮到codeblocks本身的誤差,我單單除去這條語句,將代碼其餘部分在codeblocks下的運行,依舊5次取平均,時間爲:0.015s。
因此,算入誤差可以發現,前兩條語句最快,第三條也不錯,第四條較慢,最後一條用了3倍的時間。故而我的代碼中採用了第一行的寫法,建議大家儘量採用前三行的寫法。
下面給出代碼:
// 假設儲存的信息類型是int
// 棧
class Stack
{
static const int maxn = 10000;
int S[maxn],L;
public:
Stack(): L(0) {}
void in(int x) { S[L++]=x; }
int out() { return S[--L]; }
int size() { return L; }
};
// 隊列
class Queue
{
static const int maxn = 10000;
int Q[maxn],i,j;
public:
Queue(): i(0), j(0) {}
void in(int x) { Q[j++]=x; }
int out() { return Q[i++]; }
int size() { return j-i; }
};
// 循環隊列
class CycleQueue
{
static const int maxn = 10000;
int Q[maxn],i,j;
void add(int &k) { k=(k==maxn-1)?0:(k+1); }
public:
CycleQueue(): i(0), j(0) {}
void in(int x) { Q[j]=x; add(j); }
int out() { int x=Q[i]; add(i); return x; }
int size() { return (j>i)?(j-i):(j+maxn-i); } // 此處提醒,循環隊列元素個數應在0~maxn-1之間,不可達到maxn
38 };