栈和队列的实现

简介: 栈和队列的实现

@TOC

一、栈

1.概念

一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,栈中的数据元素遵循后进先出的原则。

注意从栈顶入,栈顶出

在这里插入图片描述

二 、栈的实现(顺序表)

1.函数的定义和结构体的创建——stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int datatype;
typedef struct stack
{
    datatype* a;
    int top;
    int capacity;
}ST;
void stackinit(ST* p);
void stackpush(ST* p, datatype x);
int stacktop(ST* p);
void stackpop(ST* p);
int stacksize(ST* p);
bool stackempty(ST* p);
void stackdestroy(ST* p);

2.函数的调用——test.c

#include"stack.h"
int main()
{
    ST st;
    stackinit(&st);
    stackpush(&st, 1);
    stackpush(&st, 2);
    stackpush(&st, 3);
    stackpush(&st, 4);
    while (!stackempty(&st))//判断是否为空
    {
        printf("%d ", stacktop(&st));//出栈
        stackpop(&st);//移除栈顶元素
    }
    stackdestroy(&st);//内存销毁
    return 0;
}

3.栈的接口

1.初始化

void stackinit(ST* p)//栈的初始化
{
    assert(p);
    p->a = NULL;
    p->top = 0;
    p->capacity = 0;
}

2.入栈

void stackpush(ST* p, datatype x)//入栈
{
    assert(p);
    if (p->top == p->capacity)//扩容
    {
        int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
        datatype* tmp = (datatype*)realloc(p->a, sizeof(datatype) * newcapacity);
        if (tmp != NULL)
        {
            p->a = tmp;
            p->capacity = newcapacity;//扩容成原来的2倍
        }
    }
    p->a[p->top] = x;
    p->top++;
}

在这里插入图片描述

3.移除栈顶元素

void stackpop(ST* p)//移除栈顶元素
{
    assert(p);
    assert(p->top > 0);
    p->top--;
}

4.出栈

int  stacktop(ST* p)//出栈
{
    assert(p);
    assert(p->top > 0);
    return p->a[p->top - 1];//top从0开始,每次入栈top都向后移,所以top-1是实际储存的元素
}

在这里插入图片描述

5.判断为空

bool  stackempty(ST* p)//是否为空
{
    return p->top == 0;//当栈中没有数据时,则为空,为真, 否则为假。
}

6.栈中元素个数

int stacksize(ST* p)//栈中元素个数
{
    assert(p);
    return p->top;//虽然top是指向下一个,但是top从0开始,top正好是元素个数
}

7.内存销毁

void stackdestroy(ST* p)//内存销毁
{
    assert(p);
    free(p->a);//销毁动态开辟数组
    p->a = NULL;
    p->top = 0;
    p->capacity = 0;
}

三、队列

1.概念

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的原则。

入队列:进行插入操作的一段称为队尾

出队列:进行删除操作的一端称为对头

注意  :对尾入,对头出

在这里插入图片描述  

四、队列的实现(链表)

1.函数的定义和结构体的创建——queue.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int datatype;
typedef struct queuenode
{
    datatype data;
    struct queuenode* next;
}queuenode;
typedef struct queue
{
    queuenode * head;
    queuenode * tail;
}queue;
void queueinit(queue*p);
void queuedestroy(queue* p);
void queuepush(queue* p,datatype x);
void queuepop(queue* p);
datatype queuefront(queue* p);
datatype queueback(queue* p);
int queuesize(queue* p);
bool queueempty(queue* p);

2.函数的调用——test.c

#include"queue.h"
int main()
{
    queue p;
    queueinit(&p);
    queuepush(&p, 1);
    queuepush(&p, 2);
    queuepush(&p, 3);
    queuepush(&p, 4);
    while (!queueempty(&p))//判断为空
    {
        datatype front = queuefront(&p);
        printf("%d ", front);
        queuepop(&p);
    }
    queuedestroy(&p);//内存销毁
    return 0;
}

3.取一级指针的原因

正常来说,如果将head与tail放在queuenode内部,应该取二级指针,

但是由于此时定义的是结构体为queue 的变量,改变的是该变量的内部。

所以只取一级指针就可以。

4.队列的接口的实现

1.初始化

void queueinit(queue* p)//初始化队列
{
    assert(p);
    p->head = NULL;
    p->tail = NULL;
}

2.入队列

void queuepush(queue* p,datatype x)//入队列 (队尾入)
{
    assert(p);
    queuenode* newnode = (queuenode*)malloc(sizeof(queuenode));
    newnode->data = x;
    newnode->next = NULL;
    if (p->tail == NULL)
    {
        p->tail = newnode;
        p->head = newnode;
    }
    else
    {
        p->tail->next = newnode;
        p->tail = newnode;
    }
}

在这里插入图片描述

3.删除数据

void queuepop(queue* p)//删除数据
{
    assert(p);
    assert(!queueempty(p));//断言队列是否为空
    queuenode* next = p->head->next;
    free(p->head);
    p->head = next;
    if (p->head == NULL)//当删除只剩下最后一个节点时 head与tail都指向,free(head) ,tail就变成了野指针
    {
        p->tail = NULL;
    }
}

4.取对头数据

datatype queuefront(queue* p)//取队头数据
{
    assert(p->head);
    assert(!queueempty(p));
    return p->head->data;
}

在这里插入图片描述

5.取队尾数据

datatype queueback(queue* p)//取队尾数据
{
    assert(p->head);
    assert(!queueempty(p));
    return p->tail->data;
}

在这里插入图片描述

6.取队的元素个数

int queuesize(queue* p)//队的数量
{
    assert(p);
    int sum = 0;
    queuenode* cur = p->head;
    while (cur != NULL)
    {
        sum++;
        cur= cur->next;
    }
    return sum;
}

7.判断为空

bool queueempty(queue* p)//判断队列是否为空
{
    assert(p);
    return p->head == NULL;
}

8.内存销毁

void queuedestroy(queue* p)//内存销毁
{
    assert(p);
    queuenode* cur = p->head;
    while (cur != NULL)
    {
        queuenode* next = cur->next;
        free(cur);
        cur = next;
    }
    p->head = NULL;
    p->tail = NULL;
}
目录
相关文章
|
15天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
90 9
|
6天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
15 1
|
9天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
12天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
14天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
41 4
|
18天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
数据结构(栈与列队)
数据结构(栈与列队)
17 1
|
1月前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
68 1
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
16 0
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
30 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器

热门文章

最新文章