栈和队列(数据结构)

1.栈

1.1栈的概念及结构

定义:一种特殊的线性表。
性质:后进先出;
栈顶:进行数据插入删除的一段称作栈顶;
栈底:另一端称作栈底;
压栈:栈的插入操作叫做进栈/入栈,人数据在栈顶;
出栈:栈的删除操作叫做出栈,出数据也在栈顶;

示例:
在这里插入图片描述

1.2栈的实现

1.数组栈
刚好符合栈的单向插入;
在这里插入图片描述

2.链式栈
双链表怎么都可以;
但是单链表建议将链表的头设为栈顶,栈尾设尾栈底;
在这里插入图片描述

2.栈的实现

头文件

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDateType;
typedef struct strack
{
	struct strack* pa;
	STDateType top;
	STDateType capacity;
}ST;
void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDateType x);
void STpop(ST* pst);
STDateType STTop(ST* pst);
bool STEmpty(ST* pst);
int STsize(ST* pst);

2.1栈的初始化

void STInit(ST* pst)
{
	pst->pa = NULL;
	//pst->top=-1;
	pst->top =0;//这里的数值的取值不同,top的指向不同;这里两者都可;
	pst->capacity = 0;
}

这里的top的取值不同;top的指向不同;
top为0时:top指针的指向在栈顶的下一位;
top为-1时:top指针的指向 在栈顶位置;
在这里插入图片描述
在这里插入图片描述
这里top可以;联想到数组的下表;0—正无穷
是合理 的栈顶位置;-1是不存在的;

2.2栈的添加

void STPush(ST* pst, STDateType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDateType* tmp = (STDateType*)realloc(pst->a, newcapacity * sizeof(STDateType));
		//增加内存需要判断内存是否扩容成功
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
		//这里top不需要将其改变原因:top已经在改在的位置了;
	}
	pst->a[pst->top] = x;
	pst->top++;

	 
}

top不需要将其改变原因:top已经在改在的位置了

2.3栈的删除

void STpop(ST* pst)
{
	assert(pst);
	//删除这里出现问题:当pst的top指针指向0之前的数据原本不应该再次删除;
	assert(!STEmpty(pst));
	pst->top--;

}

2.4返回栈顶元素

返回栈顶元素//这里主函数不要使用结构体来访问栈顶元素,原因:这里的栈顶元素有两种方式;使用者不知道top是0还是-1;

STDateType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top-1];//这里由于vs2019的版本不同就会导致越界不会报错;
}

2.5检查栈是否为空

检查栈顶是否为空;

bool STEmpty(ST* pst)
{
	assert(pst);
	//if (pst->top == 0)
	//{
	//	return true;
	//}
	//else
	//return false;
	return pst->top == 0;
}

2.6 查看栈内部元素的个数

int STsize(ST* pst)
{
	assert(pst);
	return pst->top;
}

完整代码

//头文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDateType;
typedef struct strack
{
	STDateType* a;
	STDateType top;
	STDateType capacity;
}ST;
void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDateType x);
void STpop(ST* pst);
STDateType STTop(ST* pst);
bool STEmpty(ST* pst);
int STsize(ST* pst);
//主文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"strack.h"
void text1()
{
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	STPush(&st, 3);
	//栈无法实现打印函数;
	//所以使用出栈来元素输出;
	while (!STEmpty(&st))
	{
		printf("%d ", STTop(&st));
		STpop(&st);//删除栈顶
	}
	STDestroy(&st);
}
int main()
{
	text1();
	return 0;
}
//函数体
#define _CRT_SECURE_NO_WARNINGS 1
#include"strack.h""
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;//这里的数值的取值不同,top的指向不同;
	pst->capacity = 0;
}
void STDestroy(ST* pst)
{
	assert(pst);
	pst->top=0;
	pst->capacity = 0;
	free(pst->a);
	pst->a = NULL;
}
void STPush(ST* pst, STDateType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDateType* tmp = (STDateType*)realloc(pst->a, newcapacity * sizeof(STDateType));
		//增加内存需要判断内存是否扩容成功
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
		//这里top不需要将其改变原因:top已经在改在的位置了;
	}
	pst->a[pst->top] = x;
	pst->top++;

	 
}
void STpop(ST* pst)
{
	assert(pst);
	//删除这里出现问题:当pst的top指针指向0之前的数据原本不应该再次删除;
	assert(!STEmpty(pst));
	pst->top--;

}
//返回栈顶元素//这里主函数不要使用结构体来访问栈顶元素,原因:这里的栈顶元素有两种方式;使用者不知道top是0还是-1;
STDateType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top-1];//这里由于vs2019的版本不同就会导致越界不会报错;
}
bool STEmpty(ST* pst)
{
	assert(pst);
	//if (pst->top == 0)
	//{
	//	return true;
	//}
	//else
	//return false;
	return pst->top == 0;
}
int STsize(ST* pst)
{
	assert(pst);
	return pst->top;
}

3.队列

3.1.什么是队列:

定义:一种特殊的数据结构。只允许在一端插入数据,在另一端进行删除数据操纵的特殊线性表,队列具有—先进先出;
入队列:进行插入操作的一端称为队尾;
出队列:进行删除操作的一端称作队头;
在这里插入图片描述

3.2队列的实现

实现队列的实现;可以使用链表和数组实现。
由于队列的实现需要使用头删数列实现队列时间复杂度较高;所以使用链表来实现;

// 链式结构:表示队列
typedef struct QListNode
{ 
 struct QListNode* _pNext; 
 QDataType _data; 
}QNode; 
// 队列的结构
typedef struct Queue
{ 
 QNode* _front; 
 QNode* _rear; 
}Queue; 
// 初始化队列
void QueueInit(Queue* q); 
// 队尾入队列
void QueuePush(Queue* q, QDataType data); 
// 队头出队列
void QueuePop(Queue* q); 
// 获取队列头部元素
QDataType QueueFront(Queue* q); 
// 获取队列队尾元素
QDataType QueueBack(Queue* q); 
// 获取队列中有效元素个数
int QueueSize(Queue* q); 
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q); 
// 销毁队列
void QueueDestroy(Queue* q)
3.2.1队列结构体的实现

由于使用链表来构造队列;这里链表的每一个元素是由数和指针组成的;整个队列需要指针
和计数的变量来判断;
在这里插入图片描述

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType date;
}Qnode;
//整个链表的结构
typedef struct Queue
{
	Qnode* phead;//头指针
	Qnode* ptail;//尾指针
	int size;//链表元素的个数
}Queue;
3.2.2队列初始化

将整个队列的结构体的指针和变量置为空和0;
1.添加
2.删除

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;

}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	Qnode* cur = pq->phead;
	while (cur)
	{//这里有两种方法一种是尾删,一种是头删,尾删除需要遍历;所以使用头删
		Qnode* next = cur->next;
		free(cur);
		cur = next;
	}
	//指针置空加size为0
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

3.2.2队列的添加

使用一级指针原因:这里改变的是结构体的内容;这里需要考虑扩容和添加数据两个部分;

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	Qnode* newnode = (Qnode*)malloc(sizeof(Qnode));
	if (newnode == NULL)
	{
		perror("malloc失败");
	}
	newnode->date = x;
	newnode->next = NULL;

	//这里是单链表就决定了这里的初始化需要分情况:什么也没有;已经有一些元素
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{

		pq->ptail->next  = newnode;
		pq->ptail = newnode;
	}
	pq->size++;

}

3.2.3队列的删除

这里的队列需要考虑三种情况;
0和1和多个元素3种情况;

void QueuePop(Queue* pq)
//头部删除
{
	assert(pq);
	//分三种情况
	//0
	assert(!QueueEmpty(pq));
	//1:
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	//多个
	else
	{
		Qnode* next = pq->phead->next;//这里可能出现空指针的调用;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;

	

}

3.2.4找出队头

QDataType QueueFront(Queue* pq)
//选出对头
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->date;

}

3.2.5找出队尾

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq-

3.2.6队列元素的个数

int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;

}

3.2.7判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == 0 && pq->ptail == 0;
}

3.3循环队列

在这里插入图片描述

练习

用栈实现队列
设计循环队列
用队列实现栈

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值