棧與佇列 -- 增、查、改、刪操作
1. 棧
棧是一種只能在一端進行插入或刪除操作的線性表 其中允許進行插入或刪除操作的一端稱為棧頂(Top) 棧頂由一個棧頂指標的位置指示器(其實是1個變數,對於順序棧就是記錄棧頂元素所在陣列位置標號的一個整型變數,對於鏈式棧就是記錄棧頂元素所在結點地址的指標)它是動態變換的。 表的另一端稱為棧底,棧底是固定不變的。 棧的插入和刪除操作一般稱為入棧和出棧。 特點:先進後出(FILO) 儲存結構:順序棧和鏈式棧 棧是一種在操作上稍加限制的線性表,即棧的本質是線性表; 數學性質: 當n個元素以某種順序進棧,並且可在任意時刻出棧時,所獲得的元素排序的數目N恰好滿足函式
01. 順序棧
棧空狀態:st.top == -1或st.top == 0 棧滿狀態:st.top ==maxsize -1
因為陣列下標從0開始,maxsize -1 為棧滿時,棧頂元素在陣列中的位置
上溢:棧滿繼續入棧 下溢:棧空的時候繼續出棧所造成的
元素x進棧操作:
++(st.top);
st.data[st.top]=x ;
必須先移動指標,再進入元素 元素x出棧操作:
x = st.data[st.top] ;
--(st.top);
1) 定義棧
typedef struct
{
int data[maxsize];
int top;
}SqStack;
2) 初始化棧
void initStack( SqStack &st)
{
st.top = -1;
}
3) 判斷棧空
int isEmpty(SqStack st)
{
if(st.top ==-1)
return 1;
else
return 0;
}
4) 進棧
int push(SqStack &st , int x)
{
if(st.top == maxsize -1)
return 0;
++(st.top);
st.data[st.top] = x;
return 1;
}
5) 出棧
int pop (SqStack &st ,int &x)
{
if(st.top == -1)
return 0;
x = st.data[st.top];
--(st.top);
return 1;
}
6) 簡化操作
//定義並初始化
int stack[maxsize];
int top = -1;
//元素x進棧
stack[++top] == x;
//元素x出棧
x = stack[top--];
02、 鏈棧
棧空狀態:lst->next == NULL; 棧滿狀態:不存在棧滿狀態 元素進棧(由p指標所指)
p->next = lst->next;
lst->next = p
元素出棧(出棧元素儲存在x中)
p = last->next;
x = p->data;
lst->next = p->next;
free(p)
1) 鏈棧結點定義
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
2) 初始化鏈棧
void initStack(LNode *&lst)
{
lst = (LNode *)malloc(sizeof(LNode));
lst->next = NULL;
}
3) 判斷棧空
int isEmpty(LNode *lst)
{
if(lst->next == NULL)
return 1;
else
return 0;
}
4) 進棧(頭插法)
void push(LNode *lst , int x)
{
LNode *p;
p = (LNode *)malloc(sizeof(LNode));
p->next = NULL;
p->data = x;
p->next = lst->next;
p->next = p;
}
5) 出棧
int pop(LNode *lst , int &x)
{
LNode *p;
if(lst->next == NULL)
return 0;
p = lst->next;
x = p->data;
lst->next = p->next;
free(p);
return 1;
}
3. 佇列
定義:佇列是一種操作受限的線性表, 其限制為僅允許在標的一端進行插入,在表的另一端刪除, 可進行插入的一端稱為隊尾,可進行刪除的一端稱為隊頭; 向佇列中插入元素稱為進隊,新元素進隊後就成為新的隊尾元素; 從佇列中刪除元素稱為出隊,其後繼元素就成為新的隊頭元素。
- 特點: 先進先出(FIFO)
- 儲存結構: 可用順序表和連結串列來儲存佇列,分別為順序隊、鏈隊
01. 順序佇列
假溢位問題:
- 隊尾指標rear -> 剛進隊元素位置
- 隊首指標fort -> 剛出隊元素位置
- 進隊時 rear 向後移動
- 出隊時 fort 向後移動
這樣進過一系列的出隊和進隊操作之後,兩個指標最終會到達陣列末端,maxsize-1處,隊中沒有元素,但仍然無法進隊,這就是“假溢位問題”
解決辦法:
將陣列組成一個環,讓rear和fort沿著環走,這樣就產生了迴圈佇列,可以通過執行語句 fort = (fort +1)%maxsize 實現環形道路走。
隊滿:
(rear+1)%maxsize == fort : (qu.rear+1)%maxsize == qu.fort
隊空:
fort == rear
元素x進隊(移動隊尾指標):元素入隊時,先移動指標,後存入元素
qu.rear = (qu.rear + 1)%maxsize;
qu.data[qu.rear] = x;
元素x出隊(移動隊首指標):元素出隊時,先移動指標,再取出元素
qu.fort = (qu.fort +1)%maxsize;
x = qu.data[qu.fort];
1) 初始化佇列
void initQueue(SqQueue &qu)
{
qu.fort = qu.rear = 0;
}
2) 判斷隊空
init isQueueEmpty(SqQueue qu)
{
if(qu.fort == qu.rear)
return 1;
else
return 0;
}
3) 進隊演算法
init enQueue(SqQueue &qu , int x)
{
if((qu.rear+1)%maxsize == qu.fort)
return 0;
qu.rear = (qu.rar+1)%maxsize;
qu.data[qu.rear] = x;
return 1;
}
4) 出隊演算法
int deQueue(SqQueue &qu , int &x)
{
if(qu.fort == qu.rear)
return 0;
qu.fort = (qu.fornt+1)%maxsize;
x = qu.data[qu.fornt];
return 1;
}
02. 鏈隊
鏈隊就是採用鏈式儲存結構儲存佇列(這裡採用單鏈表實現)
- 特點:不存在佇列滿上溢的情況 隊空狀態:lqu ->rear == NULL 或 lqu -> fort == NULL 隊空狀態:不存在這種情況 元素進隊操作:(假設p指向進隊元素)
lqu->rear->next = p;
lqu->rear = p;
元素出隊操作:(假設x儲存出隊元素)
p = lqu->fort;
lqu->fort = p->next;
x = p->data;
free(p);
1) 鏈隊型別定義
typedef struct
{
QNode *fornt;
QNode *rear;
}LiQueue;
2) 初始化鏈隊
void initQueue(LiQueue *&lqu)
{
lqu = (LiQueue *)malloc(sizeof(LiQueue));
lqu->fornt = lqu->rear = NULL;
}
3) 判斷隊空
int isQueueEmpty(LiQueue *lqu)
{
if(lqu->rear == NULL || lqu->fort == NULL)
return 1;
else
return 0;
}
4) 入隊演算法
void enQueue(LiQueue *lqu , int x)
{
QNode *p;
p = (QNode *)malloc(sizeof(QNode));
p->data = x;
p->next NULL;
if(lqu-rear == NULL)
lqu->fornt = lqu->rear = p;
else
{
lqu->rear->next = p;
lqu->rear = p;
}
}
5) 出隊演算法
int deQueue(LiQueue *lqu , int &x)
{
QNode *p;
if(lqu->rear == NULL)
return 0;
else
p = lqu->fornt;
if(lqu->fornt == lqu->rear)
lqu->fornt = lqu->rear = NULL;
else
lqu->fornt = lqu->fornt->next;
x = p->data;
free(p)
return 1;
}