棧和隊列的總結:
(有時候感覺自己掌握了,棧和隊列,可是在寫的時候會遇到不同的情況,就不會處理了,因此在這里進行總結下)。
棧:
棧是一端受限,一段允許進行操作的線性表。我自己理解時,會將它理解成一個裝書的盒子。放書,取書,就是進行的操作。這個的特點就是,你放了一踏書,現在你想取書,你只能先把上面的書一個個取出來,即:先放的后取,后放的先取。放在棧上說,就是先進后出。
明白了棧的定義,現在要實際的實際,首先是它的邏輯結構:線性表。它是線性的。
現在是它的存儲結構:最常采用的是順序存儲和鏈式存儲(見好多書或資料都說的最常采用的是順序存儲和鏈式存儲,百度了下不常見的沒有找到)。其中順序存儲用數組,鏈式存儲用鏈表。
順序存儲:
先進行分析下:首先要分配一個足夠大的數組(這里就出現了一個問題,要是分配的空間小,就會出現溢出的情況,這是一個潛在的隱患,但是要是分配的太過大,又會出現浪費空間,這里要做好一個估計,所以呢,我還是喜歡鏈式存儲,要多少就給多少,不用擔心空間太小或浪費),現在有了這個數組,需要的還有,必須有個東西能一個控制一端不讓操作(數組的前端從下標為0開始),一端要進行增刪,這樣就可以說是具備了棧有的特點,不讓操作的叫棧底,進行操作的是棧頂
棧的定義:(用的是順序存儲)
#define Max 100;
typedef int Datetype;
typedef struct
{
Datetype date[Max];
Int top; //控制棧頂
}SeqStack,*PseqStack;
完成了定義,就要進行對棧的各種操作:初始化,判空,進棧,出棧,得到棧頂元素,銷毀棧…….
初始化:
PseqStack Init-SeqStack( )
{
PseqStack S;
S=(PseqStack)malloc(sizeof(SeqStack)); //頭文件要包括stdilb.h
S->top=-1;
return S;
}
判空:
Int IsEmpyt(PseqStack S)
{
if(S->top==-1)
return 1;
else
return 0;
}
進棧:
int Push(PseqStack S,Datetype x)
{
If(S->top==Max-1)
return 0;
else
S->top++;
S->date[S->top]=x;
return 1;
}
出棧:
int Pop(PseqStack S,int *x)
{
if(isEmpty(PseqStack S)==1)
return 0;
else
{
*x=S->date[S->top];
S->top--;
return 1;
}
}
int GetTopdate(PseqStack S)
{
if(isEmpty(PseqStack S)==1)
return 0;
else
return S->date[s->top]
}
int Destroy(PseqStack *S)
{
if(*S)
{ free(s);
*S=NULL;
return 1;
}
return 0;
}
下面來看下鏈式存儲:
控制入棧出棧的端口,棧頂一般是鏈表的頭,第一個節點,棧底一般是最后一個節點。(可以避免順序存儲的溢出),同時節省空間,要多少,申請多少。鏈表的運用中同時要注意一旦申請了,最后要記得釋放,不然會帶來不可預計的后果。下面是鏈式存儲的一些操作。
typedef struct Stacknode
{
int date;
struct Stacknode *next;
}slStacktype;
入棧:
Int push(slStacktype *top,int x)
{
slStacktype *p;
if((p=( slStacktype *)malloc(sizeof(slStacktype )))==NULL) //申請節點
return 0;
p->date=x;
p->next=top->next; //用的是頭插法,top始終是棧頂。
top->next =p;
return 1;
}
出棧:
int pop(slStacktype *top)
{
slStacktype *p;
int x;
if(top->next==NULL)
return NULL;
p=top->next;
top->next=p->next; //刪除節點,用x記錄要刪除的元素。
x=p->date;
free(p);
return x;
}
對我來說,棧和隊列,其實很相似,只不過是控制的位置不同。
隊列:是一種限定性的線性表。這樣理解比較好,學生排隊買飯。有什么特點呢?當然,你先來,就先打飯,先吃飯。抽象到隊列上說,有隊頭,隊尾,要想加入(入隊),只能從隊尾加,想走(出隊),只能從隊頭走。即:先進先出。
和棧一樣,它常見的兩種存儲是順序存儲和鏈式存儲。
用順序存儲時,會遇到這樣的情況,數組並沒有滿,卻入不了隊(假溢出),原因在於隊頭沒有在數組的0下標處。一般情況下,因為隊列會存在假溢出的情況,所以采用循環隊列。
說下循環隊列的操作吧。(理解取余)
定義:
typedef struct
{
int date[Max];
int rear; //控制隊尾
int front;//控制隊頭
}CirQueue;
① 置隊空
void InitQueue(CirQueue *Q)
{
Q->front=Q->rear=0;
Q->count=0; //計數器置0
}
② 判隊空
int QueueEmpty(CirQueue *Q)
{
return Q->count==0; //隊列無元素為空
}
③ 判隊滿
int QueueFull(CirQueue *Q)
{
return Q->count==Max; //隊中元素個數等於max時隊滿
}
④ 入隊
void EnQueue(CirQueuq *Q,int x)
{
if(QueueFull((Q))
Error("Queue overflow"); //隊滿上溢
Q->count ++; //隊列元素個數加1
Q->data[Q->rear]=x; //新元素插入隊尾
Q->rear=(Q->rear+1)%Max; //用的是循環,當滿時頭尾相差一個空間,用於區別滿和不滿。
}
⑤ 出隊
DataType DeQueue(CirQueue *Q)
{
int temp;
if(QueueEmpty((Q))
Error("Queue underflow"); //隊空下溢
temp=Q->data[Q->front];
Q->count--; //隊列元素個數減1
Q->front=(Q->front+1)%Max; //循環意義下的頭指針加1
return temp;
}
⑥取隊頭元素
DataType QueueFront(CirQueue *Q)
{
if(QueueEmpty(Q))
Error("Queue if empty.");
return Q->data[Q->front];
}
鏈式存儲:
typedef struct node
{
Datetype date;
Struct node *next;
}Qnode;
typedef struct
{
Qnode *front;
Qnode *rear;
}LQueue;
LQueue *q;
創建:
LQueue *init_lQueue()
{
LQueue *q,*p;
q=( LQueue *)malloc(sizeof(LQueue)); //頭尾指針
p=( LQueue *)malloc(sizeof(LQueue)); // 鏈隊頭結點
p->next=NULL;
q->front=q->rear=p;
return q;
}
入隊:
void inlQueue( LQueue *q,datetype x)
{
Qnode *p;
P=( LQueue *)malloc(sizeof(LQueue)); //與鏈表的結點增加想同。
p->data=x;
p->next=NULL;
q->rear->next=p;
q->rear =q;
}
判隊空:
int isempty(LQueue *q)
{
if(q->front==q->rear)
Return 0;
else
return 1;
}
出隊:
int outqueue(LQueue *q,datedef *x)
{
Qnode *p;
if(isempty(q))
{
Printf(“隊空”);
Return 0;
}
else
{
P=q->front->next; //與鏈表的刪除相同。
q->front->next=p->next;
*x=p->date;
free(p);
if(q->front->next==NULL)
q->rear=q->front;
return turn;
}
}
By:暖暖
2014.11.19