堆棧和隊列
一、棧
1.定義
棧是一種滿足后進先出的數據結構;例:死胡同
- 允許進行插入、刪除操作的一端稱為棧頂 top
- 表的另一端稱為棧底
- 當棧中沒有數據元素時,稱為空棧
- 棧的插入操作通常稱為進棧或入棧
- 棧的刪除操作通常稱為退棧或出棧
void InitStack(SqStack *&s);
void DestroyStack(SqStack *&s);
bool StackEmpty(SqStack *s);
bool Push(SqStack *&s,ElemType e);
bool Pop(SqStack *&s,ElemType &e);
bool GetTop(SqStack *s,ElemType &e);
2.類型
①順序棧
②鏈棧
2.1順序棧
順序棧四要素:
①棧空條件:top=-1
②棧滿條件:top=MaxSize - 1
③進棧操作:top++;將e放在棧頂
④退棧操作:從top取出;top--
//順序棧基本運算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct
{
ElemType data[MaxSize];
int top;//棧指針
} SqStack;//順序棧類型
void InitStack(SqStack *&s)
{
s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;//top為下標,始終指向棧頂元素;在以數組構成的棧中,初始值為-1,自加一次則指向下標為0的元素
}
void DestroyStack(SqStack *&s)
{
free(s);
}
bool StackEmpty(SqStack *s)
{
return(s->top==-1);
}
bool Push(SqStack *&s,ElemType e)
{
if (s->top==MaxSize-1)//棧滿的情況,即棧上溢出
return false;
s->top++;
s->data[s->top]=e;
return true;
}
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1)//棧為空的情況,即棧下溢出
return false;
e=s->data[s->top];
s->top--;
return true;
}
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1)//棧為空的情況,即棧下溢出
return false;
e=s->data[s->top];
return true;
}
2.2 鏈棧
//鏈棧基本運算算法
#include <stdio.h>
#include <malloc.h>
typedef char ElemType;
typedef struct linknode
{
ElemType data; //數據域
struct linknode *next; //指針域
} LinkStNode; //鏈棧類型
void InitStack(LinkStNode *&s)
{
s=(LinkStNode *)malloc(sizeof(LinkStNode));
s->next=NULL;
}
void DestroyStack(LinkStNode *&s)
{
LinkStNode *p=s->next;
while (p!=NULL)
{
free(s);
s=p;
p=p->next;
}
free(s); //s指向尾結點,釋放其空間
}
bool StackEmpty(LinkStNode *s)
{
return(s->next==NULL);
}
void Push(LinkStNode *&s,ElemType e)
{ LinkStNode *p;
p=(LinkStNode *)malloc(sizeof(LinkStNode));
p->data=e; //新建元素e對應的結點p
p->next=s->next; //插入p結點作為開始結點
s->next=p;
}
bool Pop(LinkStNode *&s,ElemType &e)
{ LinkStNode *p;
if (s->next==NULL) //棧空的情況
return false;
p=s->next; //p指向開始結點
e=p->data;
s->next=p->next; //刪除p結點
free(p); //釋放p結點
return true;
}
bool GetTop(LinkStNode *s,ElemType &e)
{ if (s->next==NULL) //棧空的情況
return false;
e=s->next->data;
return true;
}
3.表達式
算數表達式=中綴表達式【考慮運算符優先性】
二叉樹畫法:【根據優先級順序,找運算符;整體上()> 乘除 > 加減 ,局部上從左到右)
①找到符號兩邊的兩個數
②先寫符號,再寫數
③根據中序,依次合並,畫出二叉樹
轉后綴表達式:
1.遇到操作數:直接輸出
2.棧為空時,遇到運算符,直接入棧
3.遇到左括號:將其入棧
4.遇到右括號:執行出棧操作,直到彈出棧的是左括號,括號不輸出。
5.遇到其他運算符:加減乘除:彈出所有優先級大於或者等於該運算符的棧頂元素,然后將該運算符入棧
6.最終將棧中的元素依次出棧,輸出。簡便方法:
①根據優先級順序中綴符號兩邊,兩兩結合,用括號括起來。
②前綴則把符號挪到括號左側,后綴則挪到右側。
③最后括號都去掉
前綴與后綴【不用考慮運算符優先性】
后綴表達式---->二叉樹以后序輸出
二叉樹畫法:①找到符號的前兩個數
②先寫符號,再寫數
③根據后序,依次合並,畫出二叉樹
前綴表達式---->二叉樹以前序輸出
4.出入棧序列
入棧序列為1,2,3,4,5,6,則不可能的序列
棧頂有高位元素后,+出棧的首先得是高位元素;
5.進制轉化
高進制->低進制,除法
余數依次進棧,依次輸出即可
6.括號匹配
二、隊列
1.順序隊列基本代碼
(1) 入隊時隊尾指針前進1:(rear+1)%QueueSize
(2) 出隊時隊頭指針前進1:(front+1)%QueueSize
(3) 隊列長度:(rear-front+QueueSize)%QueueSize
現有一循環隊列,其隊頭指針為front,隊尾指針為rear;循環隊列長度為N。其隊內有效長度為?(假設隊頭不存放數據)
答案:(rear-front+N)%N
(4) 隊空和隊滿的條件
為了區分隊空還是堆滿的情況,有多種處理方式:
方式1: 犧牲一個單元來區分隊空和隊滿,入隊時少用一個隊列單元,即約定以"隊頭指針在隊尾指針的下一位置作為隊滿的標志"。
隊滿條件為:(rear+1)%QueueSize==front
隊空條件為:front==rear
隊列長度為:(rear-front+QueueSize)%QueueSize
方式2: 增設表示隊列元素個數的數據成員size,此時,隊空和隊滿時都有front==rear。
隊滿條件為:size==QueueSize
隊空條件為:size==0
方式3: 增設tag數據成員以區分隊滿還是隊空
tag表示0的情況下,若因刪除導致front==rear,則隊空;
tag等於1的情況,若因插入導致front==rear則隊滿
2.類型
①順序隊列(非環形)
②順序隊列(環形)
③鏈隊
2.1 順序隊列(非環形)
//順序隊列(非環形隊列)基本運算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct
{
ElemType data[MaxSize];
int front,rear; //隊頭和隊尾指針
} SqQueue;
void InitQueue(SqQueue *&q)
{ q=(SqQueue *)malloc (sizeof(SqQueue));
q->front=q->rear=-1;
}
void DestroyQueue(SqQueue *&q) //銷毀隊列
{
free(q);
}
bool QueueEmpty(SqQueue *q) //判斷隊列是否為空
{
return(q->front==q->rear);
}
bool enQueue(SqQueue *&q,ElemType e) //進隊
{ if (q->rear==MaxSize-1) //隊滿上溢出
return false; //返回假
q->rear++; //隊尾增1
q->data[q->rear]=e; //rear位置插入元素e
return true; //返回真
}
bool deQueue(SqQueue *&q,ElemType &e) //出隊
{ if (q->front==q->rear) //隊空下溢出
return false;
q->front++;
e=q->data[q->front];
return true;
}
2.2 順序隊列(環形)
//順序隊列(環形隊列)基本運算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct
{
ElemType data[MaxSize];
int front,rear; //隊首和隊尾指針
} SqQueue;
void InitQueue(SqQueue *&q)
{ q=(SqQueue *)malloc (sizeof(SqQueue));
q->front=q->rear=0;
}
void DestroyQueue(SqQueue *&q)
{
free(q);
}
bool QueueEmpty(SqQueue *q)
{
return(q->front==q->rear);
}
bool enQueue(SqQueue *&q,ElemType e)
{ if ((q->rear+1)%MaxSize==q->front) //隊滿上溢出
return false;
q->rear=(q->rear+1)%MaxSize;
q->data[q->rear]=e;
return true;
}
bool deQueue(SqQueue *&q,ElemType &e)
{ if (q->front==q->rear) //隊空下溢出
return false;
q->front=(q->front+1)%MaxSize;
e=q->data[q->front];
return true;
}
2.3 鏈隊
同樣包括單鏈表的隊列,循環鏈表隊列
//鏈隊運算算法
#include <stdio.h>
#include <malloc.h>
typedef char ElemType;
typedef struct DataNode
{
ElemType data;
struct DataNode *next;
} DataNode; //鏈隊數據結點類型
typedef struct
{
DataNode *front;
DataNode *rear;
} LinkQuNode; //鏈隊類型
void InitQueue(LinkQuNode *&q)
{
q=(LinkQuNode *)malloc(sizeof(LinkQuNode));
q->front=q->rear=NULL;
}
void DestroyQueue(LinkQuNode *&q)
{
DataNode *p=q->front,*r;//p指向隊頭數據結點
if (p!=NULL) //釋放數據結點占用空間
{ r=p->next;
while (r!=NULL)
{ free(p);
p=r;r=p->next;
}
}
free(p);
free(q); //釋放鏈隊結點占用空間
}
bool QueueEmpty(LinkQuNode *q)
{
return(q->rear==NULL);
}
void enQueue(LinkQuNode *&q,ElemType e)
{ DataNode *p;
p=(DataNode *)malloc(sizeof(DataNode));
p->data=e;
p->next=NULL;
if (q->rear==NULL) //若鏈隊為空,則新結點是隊首結點又是隊尾結點
q->front=q->rear=p;
else
{ q->rear->next=p; //將p結點鏈到隊尾,並將rear指向它
q->rear=p;
}
}
bool deQueue(LinkQuNode *&q,ElemType &e)
{ DataNode *t;
if (q->rear==NULL) //隊列為空
return false;
t=q->front; //t指向第一個數據結點
if (q->front==q->rear) //隊列中只有一個結點時
q->front=q->rear=NULL;
else //隊列中有多個結點時
q->front=q->front->next;
e=t->data;
free(t);
return true;
}