初识栈和队列

1.栈

1.1 栈的概念及结构

 栈:一种特殊的线性表,只允许在固定的一段进行插入或删除元素操作。进行数据插入和删除操作
 的一端叫做栈顶,另一端叫做栈底。
 压栈:栈的插入操作
 出栈:栈的删除操作(都在栈顶操作)

后进先出(last in first out)

1.2 栈的数组动态实现(静态类似,直接给定capacity,不实用)

栈的实现一般可以由链表或者数组进行实现,平时我们更提倡用数组进行实现,因为数组的尾插尾删效率更高,cpu缓存的利用率也更高。
下面就是由数组进行的对栈的实现:

//创建一个栈的结构体,其中top代表栈顶,capacity代表栈的容量,a代表栈的起始地址。
typedef int DataType;
typedef struct Stack
{
	DataType* a;
	int capacity;
	int top;
}ST;
//这里实现的是栈的初始化,在初始化的时候,可以给这个栈开一点空间,这样一会扩容的realloc就可以只执行扩容的功能,而不用像顺序表一样,先执行开辟空间,再执行扩容。
void StackInit(ST* st)
{
	assert(st);
	st->a = (DataType*)malloc(sizeof(DataType) * 4);
	if (st->a == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	st->capacity = 4;
	st->top = 0;
}

top初始化可以为0,也可以为-1,
初始化为0时,代表top是栈顶元素的后一格。
为-1时,代表top是栈顶元素的那一格。

//栈的销毁
//栈的销毁非常简单,只需要先将这个栈使用的这块空间释放,再将指向这块空间的指针置空即可。
void StackDestroy(ST* st)
{
	assert(st);
	free(st->a);
	st->a = NULL;
	//同理,栈销毁了,容量(capacity)要归零,栈顶元素也要归零
	st->capacity = 0;
	st->top = 0;
}```

```c
//压栈
void StackPush(ST* st, DataType x)
{
	assert(st);
	//首先判断这个栈的空间是否已经满了,如果满了,就申请扩容
	if (st->capacity == st->top)
	{
		DataType* New = (DataType*)realloc(st->a, st->capacity * 2 * sizeof(DataType));
		if (New == NULL)
		{
			perror("realloc failed");
			exit(-1);
		}
		st->a = New;
		st->capacity = st->capacity * 2;
	}
	//空间足够了,就往栈顶元素放进一个x,然后把栈顶元素向后挪一位。
	st->a[st->top] = x;
	st->top++;
}
//出栈
void StackPop(ST* st)
{
	assert(st);
	assert(!StackEmpty(st));
	
	st->top--;
}
//出栈很简单,只需要将栈顶元素向前移动一格即可,但需要注意的是,判断栈不为空,因为如果栈空了,再把栈顶元素向前移就会造成溢出,栈顶元素就会指向我们所申请的空间的外面。
//判断栈是否为空
bool StackEmpty(ST* st)
{
	assert(st);

	return st->top == 0;
}

//获取栈顶值
DataType StackTop(ST* st)
{
	assert(st);
	assert(!StackEmpty(st));

	DataType Top = st->a[st->top -1];
	return Top;
}

//获取栈的大小
int StackSize(ST* st)
{	
	assert(st);
	return st->top;
}

2.队列

2.1 队列的概念及结构

		队列:只允许在一段进行数据插入,在另一端进行数据删除的特殊线性表,队列
		具有先进先出FIFO(first in first out)
		入队列:进行插入操作的一段叫做队尾
		出队列:进行删除操作的一段称为队头

2.2 队列的链表实现

队列的实现一般可以由链表或者数组进行实现,平时我们更提倡用链表进行实现,因为链表对队列的效果更好。
下面就是由链表进行的对栈的实现:

#pragma once

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

//给int起个新名字
typedef int QDataType;

//设置出队列结构体
typedef struct QueueNode
{
	QDataType x;
	struct QueueNode* next;
}QNode;

//队列的结构中,需要两个指针指向整个队列的首尾,用一个结构包含两个指针简单一点,
//还能加一个size用来计算队列的长度
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

//队列需要实现的接口
void QueueInit(Queue* qn);
void QueueDestroy(Queue* qn);
void QueuePush(Queue* qn, QDataType x);
void QueuePop(Queue* qn);
QDataType QueueFront(Queue* qn);
QDataType QueueBack(Queue* qn);
int QueueSize(Queue* qn);
bool QueueEmpty(Queue* qn);

//队列接口的实现
#include"Queue.h"

void QueueInit(Queue* qn)
{
	assert(qn);
	qn->head = NULL;
	qn->tail = NULL;
	qn->size = 0;
}

void QueueDestroy(Queue* qn)
{
	assert(qn);
	QNode* cur = qn->head;
	while (cur)
	{
		QNode* new = cur;
		cur = cur->next;
		free(new);
	}
	qn->head = qn->tail = NULL;
	qn->size = 0;
}

void QueuePush(Queue* qn, QDataType x)
{
	assert(qn);
	QNode* NewNode = (QNode*)malloc(sizeof(QNode));
	if (NewNode == NULL)
	{
		perror("malloc failed");
		exit(-1);
	}
	NewNode->next = NULL;
	NewNode->x = x;
	if (qn->head == NULL)
	{
		qn->head = qn->tail = NewNode;
	}
	else
	{
		qn->tail->next = NewNode;
		qn->tail = NewNode;
	}

	qn->size++;
}

void QueuePop(Queue* qn)
{
	assert(qn);
	assert(!QueueEmpty(qn));

	if (qn->head == qn->tail)
	{
		QNode* new = qn->head;
		free(new);
		qn->head = NULL;
		qn->tail = NULL;
	}
	else
	{
		QNode* new = qn->head;
		qn->head = qn->head->next;
		free(new);
	}
	qn->size--;
}

QDataType QueueFront(Queue* qn)
{
	assert(qn);
	assert(!QueueEmpty(qn));

	return qn->head->x;

}

QDataType QueueBack(Queue* qn)
{
	assert(qn);
	assert(!QueueEmpty(qn));

	return qn->tail->x;
}

int QueueSize(Queue* qn)
{
	assert(qn);
	return qn->size;
}

bool QueueEmpty(Queue* qn)
{
	assert(qn);
	if (qn->head == NULL)
	{
		return true;
	}
	return false;
}

PS

学完栈和队列的感觉,
就是用顺序表或者链表实现结构,
如果是顺序表实现栈的话,只需要一个指针array就可以指向栈,这个时候,顺序表的长度,top之类的值都可以和那个指针array一起作为栈这个结构的成员变量。初始化的时候,
如果定义了一个栈的结构体,那么初始化只要malloc动态开辟一个空间给这个指针就可以了,
如果没有定义,初始化的时候,就还需要再malloc一个栈,在用栈中的成员变量指针array接收malloc的值。

用链表实现队列的时候,因为链表结构SL都是一个节点一个节点的,如果需要额外的指针去控制队列的话,就需要额外创建一个结构体S,将这些额外的指针,以及队列整体用到的变脸作为S的成员变量,同理,如果初始化有提前定义结构体,初始化的时候甚至都不需要malloc,直接在push的时候malloc SL的节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值