二、栈和队列
1.1栈的顺序存储
栈是限定仅在表尾进行插入和删除操作的线性表,即后进先出。其中,允许插入和删除的一端称为栈顶,另外一端称为栈底。进栈是插入,出栈是删除。
int Push(Sqstack *s, ElemType e){ //进栈操作
if(s->==MaxSize-1){ //栈满
return 0;
}
s->top++; //栈顶指针+1
s->data[s->top]=e; //新插入元素赋值给栈顶空间
return 1;
}
int Pop(Sqstack *s, ElemType e){ //出栈操作
if(s->top==-1){ //栈为空
return 0;
}
e=s->data[s->top]; //栈顶元素赋值给e
s->top--; //栈顶指针-1
return 1;
}
1.2栈的链式存储
void Push(LinkStack *s, ElemType e){ //进栈
LinkStack p=(LinkStack)malloc(sizeof(StackNode));
p->data=e;
p->next=s->next; //插入p结点作为第一个数据结点
s->next=p;
}
int Pop(LinkStack *s, ElemType e){ //出栈
LinkStack p;
if(s->next==NULL){
return 0; //栈空
}
p=s->next; //p指向第一个数据结点
e=p->data;
s->next=p->next;
free(p);
return 1;
}
栈的顺序存储和链式存储对比:
如果栈的使用过程元素变化不可预料,适合用链式存储,反之,变化在可控范围,适合用顺序存储。
1.3队列的顺序存储
队列是指允许在一端进行插入操作,而在另一端进行删除操作的线性表,即先进先出。允许插入的一端是队尾,允许删除的是队头。
为了避免只有一个元素时,队头和队尾的重合使得处理变得麻烦,所以引入了两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置。当front=rear时,队列为空。
队列这种首尾相接的顺序存储结构称为循环队列。
int QueueLength(SqQueue Q){ //求循环队列的长度
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
int EnQueue(SqQueue *Q, QElemType e){ //入队
if((Q->rear+1)%MAXSIZE==Q->front){
return 0; //队列满
}
Q->data[Q->rear]=e; //将元素e赋值给队尾
Q->rear=(Q->rear+1)%MAXSIZE; //rear指针后移,若到最后则转移到头部
return 1;
}
int DeQueue(SqQueue *Q, QElemType e){ //出队
if(Q->front==Q->rear){
return 0; //队空
}
e=Q->data[Q->front];
Q->front=(Q->front+1)%MAXSIZE; //front指针后移,若到最后则转移到头部
return 1;
}
1.4队列的链式存储
队列的链式存储,就是一个只能尾进头出的单链表。int EnQueue(LinkQueue *Q, QElemType e){ //入队
LinkQueue s=(LinkQueue)malloc(sizeof(QNode));
if(!s){
return 0; //储存分配失败
}
s->data=e;
s->next=NULL;
Q->rear->next=s; //将新结点赋值给队尾结点的后继
Q->rear=s; //将当前s设为队尾结点
return 1;
}
int DeQueue(LinkQueue *Q, QElemType e){ //出队
LinkQueue p;
if(Q->front==Q->rear){ //队空
return 0;
}
p=Q->front->next; //将欲删除的头结点暂存给p
e=p->data;
Q->front->next=p->next; //将原头结点后继赋值给头结点后继
if(Q->rear==p){ //若队头是队尾,则删除后将rear指向头结点
Q->rear=Q->front;
}
free(p);
return 1;
}