初识数据结构(三)

在了解过较为基础的顺序表和链表之后,今天梳理栈和队列,栈和队列的原理是相似的,栈是类似一个弹夹的实现,队列类似于水管的实现。

栈:后进先出  last in first out

队列:先进先出 first in first out

栈  接口实现

实现链表大抵有两种方式,数组实现和单链表实现。

我们先来分析一下单链表实现,由于栈的实现只需要一个口子,用来出入数据,单链表的头尾都可以实现这个过程,但相较而言头插较易实现,所以在单链表实现时用头节点作为栈顶。

数组我们相当熟悉了,数组的实现就是在末尾插入数据,这点就和栈十分相似,并且数组的删除数据更加简单,所以我们用数组来创建栈。

//stack.h

#pragma once

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

typedef int STDataType;

typedef struct Stack//此结构体是一个类数组的结构,a指向数组的起始位置,top来表示下表结合a可以找到数组中的任意的数,capacity用来存放数组大小
{
	STDataType* a;
	int top;//数组下标
	int capacity;//数组容量
}ST;

//常用接口
void STInit(ST* ps);//初始化
void STDestroy(ST* ps);//销毁
void STPush(ST* ps, STDataType x);//入栈
void STPop(ST* ps);//获取栈顶元素
STDataType STTop(ST* ps);//获取栈顶元素
int STSize(ST* ps);//栈大小
bool STEmpty(ST* ps);//探空

(以上是栈常用的接口,这些接口是前辈们在使用时总结出最常用的接口)

//stack.c
#include"Stack.h"

void STInit(ST* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = 0;//top指向栈顶元素的下一个,在插入一个第一个元素后,top++(同43行)。top也可以一直指向栈顶元素,则top需要初始化为-1,这样在输入第一个数时top++来到0
	ps->capacity = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

//栈顶
void STPush(ST* ps, STDataType x)
{
	//首先断言ps不能为空指针,否则会压栈失败
	assert(ps);

	
	if (ps->top == ps->capacity)//满了 扩容
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//如果没有容量初始化容量,容量不足则扩容
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));//tmp刚开始为空,在功能上等同于malloc,所有可以直接使用realloc
		if (tmp == NULL)
		{
			perror("realloc fail"); 
			return;
		}

		ps->a = tmp;
		ps->capacity = newcapacity;
	}

	ps->a[ps->top] = x;//同上先把数据放入top下表的位置,让后让top++,让top始终指向栈顶的下一个(也就是新数据插入时的位置)
	ps->top++;
}

void STPop(ST* ps)//出栈
{
	assert(ps);
	assert(!STEmpty(ps));

	ps->top--;
}

STDataType STTop(ST* ps)//获取栈顶元素
{
	assert(ps);
	assert(!STEmpty(ps));

	return ps->a[ps->top - 1];
}

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

bool STEmpty(ST* ps)//判空,判断栈是否为空
{
	assert(ps);

	return ps->top == 0;
}

在栈的实现中,top的初始化是十分有讲究的

top=0时,插入一个数据top向后移一次,这样的话top始终指向栈顶元素的下一个

top=-1时,top始终指向栈顶元素

队列 接口实现

链表队列:尾插入队,头插出队,单项不循环(头节点可带可不带),在分割链表等肯能产生空链表的情况下必循设立哨兵位

数组队列:好入队,难出队,因为数组只能通过一个口来出入数据

//Queue.h


#pragma once
#pragma once
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


typedef int QDataType;
typedef struct QueueNode
{
	int val;
	struct QueueNode* next;
}QNode;

 入队列
//void QueuePush(QNode** pphead, QNode** pptail);
//
 出队列
//void QueuePop(QNode** pphead, QNode** pptail);

typedef struct Queue//和栈的不同之处,第2个结构体存放收尾指针
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);

// 入队列
void QueuePush(Queue* pq, QDataType x);
// 出队列
void QueuePop(Queue* pq);

QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);

//Queue.c


#include"Queue.h"

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;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

// 入队列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//创建失败
	{
		perror("malloc fail");
		return;
	}

	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail)
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->phead = pq->ptail = newnode;
	}

	pq->size++;
}

// 出队列
void QueuePop(Queue* pq)
{
	assert(pq);

	// 0个节点
	// 温柔检查
	//if (pq->phead == NULL)
	//	return;

	// 暴力检查 
	assert(pq->phead != NULL);

	// 一个节点
	// 多个节点
	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--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);

	// 暴力检查 
	assert(pq->phead != NULL);

	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);

	// 暴力检查 
	assert(pq->ptail != NULL);

	return pq->ptail->val;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->size == 0;
}

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

	return pq->size;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值