数据结构-栈和队列

1.栈是什么?

栈是一种先入后出后入先出的数据结构,其原理可以理解成从羽毛球桶的一端依次取出羽毛球或放入羽毛球,而且你只能从这端取,参考下面这个动图:
图片来源于网络
存入数据时,数据的存放位置是这样的:
在这里插入图片描述
取出数据时,顺序是这样的:
在这里插入图片描述
大概能明白了栈的先入后出和后入先出了吧

2.栈的代码实现

(在stack.h中声明这些数据结构和函数)
1.首先可以使用宏定义要确定我们要存入数据的类型,使用宏定义的好处就是以后代码的易修改.
假设我们要存入的数据类型是int型的数据,那么如下定义:

typedef int Type;

2.然后声明栈的大小,这里大小以10为例:

#define STACK_SIZE 10

3.栈的结构体声明,在结构体中使用数组来储存我们的数据,数组大小就是我们定义的大小,这样在结构体中可以使用top变量来存储我们要取或者要储存的数组下标值,比如top=1时,我们能取出来的值就是data[1],在存入数据时就会存入到data[top+1]的位置上去,然后top自增1:

typedef struct Stack			//栈的结构体声明
{
	Type data[STACK_SIZE];		//数据域
	int top;					//栈顶元素下标
}stack;

4.声明栈的各个功能,最基本的有栈的初始化、入栈、出栈、获取栈顶元素、判断栈是否为空、判断栈是否满了:

/*栈的功能声明*/

//栈的初始化函数
stack* stack_init();

//数据入栈函数
void stack_push(stack* st,Type val);

//数据出栈函数
Type stack_pop(stack* st);

//获取栈顶元素
Type stack_top(stack* st);

//判断栈是否为空
bool stack_empty(stack* st);

//判断栈是否满了
bool stack_full(stack* st);

5.接下来就是去实现这些功能(在Stack.cpp中实现):
(在Stack.cpp中实现stack.h中的函数)
(1)栈的初始化:
使用assert()断言来判断temp分配内存的情况,如果分配失败就会报错.成功就继续执行代码
在初始化时将top的值赋值为-1,因为top值对应了我们要存或者取的数据的数组下标,在初始化时数组中是没有值的,如果将top值赋值为0的话,就对应了数组[0]的数据,这样是错误的!

stack* stack_init()
{
	stack* temp = (stack *)malloc(sizeof(stack));
	assert(temp);
	temp->top = -1;	//初始化栈顶元素下标,-1表示栈中没有元素
	return temp;
}

(2)判断栈是否满了,如果我们要取或者要存入数据的下标已经到达了9或者更高,说明我们这里的栈已经满了,因为我们的空间一共只有10个:

bool stack_full(stack* st){

	return st->top >= STACK_SIZE - 1;	//在这里我们的STACK_SIZE定义值的是10

}

(3)入栈函数,向栈中存入数据:

void stack_push(stack* st, Type val)
{
	assert(st);	//判断栈是否存在
	assert(!stack_full(st));	//判断栈是否满了
	st->data[++st->top] = val;	//从栈顶插入元素
}

(4)判断栈是否为空,只要top不为-1,说明栈中有数据,反之top为-1,说明栈还是空的:

bool stack_empty(stack* st)
{
	return st->top != -1;
}

(5)数据出栈函数,取出一个数据后top要-1,下一次就是取这个数据的前一个数据了:

Type stack_pop(stack* st)
{
	assert(st);
	assert(stack_empty(st));
	 
	Type val = st->data[st->top];	//记录当前栈顶元素
	st->top--;	//栈顶元素下标-1.因为这个时候已经取出当前元素了,下一次就是应该取前面一个元素了
	return val;

}

(6)取出栈的当前元素:

	Type stack_top(stack* st)
{
	assert(st);
	assert(stack_empty(st));
	return st->data[st->top];
}

3.测试栈的各个功能:

#include <stdio.h>
#include <assert.h>
#include "queue.h"

#define S "%d"
#define P "%d\t"

void stack_test()
{
	stack* st1 = stack_init();
	Type val;
	printf("输入要存入的数据:");
	do
	{
		scanf(S, &val);
		stack_push(st1, val);
	} while ('\n' != getchar());

	printf(P, stack_pop(st1));
	printf(P, stack_pop(st1));
	putchar('\n');
	printf(P, stack_top(st1));
	putchar('\n');
	printf(P, stack_pop(st1));
	printf(P, stack_pop(st1));

}

int main(){
	stack_test();
	getchar();
	return 0;
}

输入0 1 2 3 4 5 6 7 8 9测试结果,其中第二行的单7是获取的栈的当前数据:
在这里插入图片描述

队列

1.队列是什么

队列就是类似于排队一样,想象一下在地铁站排队时候,先到的人排在前面,就最先进入地铁,后来的人就排到后面,后进入地铁,所以队列就是先入先出,后入后出,入指的就是去排队,出指的就是进入地铁,先排先进,后排后进.实现队列一般使用链表结构.
在存入数据时,如下图这样,依次放在之前数据的后面:
在这里插入图片描述
在取数据时,则取的就是先放入的数据了,如下图:
在这里插入图片描述

2.队列的代码实现

(在queue.h中声明数据结构和函数)
1.先定义我们要存入的数据类型,比如这里假设要存入int型:

typedef int Type;

2.声明链表节点结构体,一个节点就带一个数据,使用链表来将这个队列串起来:

	typedef struct node{
	Type data;	//数据域
	node* next;	//指针域
}Node;

3.队列链表的声明

typedef struct Queue{
	Node* front;	//队首指针
	Node* back;		//队尾指针
}Queue;

4.声明队列各种功能的函数:

//队列单链表的初始化
Queue* queue_init();

//队列单链表节点的初始化
Node* node_create(Type val);

//数据入队函数
void queue_push(Queue* q, Type val);

//数据出队函数
Type queue_pop(Queue* q);

//获取队首元素
Type queue_front(Queue* q);

//获取队尾元素
Type queue_back(Queue* q);

//判断队列是否为空
bool queue_empty(Queue* q);

(Queue.cpp中实现这些函数)
5.实现这些功能函数:
(1)队列单链表的初始化:

Queue* queue_init()
{
	Queue * temp = (Queue *)malloc(sizeof(Queue));
	assert(temp);
	temp->front = temp->back = NULL;	//队首和队尾指针初始化为空
	return temp;
}

(2)给定数据,实现节点的初始化:

	Node* node_create(Type val)
{
	Node* temp = (Node *)malloc(sizeof(Node));
	assert(temp);

	temp->data = val;	//节点数据域的初始化
	temp->next = NULL;	//节点指针域的初始化

	return temp;
}

(3)数据入队函数:

	void queue_push(Queue* q, Type val)
{
	assert(q);
	if (q->front == NULL)
	{
		q->front = node_create(val);	//创建队列的第一个节点
		q->back = q->front;	//队列只有一个节点,其既是头部也是尾部
	}
	else
	{
		q->back->next = node_create(val);
		q->back = q->back->next;
	}
}

(4)数据出队函数:

	Type queue_pop(Queue* q)
{
	assert(q);	//整个链表不存在
	assert(q->front);	//链表为空
	Node *temp = q->front;
	Type val = temp->data;
	q->front = q->front->next;
	free(temp);
	temp = NULL;
	return val;
}

(5)获取队首元素:

Type queue_front(Queue* q)
{
	assert(q);
	assert(q->front);
	return q->front->data;
}

(6)获取队尾元素:

Type queue_back(Queue* q){
	assert(q);
	if (queue_empty(q))
		return NULL;
	return q->back->data;
}

(7)判断队列是否为空:

bool queue_empty(Queue* q)
{
	assert(q);	//整个链表不存在
	return q->front == NULL;
}

3.测试队列的各个功能:

#include <stdio.h>
#include <assert.h>
#include "queue.h"

void queue_test(){
	Queue* q1 = queue_init();
	Type val;
	printf("输入要存入的数据:");
	do{
		scanf(S, &val);
		queue_push(q1,val);
	} while ('\n' != getchar());
	printf("获取队列的当前值:");
	printf(P, queue_pop(q1));
	printf("获取队列的当前值:");
	printf(P, queue_pop(q1));
	putchar('\n');
}
int main(){

	queue_test();
	getchar();
	return 0;
}

存入数据1,2,3,4,5,6,运行结果如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浔汐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值