一、栈和队列的定义和特点
- 栈和队列是两种常用的、重要的数据结构
- 栈和队列是限定插入和删除只能在表的“端点”进行的线性表
- 栈和队列是线性表的子集(是插入和删除位置受限的线性表)
栈——先进后出、后进先出
队列——先进先出
二、栈的定义和特点
- 栈(stack)是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表
- 又称为后进先出的线性表,简称LIFO结构
- 表尾(即an端)称为栈顶Top;表头(即a1端)称为栈底Base
- 插入元素到栈顶(即表尾)的操作,称为入栈
- 从栈顶(即表尾)删除最后一个元素的操作,称为出栈
- “入”=PUSH(x) “出”=POP(y)
三、队列的定义和特点
- 队列(queue)是一种先进先出(FIFO)的线性表。在表一端插入(表尾),在另一端(表头)删除
- 逻辑结构:与同线性表相同,仍为一对一关系
- 存储结构:顺序队或链队,以循环顺序队列更常见
四、栈的表示和操作的实现
-
空栈:base==top 是栈空标志
-
栈满:top-base==stacksize
-
栈满时的处理方法
- 报错,返回操作系统
- 分配更大的空间,作为栈的存储空间,将原栈的内容移入新栈
-
使用数组作为顺序栈存储方式的特点:
-
简单,方便,单易产生溢出(数组大小固定)
- 上溢(overflow):栈已经满,又要压入元素
- 下溢(underflow):栈已经空,还要弹出元素
注:上溢是一种错误,使问题的处理无法进行;而下溢一般认为是一种结束条件,即问题处理结束
-
1、栈的初始化
void InitStack(SeqStack *S)
{
S->top=-1;
}
2、判断栈空
int IsEmpty(SeqStack S)
{
if(S.top==-1)
return TRUE;
else
return FALSE;
}
3、判断栈满
int IsFULL(SeqStack S)
{
if(S.top==StackSize-1)
return TRUE;
else
return FALSE;
}
4、求顺序栈长度
int StackLength(SeqStack S)
{
return S.top-S.base;
}
5、清空栈
int ClearStack(SeqStack S)
{
if(S.base)
S.top=S.base;
return OK;
}
6、销毁栈
int DestryStack(SeqStack &S)
{
if(S->base)
{
delete S.base;
S.stacksize=0;
S.base=S.top=NULL;
}
return OK;
}
7、入栈
int Push(SeqStack *S,ElemType x)
{
if(S->top==Stack_Size-1)
return FALSE;
S->top++;
S->elem[S->top]=x;
return TRUE;
}
8、出栈
int Pop(SeqStack *S,ElemType *x)
{
if(S->top==-1)
return FALSE;
*x=S->elem[S->top];
S->top--;
return TRUE;
}
9、取栈顶元素
int GetTop(SeqStack *S,ElemType *x)
{
if(S->top==-1)
return FALSE;
*x=S->elem[S->top];
return TRUE;
}
五、链栈的表示和实现
- 链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct node
{
ElemType data;
struct node *next;
}LinkStackNode,*LinkStack;
- 链表的头指针就是栈顶
- 不需要头结点
- 基本不存在栈满的情况
- 空栈相当于头指针指向空
- 插入和删除仅在栈顶处执行
1、链栈的初始化
void InitStack(LingkStack &S)
{
S=NULL;
}
2、判断栈空
status StackEmpty(LinkStack S)
{
if(S==NULL)
return TRUE;
else
return FALSE;
}
3、入栈
int Push(LinkStack top,ElemType x)
{
LinkStackNode *temp;
temp=(LinkStackNode *)malloc(sizeof(LinkStackNode));
if(temp==NULL)
return FALSE;
temp->data=x;
temp->next=top->next;
top->next=temp;
return TRUE;
}
4、出栈
int Pop(LinkStack top,ElemType *x)
{
LinkStackNode *temp;
temp=top->next;
if(temp==NULL)
return FALSE;
top->next=temp->next;
*x=temp->data;
free(temp);
return TRUE;
}
5、取栈顶元素
int GetTop(LinkStack S)
{
if(S!=NULL)
return S->data;
}
六、栈与递归
- 递归的定义
- 若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的
- 若一个过程直接地或间接地调用自己,则称这个过程是递归的过程
- 递归问题——分治法
- 对于一个较为复杂的问题,能够分解成几个相对简单的且解法相同或类似的子问题来求解
- 递归的优缺点
- 优点:结构清晰,程序易读
- 缺点:每次调用要生成工作记录,保存状态信息,入栈;返回时要出栈,恢复状态信息。时间开销大
七、队列的表示和操作的实现
- 顺序队列、链式队列
- 队列的顺序表示——用一维数组base[MAXQSIZE]
#define MAXQSIZE 100 //最大队列长度
Typedef struct
{
QElemType *base; //初始化的动态分配存储空间
int front; //头指针
int rear; //尾指针
}sqQueue;
- 设数组大小为MAXQSIZE rear=MAXQSIZE时,发生溢出
- 若front=0 rear=MAXQSIZE时,再入队——真溢出
- 若front≠0 rear=MAXQSIZE时,再入队——假溢出
顺序队列
1、队列的初始化
Status InitQueue(SqQueue &Q)
{
Q.base=(QElemType*)malloc(MAXQSIZE*sizeof(QElemType)); //分配数组空间
if(!Q.base)
return(OVERFLOW); //存储分配失败
Q.front=Q.rear=0; //头指针尾指针置为0,队列为空
return OK;
}
2、求队列长度
int QueueLength(SqQueue Q)
{
return((Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);
}
3、循环队列入队
status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.front)
return ERROR; //队满
Q.base[Q.rear]=e; //新元素入队尾
Q.rear=(Q.rear+1)%MAXQSIZE; //队尾指针+1
return OK;
}
4、循环队列出队
status DeQueue(SqQueue &Q,QElemType e)
{
if(Q.front==Q.rear)
return ERROR; //队空
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MAXQSIZE; //队头指针+1
return OK;
}
5、取队头元素
SElemType GetHead(SqQueue Q)
{
if(Q.front!=Q.rear) //队列不为空
return Q.base[Q.front]; //返回队头指针元素的值,队头指针不变
}
链式队列
#define MAXQSIZE 100
typedef struct Qnode
{
QElemType data;
struct Qnode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
1、初始化
status InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
if(!Q.front)
return(OVERFLOW);
Q.front->next=NULL;
return OK;
}
2、链队列销毁
status DestroyQueue(LinkQueue &Q)
{
while(Q.front)
{
p=Q.front->next;
free(Q.front);
Q.front=p;
}
return OK;
}
3、入队
status EnQueue(LinkQueue &Q,QElemType e)
{
p=(QueuePtr)malloc(sizeof(QNode));
if(!p)
return(OVERFLOW);
p->data=e;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return OK;
}
4、出队
status EnQueue(LinkQueue &Q,QElemType e)
{
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p)
Q.rear=Q.front;
delete p;
return OK;
}
5、取队头元素
Status GetHead(LinkQueue Q,QElemType &e)
{
if(Q.front==Q.rear)
return ERROR;
e=Q.front->next->data;
return OK;
}