栈和队列的实现

栈的实现:

首先,我们要明白栈是一个怎样的结构;

栈是一个在顶部操作的结构;所以我们的所有操作都必须在栈顶;那前面我们有两个对应的结构可以来进行选择;一个是我们的数组,一个是我们的链表;

我们要读取栈的元素都是连续的,所以我们两个结构都还是可以的;但是我选择数组来,因为它够简单;

分析栈的结构体的成员:

首先我们要进行存储数据,且为数组形式进行存;那我们要有一个数组指针;其次我们要进行栈顶的操作,所以我们进行对我们的数组所占的大小进行管理;所以我们要定义一个栈顶;这个的作用和我们的顺序表里面的size是作用一样;那刚好和顺序表一样,那我们要知道我们什么时候进行扩容;所以我们进行管理我们开辟的空间大小;

所以结构体成员如下:

int* arry;

int top;

int capacity;

#pragma once
typedef struct stack {
	int* arry;
	int capacity;
	int top;
}ST;

其次,这个结构体是声明意思就是我们这个只是说有这些东西,但是没开辟空间就没有进行定义;和后面的CPP的类是有相同之处;那我们结构体就是放在头文件里面;而不是.c文件的mian函数里面;

进行栈的初始化:

我们要对这个情况进行判定,这个到底是我们已经对指向的元素进行了操作还是没有进行操作;

那我们的方法就是对top的初始化的值赋予不同的意义;

我自己在脑子里面定义 当 top指向一个元素的时候; 我们是已经对元素进行了操作;

那我们要对top赋值为-1;因为这样我们top指向下标为0的元素的时候,符合我们的定义;不然从0开始我们会将最后一个元素漏掉;

void STinit(ST* pst) {
	assert(pst);
	pst->arry = NULL;
	pst->top = -1;
	pst->capacity = 0;
}
栈的插入:

我们是对我们结构体里面的数组进行操作;所以我们的所有东西都是对数组来说的;包括扩容,插入和删除等操作;

void STPush(ST* pst, STDataType x) {
	assert(pst);
	if (pst->top == pst->capacity-1) {
		int tmpcapacity = pst->capacity==0?4:pst->capacity * 2;
		int* tmp = (int*)realloc(pst->arry,sizeof(STDataType)*tmpcapacity);
		if (tmp == NULL) {
			perror("realloc fail");
			exit(-1);
		}
		pst->arry = tmp;
		pst->capacity = tmpcapacity;
	}
	pst->arry[pst->top+1]= x;
	pst->top++;
}
栈的删除:

栈的删除是对数组的访问范围进行限制;然后我们打印和访问就访问不了,这样是最简单的方式;

void STPop(ST* pst) {
	assert(pst);
	assert(pst->arry);
	//上面这两步是为了后面我们要访问元素而进行准备的,不然就可能是非法访问;
	pst->top--;
}
获取栈顶元素:

注意事项和我们上面删除一样;

STDataType STTop(ST* pst) {
	assert(pst);
	assert(pst->arry);
	return pst->arry[pst->top];
}
判断栈是否为空:

这个很简单,就是判断top的位置或者叫值;

bool STEmpty(ST* pst) {
	assert(pst);
	return pst->top == -1;
}
求栈里面的元素个数:

这个也很简单,就是将我们top+1输出就可以了;

int STSize(ST* pst) {
	assert(pst);
	return pst->top + 1;
}
栈的销毁:

我们要先销毁我们开在堆的空间;然后再对我们的元素进行赋值;

void STDestory(ST* pst) {
	assert(pst);
	free(pst->arry); //这个写法是可以的;因为我们释放空也不会报错;
	pst->capacity = 0;
	pst->top = -1;
}
栈的打印:

就是按照数组来进行打印;

void STPrint(ST* pst) {
	assert(pst);
	int tmp = -1;
	while (tmp<pst->top) {
		printf("%d", pst->arry[tmp+1]);
		tmp++;
	}
	printf("\n");
}

栈总的代码:

#include"ST.h"

void STinit(ST* pst) {
	assert(pst);
	pst->arry = NULL;
	pst->top = -1;
	pst->capacity = 0;
}
void STPush(ST* pst, STDataType x) {
	assert(pst);
	if (pst->top == pst->capacity-1) {
		int tmpcapacity = pst->capacity==0?4:pst->capacity * 2;
		int* tmp = (int*)realloc(pst->arry,sizeof(STDataType)*tmpcapacity);
		if (tmp == NULL) {
			perror("realloc fail");
			exit(-1);
		}
		pst->arry = tmp;
		pst->capacity = tmpcapacity;
	}
	pst->arry[pst->top+1]= x;
	pst->top++;
}
void STPop(ST* pst) {
	assert(pst);
	assert(pst->arry);
	//上面这两步是为了后面我们要访问元素而进行准备的,不然就可能是非法访问;
	pst->top--;
}
STDataType STTop(ST* pst) {
	assert(pst);
	assert(pst->arry);
	return pst->arry[pst->top];
}
bool STEmpty(ST* pst) {
	assert(pst);
	return pst->top == -1;
}
int STSize(ST* pst) {
	assert(pst);
	return pst->top + 1;
}
void STDestory(ST* pst) {
	assert(pst);
	free(pst->arry); //这个写法是可以的;因为我们释放空也不会报错;
	pst->capacity = 0;
	pst->top = -1;
}
void STPrint(ST* pst) {
	assert(pst);
	int tmp = -1;
	while (tmp<pst->top) {
		printf("%d", pst->arry[tmp+1]);
		tmp++;
	}
	printf("\n");
}
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int STDataType;
typedef struct stack {
	int* arry;
	int capacity;
	int top;
}ST;
void STinit(ST* pst);
int STSize(ST* pst);
void STDestory(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
void STPrint(ST* pst);
#include"ST.h"
int main() {
	ST test;
	ST* ptest = &test;
	STinit(ptest);
	STPush(ptest, 1);
	STPush(ptest, 2);
	STPush(ptest, 3);
	STPush(ptest, 4);
	STPrint(ptest);
	STPush(ptest, 6);
	STPrint(ptest);
	STPop(ptest);
	//int num=STTop(ptest);
	//int num = STEmpty(ptest);
	STPop(ptest);
	int num = STSize(ptest);
	printf("%d\n", num);
	 STDestory(ptest);
	STPrint(ptest);
	return 0;
}

队列的实现:

队列是先进先出的;所以我们队列的出队的顺序只会有一种;

队列的底层的结构的选择:

我们要在队尾不断进行插入数据,在队头不断的拿出数据;

那我们就不适合选择数组,因为头删操作时间复杂度太大了;

但链表也不行呀,链表对队尾的操作太难了,于是有大神想到了一个办法;

我们对链表的尾巴和头部一直进行记录,并且一直记录长度;

那链表的所有操作都会变的很简单;

队列的成员:

第一,我们要有值 val

第二,有下一个节点的指针 *next;

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;
再封装的结构体的成员:

我们要进行头部和尾巴的封装 *phead , *ptail;

我们还要管理大小 size,这个我们就可以通过头部指针来进行偏移,我们就可以大致实现数组的下标访问的效果了;

这个再封装有一个很大的用处,就是我们可以通过改变这个结构体的成员来进而改变我们指针的指向;

这样我们就可以不用传二级指针就可以改变一级指针的指向了;很强的思路;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size//size为队尾到队头总共有多少个节点
}Queue;
队列的初始化:
void QueueInit(Queue* pq) {
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}                //队列的初始化
队列的销毁:

我们要先释放掉我们指向的空间,再进行指针改变指向;因为为单链表,所以我们要进行不断的保存下一个节点的位置;

//队列的销毁
void QueueDestroy(Queue* pq) {
	assert(pq && pq->size);
	QNode* tmp = pq->phead->next;//保存下一个节点位置
	//尾节点也要被释放;
	while (tmp->next) {
		free(pq->phead);
		pq->phead = tmp;
		tmp = pq->phead->next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}
队列节点的申请:
//申请节点
QNode* CreateNode(int x) {
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL) {
		perror("Create fail");
		exit(-1);
	}
	tmp->val = x;
	tmp->next = NULL;
	return tmp;
}
队列的插入:

我们先来实现尾插,我们的操作和以前一样;先找尾,再进行操作;

//插入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	QNode* newnode = CreateNode(1);
	//没有一个节点,改头尾指针
	if (pq->size == 0) {
		pq->phead = pq->ptail = newnode;
		pq->size++;
	}
	//有节点,改尾指针;
	else {
		pq->ptail->next = newnode;
		pq->ptail = newnode;
		pq->size++;
	}
} 
队列的删除:

我们要先保存我们的下一个位置,再进行释放;

void QueuePop(Queue* pq) {
	assert(pq);
	if (pq->size == 0) return;
	QNode* tmp= pq->phead->next;
	free(pq->phead);
	pq->phead = tmp;
    pq->size--;
}
队列数据的打印:

思路和打印单链表一样;

//打印数据
void QueuePrint(Queue* pq) {
	assert(pq);
	if (pq->size == 0) return;
	int tmpLen = pq->size;
	QNode* tmphead=pq->phead;
	while (tmpLen--) {
		printf("%d", tmphead->val);
		tmphead = tmphead->next;
	}
	printf("\n");
}
队列判空:
//队列的判空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->size == 0;
}
队列的头部数据:
//队列头部数据
QDataType QueueFront(Queue* pq) {
	assert(pq && pq->size);
	return pq->phead->val;
}
队列的尾部数据:
//队列尾部数据
QDataType QueueBck(Queue* pq) {
	assert(pq && pq->size);
	return pq->ptail->val;
}
队列的大小:
//队列的大小
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}

队列总的代码

#include"Queue.h"
//队列的初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}   
//队列的销毁
void QueueDestroy(Queue* pq) {
	assert(pq);
	//尾节点也要被释放;
	while (pq->phead) {
		QNode* tmp = pq->phead->next;//保存下一个节点位置
		free(pq->phead);
		pq->phead = tmp;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
//申请节点
QNode* CreateNode(int x) {
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL) {
		perror("Create fail");
		exit(-1);
	}
	tmp->val = x;
	tmp->next = NULL;
	return tmp;
}
//插入数据
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	QNode* newnode = CreateNode(x);
	//没有一个节点,改头尾指针
	if (pq->size == 0) {
		pq->phead = pq->ptail = newnode;
		pq->size++;
	}
	//有节点,改尾指针;
	else {
		pq->ptail->next = newnode;
		pq->ptail = newnode;
		pq->size++;
	}
} 
//删除数据
void QueuePop(Queue* pq) {
	assert(pq);
	if (pq->size == 0) return;
	QNode* tmp= pq->phead->next;
	free(pq->phead);
	pq->phead = tmp;
	pq->size--;
}
//打印数据
void QueuePrint(Queue* pq) {
	assert(pq);
	if (pq->size == 0) return;
	int tmpLen = pq->size;
	QNode* tmphead=pq->phead;
	while (tmpLen--) {
		printf("%d", tmphead->val);
		tmphead = tmphead->next;
	}
	printf("\n");
}

//队列的判空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->size == 0;
}
//队列头部数据
QDataType QueueFront(Queue* pq) {
	assert(pq && pq->size);
	return pq->phead->val;
}
//队列尾部数据
QDataType QueueBck(Queue* pq) {
	assert(pq && pq->size);
	return pq->ptail->val;
}
//队列的大小
int QueueSize(Queue* pq) {
	assert(pq);
	return pq->size;
}
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;//size为队尾到队头总共有多少个节点
}Queue;
void QueueInit(Queue* pq);                //队列的初始化
void QueueDestroy(Queue* pq);             //队列的销毁
QNode* CreateNode(int x); //申请节点
void QueuePush(Queue* pq, QDataType x);   //插入数据
void QueuePrint(Queue* pq);                 //打印数据
void QueuePop(Queue* pq);                 //删除数据
bool QueueEmpty(Queue* pq);               //队列的判空
QDataType QueueFront(Queue* pq);          //队列头部数据
QDataType QueueBck(Queue* pq);            //队列尾部数据
int QueueSize(Queue* pq);                 //队列的大小
#include"Queue.h"
int main() {
	Queue test;
	Queue* ptest = &test;
	QueueInit(ptest);
	QueuePush(ptest, 1);
	QueuePush(ptest, 2);
	QueuePush(ptest, 3);
	QueuePush(ptest, 4);
	QueuePush(ptest, 5);
	QueuePush(ptest, 6);
    QueuePush(ptest, 7);
	QueuePrint( ptest);
	 QueuePop(ptest);
	QueuePrint(ptest);
	/*int tmp = QueueEmpty(ptest);
	printf("%d", tmp);*/
	int tmp = QueueSize( ptest);
	printf("%d", tmp);

	return 0;
}
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值