关于线性表还有两种比较特殊的线性表——栈和队列
- 栈(Stack)是限定只能在表的一端进行插入和删除操作的线性表。
- 队列(Queue)是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
栈只允许在表尾一端进行插入和删除
队列只允许在表尾一端进行插入,在表头一端进行删除
它们的顺序结构以及链式结构的操作与之前几篇介绍的基本类似(故这里不再细讲,只介绍几种比较特殊的),唯一不同的是他们的操作受到限制
顺序栈的描述
typedef int Element;
typedef struct{
Element *base; //栈的起始位置,栈为空时,base的值为NULL
Element *top; //栈顶指针,始终指向栈顶元素的下一个位置
int StackSize; //当前已分配的存储空间大小,以元素为单位
}SeqStack;
栈的顺序存储结构中,当在一个应用程序中需要使用多个栈时,为了提高空间利用率,就用到了共享栈,即在一段内存空间存有两个相对的栈
#include<stdio.h>
#define TRUE 1
#define FALSE 0
#define ERROR -1
#define MAXSIZE 100 //最大数组空间长度
typedef int Element;
typedef struct{
Element data[MAXSIZE];
int top1; //栈顶指针1
int top2; //栈顶指针2
}SharedStack;
//初始化
void InitStack(SharedStack *S){
S->top1=0;
S->top2=MAXSIZE-1;
}
//入栈操作,把元素x压人编号为stacknumber的栈中
int PushStack(SharedStack* S,Element x,int stacknumber){
if(S->top1-1==S->top2) //共享栈满
return FALSE;
switch(stacknumber){
case 1:
S->data[S->top1++]=x;
break;
case 2:
S->data[S->top2++]=x;
break;
}
return TRUE;
}
//出栈操作,用元素x返回编号为stacknumber的栈顶元素
int PopStack(SharedStack* S,int stacknumber){
Element x;
switch(stacknumber){
case 1:
if(S->top1==0) //栈为空
return ERROR;
x=S->data[--S->top1];
break;
case 2:
if(S->top2==MAXSIZE-1) //栈为空
return ERROR;
x=S->data[++S->top2];
break;
}
return x;
}
栈的链式存储结构,描述如下
typedef int Element;
typedef struct Node{
Element data;
struct Node *next;
}StackNode,*LinkStack;
和单链表是不是完全一样啊,接下来就用一道题简单练习
#include<stdio.h>
#define TRUE 1
#define FALSE 0
#define ERROR -1
typedef char Element;
typedef struct Node
{
Element data;
struct Node *next;
} StackNode,*LinkStack;
//初始化
LinkStack InitLinkStack(LinkStack top)
{
top = (LinkStack)malloc(sizeof(StackNode));
top->next=NULL;
return top;
}
int PushLinkStack(LinkStack top,Element x)
{
LinkStack p;
p=(LinkStack)malloc(sizeof(StackNode));
if(!p)return FALSE;
p->data=x;
p->next=top->next;
top->next=p;
}
int PopLinkStack(LinkStack top,Element *x)
{
LinkStack p;
if(top->next==NULL)return FALSE;
p=top->next;
*x=p->data;
top->next=p->next;
free(p);
return TRUE;
}
int IsEpty(LinkStack S)
{
if(!S->next)return TRUE;
return FALSE;
}
int main()
{
int i,f=1;
char c[100],ch;
LinkStack top;
top = InitLinkStack(top);
gets(c);
for(i=0; c[i]!='\0'; i++)
{
if(c[i]=='('||c[i]=='{'||c[i]=='[')
PushLinkStack(top,c[i]);
else if(c[i]==')'||c[i]=='}'||c[i]==']')
{
if(!IsEpty(top))
{
PopLinkStack(top,&ch);
if(c[i]==')'&&ch!='('||c[i]=='}'&&ch!='{'||c[i]==']'&&ch!='[')
{
printf("0");f=0;
break;
}
}
else
{
printf("0");f=0;
break;
}
}
}
if(IsEpty(top)&&f)
printf("1");
else {
if(f)
printf("0");
}
}
下面是一段输出所有出栈情况的代码
#include <stdio.h>
typedef struct
{
int *stk;
int top;
int Size;
} Stack;
void initstack(Stack *s,int n)
{
s->stk = (int*)malloc((s->Size=n)*sizeof(int));
s->top = 0;
}
//将栈s中的元素copy到ss中
void copystack(Stack *ss,Stack *s)
{
int i;
if(ss->stk)
free(ss->stk);
ss->stk = (int*)malloc((ss->Size=s->Size)*sizeof(int));
ss->top = s->top;
for(i=s->top-1; i>=0; i--)
ss->stk[i]=s->stk[i];
}
//输出栈s中的元素
void outputstack(Stack* s)
{
int i;
for(i=0; i<s->top; i++) printf("%d ",s->stk[i]);
printf("\n");
}
//返回栈是否为空
int stackempty(Stack* s)
{
return !s->top;
}
//入栈
void push(Stack* s, int x)
{
s->stk[s->top++] = x;
}
//出栈
int pop(Stack* s)
{
return s->stk[--s->top];
}
//栈的调度
void stackseq(Stack *input, Stack *s, Stack *output)
{
//栈input中存放要输入的元素
Stack ii,ss,oo;
if(stackempty(input)&&stackempty(s)) //如果数据已经全部输入完毕,且栈s为空,则输出序列
{
outputstack(output);
}
else //还有元素要输入
{
//ss出栈一个的情况
if(!stackempty(s))
{
initstack(&ii, 1);
copystack(&ii, input);
initstack(&ss, 1);
copystack(&ss, s);
initstack(&oo, 1);
copystack(&oo, output);
push(&oo, pop(&ss));
stackseq(&ii, &ss, &oo);
}
//上一个入栈不出,下一个入栈之后继续遍历剩下的全部情况
if(!stackempty(input)){ //如果栈input不为空
push(s,pop(input)); //将input栈顶元素压入s
stackseq(input, s, output); //重新调度
}
}
}
void main()
{
int i,n;
Stack input,s,output;
//栈input做输入处理,逆序存储输入数据
initstack(&input,20);
//栈s为空
initstack(&s,20);
//栈output为空
initstack(&output,20);
scanf("%d",&n);
for(i=n; i>0; i--)
push(&input,i);
stackseq(&input,&s,&output);
}
这种方法运用了递归方法,从第1个入栈即出栈,然后去遍历剩下的2~n的出入栈情况(与1~n方法相同),接着第一个入栈不出栈,第2个入栈,继续遍历剩下的3~n的出入栈情况,依次类推,此题解。
顺序队列的实现太过于浪费空间,因此,这里我们使用循环队列
代码如下
//---循环队列----
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define MAXQSIZE 200 //---循环顺序队列存储结构----
typedef int Element; //队列中的元素类型
typedef struct
{
Element *base;
int front;
int rear;
}SqQueue; //循环队列类型
//初始化队列
int InitQueue(SqQueue *Q)
{
Q->base =(Element *) malloc(MAXQSIZE * sizeof (Element));
if(Q->base )
{
Q->front =0;
Q->rear =0;
return TRUE;
}
return FALSE;
}
//入队
int EnQueue(SqQueue *Q, Element e)
{
//如果队满
if ((Q->rear +1)% MAXQSIZE==Q->front)
return FALSE;
Q->base [Q->rear]=e;
Q->rear=(Q->rear +1 )%MAXQSIZE;
return TRUE;
}
//出队
int DeQueue(SqQueue *Q, Element *e)
{
//如果队空
if (Q->rear ==Q->front)
return FALSE;
*e= Q->base [Q->front];
Q->front =(Q->front +1) % MAXQSIZE;
return TRUE;
}
//判断队空
int EmptyQueue(SqQueue Q){
if(Q.front ==Q.rear )
return TRUE; //队列空
return FALSE;
}
//判断队满
int FullQueue(SqQueue Q)
{
//如果队满
if(Q.front ==(Q.rear+1)% MAXQSIZE )
return TRUE; //队满
return FALSE;
}
至于队列的链式结构,只需把单链表的插入删除操作改为只在队头删除,队尾插入即可
#include<stdio.h>
#define TRUE 1
#define FALSE 0
#define ERROR -1
typedef int Element;
typedef struct Node
{
Element data;
struct Node *next;
} LinkNode,*LinkList;
typedef struct
{
LinkList font; //队头
LinkList rear; //队尾
} LinkQueue;
//初始化
void InitLinkQueue(LinkQueue *Q)
{
Q->font = (LinkQueue*)malloc(sizeof(LinkQueue));
Q->rear=Q->font;
Q->font->next=NULL;
}
//入队操作,把元素x人队尾
int EnLinkQueue(LinkQueue* Q,Element x)
{
LinkList New;
New=(LinkList)malloc(sizeof(LinkNode));
if(New)
{
New->data=x;
New->next=NULL;
Q->rear->next=New;
Q->rear=New;
return TRUE;
}
return FALSE;
}
//出队操作,删除队头元素,用x返回其值
int DeLinkQueue(LinkQueue* Q,Element* x)
{
LinkList p;
if(Q->font==Q->rear)return FALSE;
p=Q->font->next;
Q->font->next=p->next;
if(Q->rear==p)
Q->rear=Q->font;
*x=p->data;
free(p);
return TRUE;
}
//判断队空
int IsLQEmpty(LinkQueue *Q)
{
if(Q->rear==Q->font) return TRUE;
return FALSE;
}
//打印队列
void printLinkQueue(LinkQueue Q)
{
if(IsLQEmpty(&Q)){
printf("None\n");
return;}
while(Q.font->next)
{
Q.font=Q.font->next;
if(!Q.font->next)
printf("%d",Q.font->data);
else
printf("%d ",Q.font->data);
}
printf("\n");
}
int main()
{
char c;
int x;
LinkQueue q;
InitLinkQueue(&q);
while(scanf("\n%c",&c)&&c!='Q')
{
switch(c)
{
case 'E':
scanf("%d",&x);
EnLinkQueue(&q,x);
break;
case 'D':
DeLinkQueue(&q,&x);
break;
case 'P':
printLinkQueue(q);
break;
}
}
}
到此,线性表就结束了