0
点赞
收藏
分享

微信扫一扫

数据结构学习(3.栈与队列)

栈和队列


栈和队列的定义和特点

栈 后进先出-手电筒电池
队列 先进先出-排队
栈和队列是限定插入和删除只能在表的端点进行的线性表

栈的定义和特点

栈(stack)是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表(后进先出)
表尾(an)栈顶(top)
表头(a1)栈底(base)

  • 定义:限定只能在表的一端进行插入和删除运算的线性表(只能在栈顶操作)
  • 逻辑结构:一对一关系
  • 存储结构:顺序表和链栈存储均可
  • 运算规则:后进先出,栈顶运算

队列的定义和特点

队列(queue)是一种先进先出的线性表,在表尾插入,表头删除

  • 定义:是一种先进先出的线性表,在表尾插入,表头删除
  • 逻辑结构:一对一
  • 存储结构:顺序队或链队
  • 运算规则:先进先出

栈的表示和操作的实现

栈的抽象数据类型定义

ADT stack{
    数据对象:
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
    基本操作:
    InitStack(&S): 初始化操作,建立一个空栈S。
    DestroyStack(&S): 若栈存在,则销毁它。
    ClearStack(&S): 将栈清空。栈置空操作
    StackEmpty(S): 若栈为空,返回true,否则返回false。
    GetTop(S,&e): 若栈存在且非空,用e返回S的栈顶元素。
    Push(&S,e): 入栈操作(压栈操作),若栈S存在,插入新元素e到栈S中并成为栈顶元素。 
    Pop(&S,&e): 出站操作,删除栈S中栈顶元素,并用e返回其值。
    StackLength(S): 返回栈S的元素个数。即求栈的长度
}ADT Stack

栈的顺序存储-顺序栈
栈的链式存储-链栈

顺序栈的表现和实现

空栈:base == top是栈空标志
栈满:top-base == stacksize

使用数组作为顺序栈存储方式的特点:简单方便,但是容易溢出

  • 上溢:栈满,又要压入元素
  • 下溢:栈空,又要弹出元素
    上溢是种错误,使问题的处理无法进行;下溢是一种结束条件,即问题处理结束
  • 顺序栈存储结构描述
#define MAXSIZE 100
typedef struct{
    SElemType *base;//栈底指针
    SElemType *top;//栈顶指针
    int stacksize;//栈可用最大容量
}SqStack;
  • 顺序栈的初始化
Status InitStack(SqStack &S)//构造一个空栈
{
    S.base=(SElemType*)malloc(MAXSIZE*sizeof(SqStack));
    if(!S.base)
        return ERROR;
    S.top=S.base;
    S.stacksize=MAXSIZE;
    return OK;
}
  • 顺序栈判断是否为空
Status StackEmpty(SqStack S)
{
    if(S.base == S.top)
        return TRUE;
    else
        return FALSE;
}
  • 顺序栈长度
int StackLength(SqStack S)
{
    return S.top-S.base;
}
  • 清空顺序栈
Status ClearStack(SqStack &S)
{
    if(S.base)
        S.top=S.base;
        return OK;
}
  • 销毁顺序栈
Status DestroyStack(SqStack &S)
{
    if(S.base)
    {
        free(S.base);
        S.stacksize=0;
        S.base=S.top=NULL;
    }
    return OK;
}
  • 顺序栈入栈
#define STACKINCREMENT 100
Status Push(SqStack &S,SElemType e)
{
    if(S.top-S.base >= S.stacksize)//若存储空间已满,则扩充
    {
        S.base=(SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
        if(!S.base)//若分配空间失败
        {
            printf("OVERFLOW");
            return ERROR;
        }
        S.top=S.base+S.stacksize;//修改空间增加后的基地址
        S.stacksize += STACKINCREMENT;//修改增加空间后的基地址
    }
    *S.top++ = e;//e压栈后,top指针再后移一位
    return OK;
}
  • 顺序栈出栈
Status Pop(SqStack &S,SElemType &e)
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK,否则ERROR
{
    if(S.base == S.top)
    {
        printf("THE STACK IS NULL");
        return ERROR;
    }
    e=*--S.top;
}

链栈的表现和实现

链栈是__运算受限__的单链表,只能在链表头部进行操作

  • 链栈的存储结构描述
typedef int SElemType;
typedef struct SNode{
    SElemType data;
    struct SNode *next;
}SNode,*LinkStack;
LinkStack S;//创建一个指针头指针,指向栈顶元素
  • 链栈的初始化
void InitStack(LinkStack &S)
{
    S=NULL;
    return OK;
}
  • 判断链栈是否为空
Status StackEmpty(LinkStack S)
{
    if(S == NULL)return TRUE;
    else return FALSE;
}
  • 链栈入栈
Status Push(LinkStack &S,SElemType e)
{
    LinkStack p=(LinkStack)malloc(sizeof(SNode));
    if(!p)
        return ERROR;
    p->data=e;
    p->next=S;//将新结点插入栈顶
    S=p;//修改栈顶指针
    return OK;
}
  • 链栈的出栈
Status Pop(LinkStack &S,SElemType &e)
{
    if(S == NULL)
        return ERROR;
    LinkStack p=S;//p指针来指向栈顶元素
    e=p->data;//传被删数据域的值
    S=p->next;//将栈顶指针指向原栈顶元素的下一个元素结点
    free(p);
    return OK;
}
  • 去栈顶元素
SElemType GetTop(LinkStack S)
{
    if(S!=NULL)
        return S->data;
}

栈与递归

  • 例如:递归求n的阶乘
    分治法求解递归问题的一般形式
void p(参数表)
{
    if(递归结束条件)可直接求解步骤---基本项
    else p(较小参数)---归纳项
}
c语言学习过略过。。。

队列的表示和操作的实现

队列的抽象数据类型定义

ADT 队列 (Queue)
{
    数据对象
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系 。
    基本操作
    InitQueue(&Q) :初始化操作,建立一个空队列Q。
    DestroyQueue(&Q) :若队列Q存在,则销毁它。
    ClearQueue(&Q) :将队列Q清空。
    QueueEmpty(Q) :若队列Q为空,返回true,否则返回false。
    GetHead(Q,&e) :若队列Q存在且非空,用e返回队列Q的队头元素。
    EnQueue(&Q,e) :若队列Q存在,插入新元素e到队列Q中并成为队尾元素 。
    DeQueue(&Q,&e) :删除队列Q中队头元素,并用e返回其值。
    QueueLength(Q) :返回队列Q的元素个数,即队长
    .....队列置空,遍历队列等操作.....
}ADT Queue

顺序队列的表示与操作

  • 顺序队列的存储结构描述
#define MAXQSIZE 100
Typedef struct{
    QElemType *base;//初始化的动态分配存储空间
    int front;//指示队首元素存储单元的位置(队首指针)
    int rear;//指示队尾元素的下一存储单元的位置(队尾指针)
    //两个表示下标位置,不是真正的指针
}SqQueue;

初始情况:front=rear=0;
入队:base[rear]=x;rear++;
出队:x=base[front];front++;
空队标志:front==rear
真溢出:front=0; rear=MAXQSIZE;
假溢出:front!=0; rear=MAXQSZIE;

  • 解决假溢出–引入循环队列
    base[0]接在base[MAXQSIZE-1]之后,若rear+1M,则rear=0;
    实现方法:利用
    模(%)运算==
    插入元素:
    Q.base[Q.rear]=x;
    Q.rear=(Q.rear+1) % MAXQSIZE;
    删除元素:
    x=Q.base[Q.front];
    Q.front=(Q.front+1) % MAXQSIZE;
  • 循环队列解决队满判断方法–少用一个元素空间
    空队–front==rear
    队满时,因为少用一个元素空间,队尾指针如果再+1,就与队首指针重合
    队满:(rear+1) % MAXQSIZE == front;
  • 循环队列的初始化
Status InitQueue(SqQueue &Q)
{
    Q.base=(QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
    if(!Q.base)
        return ERROR;
        Q.front=Q.rear;
        return OK;
}
  • 循环队列长度
int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);
}
  • 循环队列入队
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;
}
  • 循环队列出队
Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.rear == Q.front)
        return ERROR;
    e=Q.base[Q.front];
    Q.front=(Q.front+1)%MAXQSIZE;
    return OK;
}
  • 取队头元素Q.front
SElemType GetHead(SqQueue Q)
{
    if(Q.rear!=Q.front)
        return Q.base[Q.front];
}

链队列的表示与操作

  • 链队列的存储结构
#define MAXQSIZE 100
typedef struct QNode{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;//链队列的结点类型以及指向结点的指针类型
typedef struct
{
    QueuePtr front;//队首指针
    QueuePtr next;//队尾指针
}LinkQueue;//链队列类型
  • 链队列的初始化
Status InitQueue(LinkQueue &Q)
{
    Q.front=(QueuePtr)malloc(sizeof(QNode));
    if(!Q.front)
        return ERROR;
    Q.front->next=NULL;
    Q.rear=Q.front;
    return OK;
}
  • 销毁链队列
Status DestoryQueue(LinkQueue &Q)
{
    while(Q.front)
    {
        Q.rear = Q.front->next;//用Q.rear来遍历链队列一个一个往下走销毁
        free(Q.front);
        Q.front=Q.rear;//执行到最后成NULL
    }
    return OK;
}
  • 链队列入队
Status EnQueue(LinkQueue &Q,QElemType e)
{
    QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
    if(!p)
        return ERROR;
    p->data=e;
    p->next=Q.rear->next;
    Q.rear->next = p;
    return OK;
}
  • 链队列出队
Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.rear == Q.front)
        return ERROR;
    QueuePtr p = Q.front->next;
    e=p->data;
    Q.front->next=p->next;
    if(p == Q.rear)//如果被删结点时队尾结点
        Q.rear == Q.front;
    free(p);
    return OK;
}
  • 链队列取队头元素
Status GetHead(LinkQueue Q,QElemType &e)
{
    if(Q.rear == Q.front)
        return ERROR;
    e=Q.front->next->data;
    return OK;
}
举报

相关推荐

0 条评论