栈和队列是线性表的子集(是插入和删除位置受限的线性表)。
简单点说,栈和队列是限定插入和删除只能在表的“端点”进行的线性表。
再简单形象点来说:
普通线性表:
Insert(L,i,x) //可以插入在表的任意位置(表头,表尾,表中间)
1<=i<=n+1
Delete(L,i) //可以删除表中的任意元素
1<=i<=n
特殊线性表:
栈:
Insert(S,n+1,x) //只能在表尾插入,即第n+1个位置
Delete(S,n) //只能删除表尾的元素,即第n个元素
队列:
Insert(Q,n+1,x) //只能在表尾(即队尾)插入,即第n+1个位置
Delete(Q,1) //只能删除表头(即队头)的元素,即第1个元素
目录
(一)栈(stack):
定义:
示意图:
下面我们用一道题来帮助理解的更深刻,更透彻:
问题:假设有3个元素a,b,c,其入栈顺序为a,b,c,则其出栈顺序可以有:
c,b,a
让a,b,c依次入栈,再依次出栈。
a,b,c
让a入栈再出栈,b入栈再出栈,c入栈再出栈。
a,c,b
先让a进栈再出栈,然后b,c依次进栈再出栈。
b,a,c
先让a,b依次进栈再出栈,然后再让c进栈再出栈。
b,c,a
先让a,b进栈,然后b出栈,再让c进栈,最后让a,c依次出栈。
就以上5种情况,不能再多了。
特点:
后进先出(Last In First Out)或先进后出(First In Last Out)。
顺序栈(用顺序存储结构来存储栈)的基本操作以及代码实现:
基本操作:
上溢:栈已满,仍继续压入元素。
下溢:栈已空,仍继续弹出元素。
上溢是一种错误,使问题的处理无法进行;而下溢一般认为是一种结束条件,即问题处理结束。
栈满时分配更大空间:先分配一个空间更大的栈,将原栈中的元素全都移入,然后将原栈所占空间释放掉。因其操作太复杂,所以一般不采用这种方式。
代码:
#include<iostream>
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef char SElemType; //SElemtype 相当于 char
typedef int Status; // Status 相当于 int
#define MAXSIZE 100
//定义
typedef struct{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
Status InitStack(SqStack &S);//初始化操作,建立一个空的顺序栈
Status Push(SqStack &S,SElemType e);//顺序栈入栈
SElemType Pop(SqStack &S,SElemType &e);//顺序栈出栈 ,若栈不空,则删除S的栈顶元素,用e返回,并返回OK,否则返回ERROR
Status StackEmpty(SqStack S);//判断顺序栈是否为空 ,若为空,返回TRUE;否则返回FALSE
int StackLength(SqStack S); //求顺序栈长度
void ClearStack(SqStack &S); //清空顺序栈
void DestroyStack(SqStack &S);//销毁顺序栈
int main()
{
SqStack S;
if(InitStack(S))
cout<<"成功创建顺序栈"<<endl;
if(Push(S,'a'))
cout<<"元素a入栈成功"<<endl;
if(Push(S,'b'))
cout<<"元素b入栈成功"<<endl;
if(Push(S,'c'))
cout<<"元素c入栈成功"<<endl;
char e;
if(Pop(S,e))
cout<<"元素"<<e<<"出栈成功"<<endl;
if(StackEmpty(S))
cout<<"顺序栈为空"<<endl;
else
cout<<"顺序栈不为空"<<endl;
cout<<"此时顺序栈的长度为:"<<StackLength(S)<<endl;
ClearStack(S);
cout<<"顺序栈已清空"<<endl;
DestroyStack(S);
cout<<"顺序栈已销毁"<<endl;
}
//顺序栈的初始化
Status InitStack(SqStack &S)
{
S.base=new SElemType[MAXSIZE];//或S.base=(SElemType*)malloc(sizeof(SElemType)*MAXSIZE);
if(!S.base) exit(OVERFLOW);//存储分配失败
S.top=S.base;
S.stacksize =MAXSIZE;
return OK;
}
//顺序栈入栈
Status Push(SqStack &S,SElemType e)
{
if(S.top-S.base==S.stacksize)//栈满
return ERROR;
*S.top=e;//这两步等价于*S.top++=e;
S.top++;
return OK;
}
//顺序栈出栈
SElemType Pop(SqStack &S,SElemType &e)
{
if(S.top==S.base)//等价于if(StackEmpty(S)),即栈空
return ERROR;
--S.top;//这两步等价于 e=*--S.top;
e=*S.top;
return OK;
}
//判断顺序栈是否为空
Status StackEmpty(SqStack S)
{
if(S.base==S.top)
return TRUE;
else
return FALSE;
}
//求顺序栈长度
int StackLength(SqStack S)
{
return S.top-S.base;
}
//清空顺序栈
void ClearStack(SqStack &S)
{
if(S.base) S.top=S.base;
}
//销毁顺序栈
void DestroyStack(SqStack &S)
{
if(S.base)
{
delete S.base;
S.stacksize=0;
S.base=S.top=NULL;
}
}
运行结果:
链栈(用链式存储结构来存储栈)的代码实现:
代码:
#include<iostream>
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef char SElemType; //SElemtype 相当于 char
typedef int Status; // Status 相当于 int
#define MAXSIZE 100
//定义
typedef struct StackNode{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
Status InitStack(LinkStack &S);//初始化操作,建立一个空的链栈
Status Push(LinkStack &S,SElemType e);//链栈入栈
SElemType Pop(LinkStack &S,SElemType &e);//链栈出栈 ,若栈不空,则删除S的栈顶元素,用e返回,并返回OK,否则返回ERROR
SElemType GetTop(LinkStack S);//取栈顶元素
Status StackEmpty(LinkStack S);//判断链栈是否为空 ,若为空,返回TRUE;否则返回FALSE
void ClearStack(LinkStack &S); //清空链栈
void DestroyStack(LinkStack &S);//销毁链栈
int main()
{
LinkStack S;
if(InitStack(S))
cout<<"成功创建链栈"<<endl;
if(Push(S,'a'))
cout<<"元素a入栈成功"<<endl;
if(Push(S,'b'))
cout<<"元素b入栈成功"<<endl;
if(Push(S,'c'))
cout<<"元素c入栈成功"<<endl;
char e;
if(Pop(S,e))
cout<<"元素"<<e<<"出栈成功"<<endl;
cout<<"取栈顶元素:"<<GetTop(S)<<endl;
if(StackEmpty(S))
cout<<"链栈为空"<<endl;
else
cout<<"链栈不为空"<<endl;
ClearStack(S);
cout<<"链栈已清空"<<endl;
DestroyStack(S);
cout<<"链栈已销毁"<<endl;
}
//链栈的初始化
Status InitStack(LinkStack &S)
{
S=NULL;//构造一个空栈,栈顶指针置为空
return OK;
}
//链栈入栈
Status Push(LinkStack &S,SElemType e)
{
LinkStack p;
p=new StackNode;//生成新结点p
p->data=e;//将新结点数据域置为e
p->next=S;//将新结点插入栈顶
S=p;//修改栈顶指针
return OK;
}
//链栈出栈
SElemType Pop(LinkStack &S,SElemType &e)
{
LinkStack p;
if(S==NULL) return ERROR;
e=S->data;
p=S;
S=S->next;
delete p;
return OK;
}
//取栈顶元素
SElemType GetTop(LinkStack S)
{
if(S!=NULL)
return S->data;
}
//判断链栈是否为空
Status StackEmpty(LinkStack S)
{
if(S==NULL)
return TRUE;
else
return FALSE;
}
//清空链栈
void ClearStack(LinkStack &S)
{
if(S) S=NULL;
}
//销毁链栈
void DestroyStack(LinkStack &S)
{
if(S)
{
delete S;
}
}
运行结果:
栈与递归:
以下三种情况常常用到递归方法:
1.递归定义的数学函数:
2.具有递归特性的数据结构:
3.可递归求解的问题:
递归的求解:
----分治法:
递归的优缺点:
递归-->非递归:
1.递归:
2.非递归:
1》尾递归,单向递归-->循环结构
2》 借助栈来改写递归:
由上可见,一般情况下,我们还是采用递归的方法,但如果时间效率要求比较高, 那我们再考虑将其转化为非递归的程序。
(二)队列:
定义:
特点:
先进先出(First In First Out)。
在循环队列中我们经常会遇到的问题以及解决方法:
1.假上溢:
就是尾指针已经指到了队尾,且头指针与尾指针之间都有元素(元素已满),但头指针与队头之间仍有空着。
具体如下图所示:
解决方法:
2.判断队空与队满:
队空与队满时条件一样,如下图所示:
解决方法:
另外在求队列长度时:
循环队列的顺序实现代码实现:
代码:
#include<iostream>
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef char QElemType; //SElemtype 相当于 char
typedef int Status; // Status 相当于 int
#define MAXQSIZE 100
//定义
typedef struct{
QElemType *base;
int frort;//头指针
int rear;//尾指针
}SqQueue;
Status InitQueue(SqQueue &Q);//初始化操作,建立一个空的队列
Status EnQueue(SqQueue &Q,QElemType e);//循环队列入队
QElemType DeQueue(SqQueue &Q,QElemType &e);//循环队列出队,若队不为空,则删除S的队顶元素,用e返回,并返回OK,否则返回ERROR
QElemType GetHead(SqQueue Q);//取队头元素
Status QueueEmpty(SqQueue Q);//判断循环队列是否为空 ,若为空,返回TRUE;否则返回FALSE
int QueueLength(SqQueue Q); //求队列的 长度
void ClearQueue(SqQueue &Q); //清空循环队列
void DestroyQueue(SqQueue &Q);//销毁循环队列
int main()
{
SqQueue Q;
if(InitQueue(Q))
cout<<"成功创建队列"<<endl;
if(EnQueue(Q,'a'))
cout<<"元素a入队成功"<<endl;
if(EnQueue(Q,'b'))
cout<<"元素b入队成功"<<endl;
if(EnQueue(Q,'c'))
cout<<"元素c入队成功"<<endl;
char e;
if(DeQueue(Q,e))
cout<<"元素"<<e<<"出队成功"<<endl;
if(QueueEmpty(Q))
cout<<"循环队列为空"<<endl;
else
cout<<"循环队列不为空"<<endl;
cout<<"该循环队列的长度为:"<<QueueLength(Q)<<endl;
ClearQueue(Q);
cout<<"循环队列已清空"<<endl;
DestroyQueue(Q);
cout<<"循环队列已销毁"<<endl;
}
//初始化
Status InitQueue(SqQueue &Q)
{
Q.base=new QElemType[MAXQSIZE];//或Q.base=(QElemType*)malloc(sizeof(QElemType)*MAXQSIZE);
if(!Q.base) exit(OVERFLOW);//存储分配失败
Q.frort=Q.rear=0;//头指针尾指针置为0,队列为空
return OK;
}
//循环队列入队
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.frort) return ERROR;//队满
Q.base[Q.rear]=e; //新元素加入队尾
Q.rear=(Q.rear+1)%MAXQSIZE;//队尾指针+1
return OK;
}
//循环队列出队
QElemType DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.frort==Q.rear) return ERROR;//队空
e=Q.base[Q.frort]; //保存队头元素
Q.frort=(Q.frort+1)%MAXQSIZE; //队头指针+1
return OK;
}
//取队头元素
QElemType GetHead(SqQueue Q)
{
if(Q.frort!=Q.rear) //队列不为空
return Q.base[Q.frort];//返回队头指针元素的值,队头指针不变
}
//判断循环队列是否为空
Status QueueEmpty(SqQueue Q)
{
if(Q.frort==Q.rear)
return TRUE;
else
return FALSE;
}
//求循环队列长度
int QueueLength(SqQueue Q)
{
return((Q.rear-Q.frort+MAXQSIZE)%MAXQSIZE);
}
//清空循环队列
void ClearQueue(SqQueue &Q)
{
if(Q.base) Q.frort==Q.rear;
}
//销毁循环队列
void DestroyQueue(SqQueue &Q)
{
if(Q.base)
{
delete Q.base;
Q.frort==Q.rear;
}
}
运行结果:
链队的基本操作以及代码实现:
基本操作:
代码:
#include<iostream>
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef char QElemType; //SElemtype 相当于 char
typedef int Status; // Status 相当于 int
#define MAXQSIZE 100
//定义
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
Status InitQueue(LinkQueue &Q);//初始化操作,建立一个空的链队列
Status EnQueue(LinkQueue &Q,QElemType e);//链队列入队
QElemType DeQueue(LinkQueue &Q,QElemType &x);//链队列出队,若队不为空,则删除S的队顶元素,用e返回,并返回OK,否则返回ERROR
QElemType GetHead(LinkQueue Q);//取链队头元素
Status QueueEmpty(LinkQueue Q);//判断链队列是否为空 ,若为空,返回TRUE;否则返回FALSE
void ClearQueue(LinkQueue &Q); //清空链队列
void DestroyQueue(LinkQueue &Q);//销毁链队列
int main()
{
LinkQueue Q;
if(InitQueue(Q))
cout<<"成功创建链队列"<<endl;
if(EnQueue(Q,'a'))
cout<<"元素a入队成功"<<endl;
if(EnQueue(Q,'b'))
cout<<"元素b入队成功"<<endl;
if(EnQueue(Q,'c'))
cout<<"元素c入队成功"<<endl;
char e;
if(DeQueue(Q,e))
cout<<"元素"<<e<<"出队成功"<<endl;
cout<<"取链队头元素:"<<GetHead(Q)<<endl;
if(QueueEmpty(Q))
cout<<"链队列为空"<<endl;
else
cout<<"链队列不为空"<<endl;
ClearQueue(Q);
cout<<"链队列已清空"<<endl;
DestroyQueue(Q);
cout<<"链队列已销毁"<<endl;
}
//初始化
Status InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=new QNode;//或Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
if(!Q.front) exit(OVERFLOW);//存储分配失败
Q.front->next=NULL;
return OK;
}
//链队列入队
Status EnQueue(LinkQueue &Q,QElemType e)
{
QueuePtr p;
p=new QNode;
if(!p) exit(OVERFLOW);
p->data=e;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return OK;
}
//链队列出队
QElemType DeQueue(LinkQueue &Q,QElemType &e)
{
if(Q.front==Q.rear) return ERROR;
QueuePtr p;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p) Q.rear=Q.front;
delete p;
return OK;
}
//取链队头元素
QElemType GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
return Q.front->next->data;
}
//判断链队列是否为空
Status QueueEmpty(LinkQueue Q)
{
if(Q.front->next==NULL)
return TRUE;
else
return FALSE;
}
//清空链队列
void ClearQueue(LinkQueue &Q)
{
if(Q.front) Q.front->next=NULL;
}
//销毁链队列
void DestroyQueue(LinkQueue &Q)
{
while(Q.front)
{
QueuePtr p;
p=Q.front->next;
delete(Q.front);
Q.front=p;
}
}
运行结果:
以上就是栈和队列的全部知识点以及代码实现了,怪不容易的嘿嘿,请打开的小伙伴一定要好好看哦!