1.兩棧的共享空間是如何實現的
typedefstruct
2 {
3 if(s->top1+1 == s->top2) //棧已滿,不能再push新元素了
4 return ERROR;
5 if(stackNumber == 1) //棧1有元素進棧
6 s->data[++s->top1] = e; //若棧1則先top+1後給數組元素賦值
7 else if(stackNumber == 2) //棧2有元素進棧
8 s->data[--s->top2] = e; //若棧2則先top2-1後給數組元素賦值
9 return OK;
由於棧只是棧頂在做插入和刪除操作,所以棧頂應該放在單鏈表的頭部。另外,都有了棧頂在頭部了,單鏈表中的頭結點也就失去了意義,通常對於鏈棧來說,是不需要頭結點的。
對於鏈棧來說,基本不存在棧滿的情況,除非內存已經沒有使用空間了。
對於空棧來說,鏈表原來的定義是頭指針指向空,那麼鏈棧的空其實就是top=NULL。
SElemType data;
Struct StackNode *next;
}StackNode;
typedef struct StackNode *LinkStackPtr;
typedef struct LinkStack {
LinkStackPtr top;
int count;
}LinkStack;
1.是參數傳遞的問題。傳遞參數的目的,是爲了代碼可以重用,讓一種方法可以應用到更多的場合,而不需要爲N種情況寫N套類似的代碼。那用什麼方法來做參數的傳遞,可以選擇:
a.爲了速度快,使用cpu的寄存器傳遞參數。這會碰到一個問題,cpu寄存器的數量是有限的,當函數內再想調用子函數的時候,再使用原有的cpu寄存器就會衝突了。想利用寄存器傳參,就必須在調用子函數前吧寄存器存儲起來,然後當函數退出的時候再恢復。
b.利用某些ram的區域來傳遞參數。這和上面a的情況幾乎一樣,當函數嵌套調用的時候,還是會出現衝突,依然面臨要把原本數據保存到其他地方,再調用嵌套函數。並且保存到什麼地方,也面臨困難,無論臨時存儲到哪裏,都會有上面傳遞參數一樣的困境。
2.函數裏面必然要使用到局部變量,而不能總是用全局變量。則局部變量存儲到哪裏合適,即不能讓函數嵌套的時候有衝突,又要注重效率。
以上問題的解決辦法,都可以利用棧的結構體來解決,寄存器傳參的衝突,可以把寄存器的值臨時壓入棧裏面,非寄存器傳參也可以壓入到棧裏面,局部變量的使用也可以利用棧裏面的內存空間,只需要移動下棧指針,騰出局部變量佔用的空間。最後利用棧指針的偏移來完成存取。於是函數的這些參數和變量的存儲演變成記住一個棧指針的地址,每次函數被調用的時候,都配套一個棧指針地址,即使循環嵌套調用函數,只要對應函數棧指針是不同的,也不會出現衝突。利用棧,當函數不斷調用的時候,不斷的有參數局部變量入棧,棧裏面會形成一個函數棧幀的結構,一個棧幀結構歸屬於一次函數的調用。棧的空間也是有限的,如果不限制的使用,就會出現典型的棧溢出的問題。有了棧幀的框架在,我們在分析問題的時候,如果能獲取到當時的棧的內容,則有機會調查當時可能出現的問題。
9 3 1 - * 2 +的形式求值。其中需要兩個棧:數字棧和運算符棧。
過程:
逐個讀取中綴表達式(char型):9*(3-1)+2
1.如果是數字則壓入數字棧(如果是大於一位的數字則需要寫個函數轉換成int型)
2.如果是'('則壓入運算符棧中
3.如果是'+'或者'-',判斷一下運算符的棧頂元素,如果是'*','/','+','-'則出棧,調用出棧函數(利用數字棧和運算符棧算出中間結果),然後將該運算符壓入運算符棧中
4.如果是'*'或者'/',判斷一下運算符的棧頂元素,如果是'*'或者'/',則出棧,調用出棧函數,然後將該運算符壓入運算符棧中
5.如果是'(',則直接調用出棧函數,直到將'('出棧爲止
6.遍歷完中綴表達式後,如果此時運算符棧不爲空,則調用出棧函數逐個出棧
7.最後的結果是數字棧的棧頂元素
轉化爲前綴:從右到左遍歷中綴表達式,遇到操作數,輸出,遇到操作符,當前操作符的優先級大於等於棧頂操作符優先級,進棧,否則,彈出棧頂優先級大於當前操作符的操作符,當前操作符進棧。
#define MAXN 10
int push(int *stack,int maxn,int *toppt,int x)
//調用時不加&是因爲push(&s,Maxn,&top,i)中s是數組元素,其名字代表數組首地址
{
if(*toppt>=maxn)
return 1;//棧滿
stack[*toppt]=x;//第一步操作,保證元素在0位置處
(*toppt)++;
return 0;
}
int pop(int *stack,int *toppt,int *cp)
{
if(*toppt==0)
return 1;
(*toppt)--;
*cp=stack[*toppt];//出棧元素的臨時保存位置,結合main函數裏出棧元素爲i,按地址傳值
return 0;
}
void OutputStack(int *stack,int toppt)
{
int i;
for(i=toppt-1;i>=0;i--)
{
printf("%d",stack[i]);
printf("\n");
}
}
void main()
{
int s[MAXN],i;
int top=0;
int op;
while(1)
{
printf("請選擇操作,1:進棧 2:出棧 0:退出");
fflush(stdin);
scanf("%d",&op);
switch(op)
{
case 0:return ;
case 1:
{
printf("請輸入進棧元素:");
scanf("%d",&i);
if(push(s,MAXN,&top,i)==0)
{
printf("進棧成功,棧內元素:\n");
OutputStack(s,top);
}
else
printf("棧滿\n");
}
break;
case 2:
if(pop(s,&top,&i)==0)
{
printf("出棧元素爲:[%d],棧內元素爲:\n",i);
OutputStack(s,top);
}
else
printf("棧空\n");
break;
}
}
}
這種存儲某些數據,並在後面又以存儲的逆序恢復這些數據,以提供之後使用的需求,顯然很符合棧的數據結構,因此,編譯器使用棧實現遞歸就沒什麼好驚訝的了。