浅析数据结构之线性表<四>

关于线性表还有两种比较特殊的线性表——栈和队列

  • 栈(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;
        }
    }
}
到此,线性表就结束了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值