栈是限定仅在表位进行插入和删除操作的线性表,把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈.栈又称为后进先出(LIFO)的线性表。
栈的抽象数据类型
1 2 3 4 5 6 7 8 9 10 11 12
| ADT 栈(stack) Data 线性表的数据对象集合为{a1, a2,......,an},每个元素的类型均为DataType。其中第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。 Operation InitStack(*S):初始化操作,建立一个空栈。 DestroyStack(*S):若栈存在,则销毁它。 ClearStack(*S):将栈清空。 StackEmpty(S):若栈为空,返回TURE GetTop(S,*e):若栈存在且为空, 用e返回s的栈顶元素。 Pop(*S,*e):删除栈S中的栈顶元素,并用e返回值。 StackLength(S):返回栈S的元素个数。 endADT
|
栈的存储结构
顺序存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| typedef int SElemType;
typedef struct { SElemType data[MAXSIZE]; int top; }
Status Push(SqStack *S,SElemType e) { if(S->top == MAXSIZE -1) { return ERROR; } S->top++; S->data[S->top]=e; return OK; }
Status Pop(SqStack *S,SElemType *e) { if(S->top==-1) return ERROR; *e=S->data[S->top]; S->top--; return OK; }
|
链式存储结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| typedef struct StackNode { SElemType data; struct StackNode *next; }StackNode,*LinkStackPtr; typedef struct { LinkStackPtr top; int count; }LinkStack;
Status Push(LinkStack *S,SElemType e) { LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode)); s->data=e; s->next=S->top; S->top=s; S->count++; return OK; }
Status Pop(LinkStack *S,SElemType *e) { LinkStackPtr p; if(StackEmpty(*S)) return ERROR; *e=S->top->data; p=S->top; S->top=S->top->next; free(p) S->count--; return OK; }
|
栈的应用
递归
斐波拉契递归
四则运算表达式求值
常见的四则运算的表达式叫做中缀表达式,而计算机在计算时无法辨别表达式运算的优先顺序,因此就要将中缀表达式转化为后缀表达式。其步骤要遵循一下规则:
- 从左至右,遇到数字就输出,遇到运算符号就进栈
- 将栈中的运算符与即将进栈的运算符进行比较,如果即将进栈的运算符优先级低于栈顶运算符,则输出栈顶运算符。如果没有,则进栈。
- 如果遇到),则输出(之前的运算符。
现在得到了后缀表达式,例如 9+(3-1)*3+10/2
的后缀表达式则为 9 3 1 -3*+10 2/+
。在进行后缀表达式计算中,计算机会运用如下规则:
- 从左到右遍历表达式的每个数字和符号
- 遇到数字就进栈,遇到符号就将处于栈顶的两个数字出栈。
队列
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作(FIFO)的线性表。
队列的抽象数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| ADT 队列(Queue) Data 同线性表 Operation InitQueus(*Q):初始化操作,建立一个列Q。 DestroyQueue(*Q):若队列Q存在,则销毁它。 ClearQueue(*Q):将队列Q清空。 QueneEmpty(Q):若队列Q为空,返回TURE GetHead(Q,*e):若队列为非空,用e返回s的队头元素 EnQueue(*Q,e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素。 DeQueue(*Q,*e):删除队列Q中队头元素,并用e返回值。 QueueLength(Q):返回队列Q的元素个数。 endADT
|
队列循环
把队列头尾相接排列的顺序存储结构称为循环队列,其中 front
指向队头,rear
指向队尾新入队结点的位置。通过修改队列的存储条件:将队列保留一个元素空间。就可以通过队头 front
和队尾 rear
判断队列是否满了,其公式为 (rear-front+QueueSize)%QueueSize
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| typedef int QElemType; typedef struct { QElemType data[MAXSIZE]; int front; int rear; }SqQueue;
Status InitQueue(SqQueue *Q) { Q->front=0; Q->rear=0; return OK; }
int QueueLength(SqQueue Q) { return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; }
Status EnQueue(SqQueue *Q,QElemType e) { if ((Q->rear+1)%MAXSIZE == Q->front) return ERROR; Q->data[Q->rear]=e; Q->rear[Q->rear+1]%MAXSIZE; return OK; }
Status DeQueue(SqQueue *Q,QElemType *e) { if (Q->front == Q->rear) return ERROR; *e=Q->data[Q->front] Q->front=(Q->front+1)%MAXSIZE return OK; }
|
队列链式存储
队列的链式存储结构,其实就是线性表的单链表,只不过它只能围巾头出而已,我们把它简称为链队列
typedef intQElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front,rear;
}LinkQueue;
Status EnQueue(LinkQue *Q,QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s)
exit(OVERLOW); //存储分配失败
s->data=e;
s->next=NULL;
Q->rear->next=s;
Q->rear=s;
return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{
Queue p;
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=Qfront;
free(p);
return OK;
}