栈和队列的讲解

前言:栈和队列,严格意义上来说,也属于线性表,因为它们也都用于存储逻辑关系为 "一对一" 的数据。 

一、栈

1.1 定义 

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

从图中可以看出,栈是一种只能从表的一端存取数据且遵循 "先进后出" 原则的线性存储结构。

既然栈也是线性表,那么它就同样有线性表的两种表示形式:顺序栈和链式栈。

1.2 C语言中实际使用(顺序栈基本操作)

#include <stdio.h>
//元素elem进栈
int push(int* a,int top,int elem){
    a[++top]=elem;
    printf("%d\n",elem);
    return top;
}
//数据元素出栈
int pop(int * a,int top){
    if (top==-1) {
        printf("空栈\n");
        return -1;
    }
    printf("%d\n",a[top]);
    top--;
    return top;
}
int main() {
    int a[100];
    int top=-1;
    printf("入栈顺序:\n");
    top=push(a, top, 1);
    top=push(a, top, 2);
    top=push(a, top, 3);
    top=push(a, top, 4);
    top=push(a, top, 5);
        
    printf("\n出栈顺序:\n");
    top=pop(a, top);
    top=pop(a, top);
    top=pop(a, top);
    top=pop(a, top);
    top=pop(a, top);
    top=pop(a, top);
    
    return 0;
}

 输出结果:

1.3 C语言中实际使用(链栈基本操作)

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

//链表中的节点结构
typedef struct lineStack{
    char data;
    struct lineStack * next;
}lineStack;

//stack为当前的链栈,a表示入栈元素
lineStack* push(lineStack * stack,char a){
    //stack为当前的链栈,a表示入栈元素
    lineStack * line=(lineStack*)malloc(sizeof(lineStack));
    line->data=a;
    //新节点与头节点建立逻辑关系
    line->next=stack;
    //更新头指针的指向
    stack=line;
    printf("入栈元素:%c \n", a);
    return stack;
}

//栈顶元素出链栈的实现函数
lineStack * pop(lineStack * stack){
    if (stack) {
        //声明一个新指针指向栈顶节点
        lineStack * p=stack;
        //更新头指针
        stack=stack->next;
        printf("出栈元素:%c   ",p->data);
        if (stack) {
            printf("栈顶元素:%c\n",stack->data);
        }else{
            printf("栈已空\n");
        }
        free(p);
    }else{
        printf("栈内没有元素");
        return stack;
    }
    return stack;
}

int main() {
    lineStack * stack=NULL;
    printf("==== 入栈\n");
    stack=push(stack, '5');
    stack=push(stack, '4');
    stack=push(stack, '3');
    stack=push(stack, '2');
    stack=push(stack, '1');
    
    printf("\n==== 出栈\n");
    stack=pop(stack);
    stack=pop(stack);
    stack=pop(stack);
    stack=pop(stack);
    stack=pop(stack);
    stack=pop(stack);
    return 0;
}

 输出结果:

 

二、队列 

2.1 定义 

 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为 "队尾",进行删除操作的端称为 "队头",数据元素进队列的过程称为 "入队",出队列的过程称为 "出队"。

而队列的两端全是开口,特点是"先进先出"。

队列同样有线性表的两种表示形式:顺序队列和链式队列。

2.2 C语言中实际使用(顺序队列基本操作)

1)顺序普通队列 

#include <stdio.h>
int enQueue(int *a,int rear,int data){
    a[rear]=data;
    rear++;
    printf("入队元素:%d\n", data);
    return rear;
}

void deQueue(int *a,int front,int rear){
    //如果 front==rear,表示队列为空
    while (front!=rear) {
        printf("出队元素:%d\n", a[front]);
        front++;
    }
}

int main() {
    int a[100];
    int front,rear;
    //设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址
    front=rear=0;
    //入队
    printf("==== 入队\n");
    rear=enQueue(a, rear, 1);
    rear=enQueue(a, rear, 2);
    rear=enQueue(a, rear, 3);
    rear=enQueue(a, rear, 4);
    rear=enQueue(a, rear, 5);
    //出队
    printf("\n==== 出队\n");
    deQueue(a, front, rear);
    return 0;
}

结果展示:

 

2)顺序圆形队列 

#include <stdio.h>
#define max 5//表示顺序表申请的空间大小
int enQueue(int *a,int top,int rear,int data){
    //添加判断语句,如果rear超过max,则直接将其从a[0]重新开始存储,如果rear+1和top重合,则表示数组已满
    if ((rear+1)%max==top) {
        printf("空间已满");
        return rear;
    }
    a[rear%max]=data;
    
    printf("* 入队元素:%d \n", data);
    
    rear++;
    return rear;
}
int  deQueue(int *a,int top,int rear){
    //如果top==rear,表示队列为空
    if(top==rear%max) {
        printf("队列为空");
        return top;
    }
    printf("# 出队元素:%d \n",a[top]);
    //top不再直接 +1,而是+1后同max进行比较,如果=max,则直接跳转到 a[0]
    top=(top+1)%max;
    return top;
}
int main() {
    int a[max];
    int top,rear;
    //设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址
    top=rear=0;
    
    printf("==== 圆形队列(*为入队列,#为出队列)\n");
    //入队
    rear=enQueue(a,top,rear, 1);
    rear=enQueue(a,top,rear, 2);
    rear=enQueue(a,top,rear, 3);
    rear=enQueue(a,top,rear, 4);
    //出队
    top=deQueue(a, top, rear);
    //再入队
    rear=enQueue(a,top,rear, 5);
    //再出队
    top=deQueue(a, top, rear);
    //再入队
    rear=enQueue(a,top,rear, 6);
    //再出队
    top=deQueue(a, top, rear);
    top=deQueue(a, top, rear);
    top=deQueue(a, top, rear);
    top=deQueue(a, top, rear);
    return 0;
}

输出结果:

  

 2.3 C语言中实际使用(链队列基本操作)

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

//链表中的节点结构
typedef struct QNode{
    int data;
    struct QNode * next;
}QNode;

//创建链式队列的函数
QNode * initQueue(){
    //创建链式队列的函数
    QNode * queue=(QNode*)malloc(sizeof(QNode));
    //对头节点进行初始化
    queue->next=NULL;
    return queue;
}

QNode* enQueue(QNode * rear,int data){
    //用节点包裹入队元素
    QNode * enElem=(QNode*)malloc(sizeof(QNode));
    enElem->data=data;
    enElem->next=NULL;
    //2、新节点与rear节点建立逻辑关系
    rear->next=enElem;
    
    printf("入队元素:%d \n", data);
    
    //3、rear指向新节点
    rear=enElem;
    //返回新的rear,为后续新元素入队做准备
    return rear;
}
QNode* DeQueue(QNode * top,QNode * rear){
    QNode * p = NULL;
    if (top->next==NULL) {
        printf("队列为空\n");
        return rear;
    }
    p=top->next;
    printf("出队元素:%d \n", p->data);
    top->next=p->next;
    if (rear==p) {
        rear=top;
    }
    free(p);
    return rear;
}
int main() {
    QNode * queue,*top,*rear;
    queue=top=rear=initQueue();//创建头结点
    //向链队列中添加结点,使用尾插法添加的同时,队尾指针需要指向链表的最后一个元素
    printf("==== 入队\n");
    rear=enQueue(rear, 1);
    rear=enQueue(rear, 2);
    rear=enQueue(rear, 3);
    rear=enQueue(rear, 4);
    rear=enQueue(rear, 5);
    
    //入队完成,所有数据元素开始出队列
    printf("\n==== 出队\n");
    rear=DeQueue(top, rear);
    rear=DeQueue(top, rear);
    rear=DeQueue(top, rear);
    rear=DeQueue(top, rear);
    rear=DeQueue(top, rear);
    rear=DeQueue(top, rear);
    return 0;
}

 结果展示:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_68949064

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值