我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C语言编程数据结构的栈和队列

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C语言编程数据结构的栈和队列

栈是一种以后进先出为顺序对对象进行添加或删除的数据结构
对栈进行形象记忆就像是桌子上的一堆书或一堆盘。对盘子取或者存盘子,都只能对最上面的书或者盘子进行操作。

在这里插入图片描述

对于栈而言,只有弹栈才能获取其数据。
当我们用C语言实现栈这个数据结构。
其实有三种方法实现

1,数组

2,单链表

3,双向链表

但是,对于双向链表,实现栈而言过于复杂。
可以选择数组或者单链表。

数组实现

标题全部代码

Stack_array.c


#include "Stack_array.h"
void InitStack(STstack* st)//栈的初始化
{
	st->top = 0;
	st->arr = (STData*)malloc(CAP*sizeof(STData));
	st->capacity = CAP;
}
void StackPush(STstack* st, STData n)//元素入栈
{
	if (st->top == st->capacity)//判断是否需要扩容
	{
		StackExpansion(st);
	}
	st->arr[st->top++] = n;
}
STData StackPop(STstack* st)//元素退栈
{
	assert(st);
	assert(!StackEmpty(st));//判断是否为空栈
	return st->arr[--st->top];
}
int StackEmpty(STstack* st)//判断栈是否为空
{
	if (st->top == 0)
		return 1;
	return 0;
}
void StackDestory(STstack* st)//销毁栈,防止内存泄漏
{
	free(st->arr);
	st->arr = NULL;
}
void StackExpansion(STstack* st)//扩容
{
	STData* tmp = (STData*)realloc((STData*)st->arr, sizeof(STData) * (st->capacity) * 2);
	if (tmp == NULL)
	{
		printf("Exparsion Error\n");
		exit(-1);
	}
	st->arr = tmp;
	st->capacity *= 2;
}
void StackPrint(STstack* st)//打印栈的元素,但前提是要退栈才能得到元素
{
	while(st->top)
	{
		STData ret = StackPop(st);
		printf("%d ", ret);
	}
}

Stack_array.h


#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define CAP 4
typedef int STData;
typedef struct Stack//结构体用于维护栈
{
	int top;//栈顶标记
	STData* arr;//栈的指针
	int capacity;//栈的容量
}STstack;
void InitStack(STstack* st);//栈的初始化
void StackPush(STstack* st, STData n);//元素入栈
STData StackPop(STstack* st);//元素退栈
void StackExpansion(STstack* st);//扩容
int StackEmpty(STstack* st);//判断栈是否为空
void StackDestory(STstack* st);//销毁栈,防止内存泄漏
void StackPrint(STstack* st);//打印栈的元素,但前提是要退栈才能得到元素

对于数组实现而言。创建一个结构体用于维护整个栈。而其中有一个用于链接创建的数组。


typedef int STData;
typedef struct Stack//结构体用于维护栈
{
	int top;//栈顶标记
	STData* arr;//栈的指针
	int capacity;//栈的容量
}STstack;

作为数组栈,需要一个动态的数组。则这就需要一个Capacity作为衡量是否需要扩容的标准。而top需要作为入栈元素的位置。
当top的值等于Capacity时就意味着栈已经满了。因为数组是从0开始的

在这里插入图片描述

初始化数组栈

在初始化时,要先动态开辟一个数组空间,且,未压栈压入数据元素,其top要设为0.要保证当需要压栈时有明确指定的空间。同时,top的位置要为最后压入数据的下一个下标。


void InitStack(STstack* st)//栈的初始化
{
	st->top = 0;
	st->arr = (STData*)malloc(CAP*sizeof(STData));
	st->capacity = CAP;
}

满栈后扩容

其Capacity要作为判断是否满栈的标准。且,满栈后要进行扩容(因为是动态数组)。


void StackExpansion(STstack* st)//扩容
{
	STData* tmp = (STData*)realloc((STData*)st->arr, sizeof(STData) * (st->capacity) * 2);
	if (tmp == NULL)
	{
		printf("Exparsion Error\n");
		exit(-1);
	}
	st->arr = tmp;
	st->capacity *= 2;
}

同时,还要每次更改栈的容量,为下一次是否满栈作为标准。

是否为空栈


int StackEmpty(STstack* st)//判断栈是否为空
{
	if (st->top == 0)
		return 1;
	return 0;
}

其是否为空。也就是top的位置在数组的0下标位。

压栈和退栈


void StackPush(STstack* st, STData n)//元素入栈
{
	if (st->top == st->capacity)//判断是否需要扩容
	{
		StackExpansion(st);
	}
	st->arr[st->top++] = n;
}
STData StackPop(STstack* st)//元素退栈
{
	assert(st);
	assert(!StackEmpty(st));//判断是否为空栈
	return st->arr[--st->top];
}

压栈
每次压栈,都需要判断是否满栈,并决定是否扩容。
同时,当在原先top位置的数位置进行赋值。并之后要将top向后移动一个位置。保证下一次压栈。

退栈
退栈返回top的上一个位置的元素。同时top向前移动一个位置,不需要free,下次压栈会自动覆盖。

链表实现

stack_chain.h


#include <stdio.h>
#include <stdlib.h>
#define N 3
typedef struct stackele
{
	int n;
	int* point;
}sta;
sta* top;
void initstack(sta* a);//初始化栈
void pushstack(sta* a,int num);//入栈
//void printstack(sta* a);//打印栈
//void fullstack(sta* a);//检查是否满栈的情况
void emptystack(sta* a);//检查是否空栈的情况
int popstack(sta*a);//出栈


stack_chain.c


#include "stack_chain.h"
void initstack(sta* a)//初始化栈
{
	top= NULL;
}
void pushstack(sta* a, int num)//入栈
{
	sta* p = (sta*)malloc(sizeof(sta));
	p->n = num;//新节点赋值
	p->point = top;
	top = p;
}
int popstack(sta* a)//出栈
{
	emptystack(a);//检查是否空栈的情况
	int date;
	sta* des = top;
	top = top->point;
	date = des->n;
	free(des);
	des = NULL;
	return date;
}
void emptystack(sta* a)//检查是否空栈的情况
{
	if (top == NULL)
	{
		printf("Stack empty");
		exit(0);
	}
}

对于链表实现栈而言,和数组其实差不多。只不够,每次压栈都需要重新动态开辟一个新节点,并且链入栈中。但是,这并不是普通的直接链入。而是需要头插入栈。

在这里插入图片描述

这样头插入栈,可以方便退栈的时候,可以找到上一个元素。而压栈是不需要什么顺序。每一个压栈节点就是top节点。

整个压栈流程

在这里插入图片描述


void pushstack(sta* a, int num)//入栈
{
	sta* p = (sta*)malloc(sizeof(sta));
	p->n = num;//新节点赋值
	p->point = top;
	top = p;
}

整个弹栈流程

在这里插入图片描述


int popstack(sta* a)//出栈
{
	emptystack(a);//检查是否空栈的情况
	int date;
	sta* des = top;
	top = top->point;
	date = des->n;
	free(des);
	des = NULL;
	return date;
}

出栈情况

尤其要把握一个条件:空栈
由于不是数组,且链式结构的特性,是不需要扩容的。即不需要判断满栈的情况。
只考虑空栈的条件


void emptystack(sta* a)//检查是否空栈的情况
{
	if (top == NULL)
	{
		printf("Stack empty");
		exit(0);
	}
}

这里空栈的条件是top指针指向NULL时也就是

在这里插入图片描述

为什么呢?
因为每次弹栈的时候,都会free掉top指向的空间然后让top指向下一个节点。就这样不断移动。但是我设计初始化的时候是top= NULL;而且每次压栈都是p->point = top;这就会有一个标准来限定空栈的情况。

对于栈而言,其更像是一个递归的具象化。

队列

在这里插入图片描述

这种数据结构就像是银行柜台的取号机,
先取号的先去柜台。

始终满足先入先出的概念

队列的实现

queue_chain.h


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int QUData;
typedef struct queue
{
	QUData data;
	struct queue* next;
}queue;
typedef struct Queue//结构体用于维护队列
{
	queue* Dequeue;//队头指针
	queue* Enqueue;//队尾指针
}QUqueue;
void InitQueue(QUqueue* qu);//栈的初始化
void QueuePush(QUqueue* qu, QUData n);//元素入队
QUData QueuePop(QUqueue* qu);//元素出队
int QueueEmpty(QUqueue* qu);//判断队列是否为空
void QueueDestory(QUqueue* qu);//销毁队,防止内存泄漏
void QueuePrint(QUqueue* qu);//打印队列中的元素,但前提是要出队才能得到元素

queue_chain.c


#include "queue_chain.h"
void InitQueue(QUqueue* qu)//队列的初始化
{
	qu->Dequeue = qu->Enqueue = NULL;
}
void QueuePush(QUqueue* qu, QUData n)//元素入队
{
	queue* newcell = (QUData*)malloc(sizeof(QUData));
	newcell->data = n;
	newcell->next = NULL;
	if (qu->Dequeue == NULL)
	{
		qu->Enqueue = qu->Dequeue = newcell;
	}
	else
	{
		qu->Enqueue->next = newcell;
		qu->Enqueue = newcell;
	}
}
QUData QueuePop(QUqueue* qu)//元素出队
{
	if (QueueEmpty(qu))
	{
		printf("Queue Is Empty");
		exit(-1);
	}
	QUData ret = qu->Dequeue->data;
	qu->Dequeue = qu->Dequeue->next;
	return ret;
}
int QueueEmpty(QUqueue* qu)//判断队列是否为空
{
	if (qu->Dequeue == qu->Enqueue)
		return 1;
	return 0;
}
void QueueDestory(QUqueue* qu)//销毁队,防止内存泄漏
{
	queue* cur = qu->Dequeue;
	while (cur)
	{
		queue* pnext = cur->next;
		free(cur);
		cur = pnext;
	}
	qu->Dequeue = qu->Enqueue = NULL;
}
void QueuePrint(QUqueue* qu)//打印队列中的元素,但前提是要出队才能得到元素
{
	queue* cur = qu->Dequeue;
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
}

队 毕竟是先入先出的数据结构。
所以要两个指针,
qu->Dequeue 指向队头,
qu->Enqueue 指向队尾,
不然每次都去找队尾是相当浪费时间的。

一个结构体类型用于维护这个队列


typedef int QUData;
typedef struct queue//描述每个队的元素
{
	QUData data;
	struct queue* next;
}queue;
typedef struct Queue//结构体用于维护队列
{
	queue* Dequeue;//队头指针
	queue* Enqueue;//队尾指针
}QUqueue;

队头指针负责出队,
队尾指针负责入队。

概念流程图

入队

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

入队列的实现


void QueuePush(QUqueue* qu, QUData n)//元素入队
{
	queue* newcell = (QUData*)malloc(sizeof(QUData));
	newcell->data = n;
	newcell->next = NULL;
	if (qu->Dequeue == NULL)
	{
		qu->Enqueue = qu->Dequeue = newcell;
	}
	else
	{
		qu->Enqueue->next = newcell;
		qu->Enqueue = newcell;
	}
}

**当然,入队列在刚开始的时候,头尾指针还是一起指向NULL。
当入第一个元素时,那个元素即是第一个元素也是最后一个元素。要独立判断。**这是一个特殊情况。

出队

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

出队列的实现


QUData QueuePop(QUqueue* qu)//元素出队
{
	if (QueueEmpty(qu))
	{
		printf("Queue Is Empty");
		exit(-1);
	}
	QUData ret = qu->Dequeue->data;
	qu->Dequeue = qu->Dequeue->next;
	return ret;
}

但是每次出队列都需要判断是否为空队。如果是空队还继续出队会相当于NULL->next ,这是直接报错的。

所以还要一个函数判断是否空队。

是否空队


int QueueEmpty(QUqueue* qu)//判断队列是否为空
{
	if (qu->Dequeue == qu->Enqueue)
		return 1;
	return 0;
}

空队就是相当于回到了初始化的情形

qu->Dequeue = qu->Enqueue = NULL;

也就是两者都指向同一处,也就是NULL。

以上就是C语言编程数据结构的栈和队列的详细内容,更多关于C语言数据结构的资料请关注编程网其它相关文章!

感谢观看~

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C语言编程数据结构的栈和队列

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Go语言有没有队列和栈结构

这篇文章主要介绍“Go语言有没有队列和栈结构”,在日常操作中,相信很多人在Go语言有没有队列和栈结构问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Go语言有没有队列和栈结构”的疑惑有所帮助!接下来,请跟着小编
2023-07-04

Go语言并发数据结构:队列和栈的性能优化

go 语言中,队列和栈的性能可以通过以下优化实现:使用 sync.mutex 和 sync.cond 实现并发队列,保证读写操作的安全性。使用 sync.mutex 和 atomic 包实现并发栈,确保 top 指针更新的原子性。实战案例中
Go语言并发数据结构:队列和栈的性能优化
2024-04-08

Go语言数据结构全面解析:队列和栈解读

队列遵循先进先出原则,在go语言中可使用链表实现。栈遵循后进先出原则,可使用切片便捷创建。队列适用于需按序处理数据的场景,如打印任务队列或消息队列。栈适用于需倒序处理数据的场景,如函数调用栈或后缀表达式求值。Go语言数据结构全面解析:队列和
Go语言数据结构全面解析:队列和栈解读
2024-04-08

Go语言数据结构精解:掌握队列和栈的奥秘

队列遵循 fifo 原则,提供 enqueue、dequeue 和 peek 操作;栈遵循 lifo 原则,提供 push、pop 和 peek 操作。队列用于任务队列,栈用于函数调用、递归和括号匹配。Go 语言数据结构精解:掌握队列和栈的
Go语言数据结构精解:掌握队列和栈的奥秘
2024-04-08

C语言数据结构之栈与队列怎么相互实现

本篇内容介绍了“C语言数据结构之栈与队列怎么相互实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、用对列实现栈题干要求:细节分析:队列是
2023-07-02

Go语言数据结构探究:队列与栈的应用

go 语言中,队列遵守先进先出 (fifo) 原则,使用标准库中的 list 包实现,常用于消息传递系统;栈遵守后进先出 (lifo) 原则,常用于函数调用跟踪和括号匹配,可以使用切片实现。Go语言数据结构漫谈:队列与栈的应用队列队列是
Go语言数据结构探究:队列与栈的应用
2024-04-08

数据结构TypeScript之栈和队列详解

这篇文章主要介绍了数据结构TypeScript之栈和队列详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-30

C++数据结构的栈与队列实例分析

今天小编给大家分享一下C++数据结构的栈与队列实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 栈1.1 栈的概念
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录