【数据结构】栈、队列

前言

临阵磨枪,不快也光。应付考试,大量摘抄课本内容,会陆续添加其他相关内容及代码。最后祝我考试顺利。

小结

特性:先进后出

 

 图中base:栈底指针;top:栈顶指针

顺序栈的实现 :

//本代码栈顶指针指向栈顶元素的后一元素
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10//顺序栈存储空间分配

typedef struct{
    int *base;//栈底指针
    int *top;//栈顶指针
    int stacksize;//栈可用最大容量
}sqStacks;

sqStacks initStack(sqStacks s){//初始化
    s.base=(int*)malloc(s.stacksize*sizeof(int));
    if(!s.base) exit(0);//存储分配失败,终止程序
    s.top=s.base;//top初始为base,空栈
    s.stacksize=MAXSIZE;
    printf("栈初始化成功\n");
    return s;
}
sqStacks push(sqStacks s,int ele){//入栈
    if(s.top-s.base==s.stacksize){
        printf("栈满\n");
        return s;
    }
    *s.top=ele;//元素压入栈顶
    printf("%d入栈\n",*s.top);
    s.top++;//栈顶指针加1
    return s;
}
sqStacks pop(sqStacks s){//出栈
    if(s.top!=s.base){
        s.top--;
        printf("%d出栈\n",*s.top);
        return s;
    }
    printf("空栈\n");
    return s;
}
int main()
{
    sqStacks s;
    s=initStack(s);
    s=push(s,1);
    s=push(s,2);
    s=push(s,3);
    s=pop(s);
    s=pop(s);
    s=pop(s);
    s=pop(s);
    return(0);
}
/* 标准输出:
栈初始化成功
1入栈
2入栈
3入栈
3出栈
2出栈
1出栈
空栈
*/

队列

特性:先进先出(First In First Out, FIFO)

//----- 队列的顺序存储结构-----
#define MAXSIZE 100;
typedef struct {
    int *base;//存储空间的基地址
    int front;//头指针
    int rear;//尾指针
}sqQueue;

 为了在 C 语言中描述方便起见,在此约定:初始化创建空队列时,令 front = rear = 0 , 每当插入 新的队列尾元素时,尾指针 rear增1; 每当删除队列头元素时, 头指针 front增1。因此,在非空队列 中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置,如图 3.12所示。

假设当前队列分配的最大空间为 6, 则当队列处于图 3.12(d) 所示的状态时不可再继续 插入新的队尾元素,否则会出现溢出现象, 即因数组越界而导致程序的非法操作错误。 事实 上,此时队列的实际可用空间并未占满,所以这种现象称 为 “假溢出"。这是由 "队尾入队,队头出队” 这种受限制 的操作造成的。 怎样解决这种 “假溢出” 问题呢? 一个较巧妙的办法是将顺序队列变为一个环状的空间,如图 3.13 所示,称之为循环队列。 

在图 3.14 (a) 中,队头元素是 J5, 在元素J6入队之前,在 Q.rear 的值为 5, 当元素J6入队之 后,通过 “模 ” 运算,Q.rear = (Q.rear + 1)%6, 得到 Q.rear 的值为 0, 而不会出现图 3.12(d) 的 “假溢出“ 状态。

在图 3.14(b) 中, J7、J8、J9、J10相继入队,则队列空间均被占满,此时头、尾指针相同。

在图 3.14 (c) 中, 若J5和J6相继从图 3.14(a)所示的队列中出队,使队列此时呈 “空 ” 的 状态, 头、尾指针的值也是相同的。由此可见,对于循环队列不能以头、尾指针的值是否相同来判别队列空间是 “满 ” 还是 “空 ”。 在这种情况下, 如何区别队满还是队空呢?

通常有以下两种处理方法:

 (1)少用一个元素空间, 即队列空间大小为m时,有m-1个元素就认为是队满。这样判断队空的条件不变, 即当头、 尾指针的值相同时, 则认为队空;而当尾指针在循环意义上加1后是等于头指针,则认为队满。 因此,在循环队列中队空和队满的条件是:

队空的条件: Q.front = Q.rear

队满的条件: (Q rear+ 1)%MAXQSIZE = Q.front

如图 3.14 (d)所示,当J7、J8、J9 进入图 3.14(a)所示的队列后, (Q.rear+ 1)%MAXQSIZE的值等千 Q.front, 此时认为队满。

(2)另设一个标志位以区别队列是 “空 ” 还是 “满 "。

链队

链队是指采用链式存储结构实现的队列。通常链队用单链表来表 示,如图 3.15 所示。 一个链队显然需要两个分别指示队头和队尾的指 针(分别称为头指针和尾指针)才能唯一确定。 这里和线性表的单链表一样, 为了操作方便起见,给链队添加一个头结点, 并令头指针始终指向头结点。

 链队源码

#include <stdlib.h>
#include <stdio.h>

#define MAXSIZE 100;

typedef struct {
    int base;
    struct sqQueue* next;
}sqQueue;

sqQueue* initQueue(){
    sqQueue* queue=(sqQueue*)malloc(sizeof(sqQueue));
    queue->next=NULL;
    return queue;
}
sqQueue* enterQuence(sqQueue* queue,int data){
    sqQueue* elem=(sqQueue*)malloc(sizeof(sqQueue));
    elem->base=data;
    elem->next=NULL;
    queue->next=elem;
    queue=elem;
    printf("%d入队\n",data);
    return queue;
}
sqQueue* delQueue(sqQueue* top,sqQueue* rear){
    if(top->next==NULL){
        printf("队列为空\n");
        return rear;
    }
    sqQueue* q=NULL;
    q=top->next;
    printf("%d出队\n",q->base);
    top->next=q->next;
    if(rear==q){
        rear=top;
    }
    free(q);
    return rear;
}
int main()
{
    sqQueue* queue=NULL,*top=NULL,*rear=NULL;
    queue=top=rear=initQueue();
    rear=enterQuence(rear,1);
    rear=enterQuence(rear,2);
    printf("----------------\n");
    rear=delQueue(top,rear);
    rear=delQueue(top,rear);
    rear=delQueue(top,rear);
    return(0);
}

 参考书目:严蔚敏-《数据结构(C语言版)》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值