栈和队列的实现

༺ 个人主页 · 纪念229 ༻

🏠我的博客主页🏠

༒专栏目录:《数据结构》༒

༒其它有趣的计算机知识༒

༺世上本没有路,走的人多了自然就有了༻


这篇文章讲述的是用顺序表实现栈、用单链表实现队列,本文主要讲述栈和队列的定义,希望对大家有所帮助!

文章目录

  • 1.Stack.h
  • 2.Stack.c
    • [2.1 STackDesTroy(ST* ps)](#2.1 STackDesTroy(ST* ps))
    • [2.2STackPush(ST* ps, STDataType x)](#2.2STackPush(ST* ps, STDataType x))
    • [2.3 STackEmpty(ST* ps)](#2.3 STackEmpty(ST* ps))
    • [2.4 STackPop(ST* ps)](#2.4 STackPop(ST* ps))
    • [2.5 STacksize(ST* ps)](#2.5 STacksize(ST* ps))
  • 3.Queue.h
  • 4.Queue.c
    • [4.1QueueInit(Queue* pq)](#4.1QueueInit(Queue* pq))
    • [4.3QueuePush(Queue* pq, QDataType x)](#4.3QueuePush(Queue* pq, QDataType x))
    • [4.4QueueTmpty(Queue* pq)](#4.4QueueTmpty(Queue* pq))
    • [4.5 QueuePop(Queue* pq)](#4.5 QueuePop(Queue* pq))
    • [4.6QueueFront(Queue* pq)](#4.6QueueFront(Queue* pq))
    • [4.7 QueueBack(Queue* pq)](#4.7 QueueBack(Queue* pq))
    • [4.8QueueSize(Queue* pq)](#4.8QueueSize(Queue* pq))

1.Stack.h

栈的头文件,讲述程序的功能

代码展示
点我展开

c 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
  STDataType* arr;
  int top;
  int capacity;
}ST;

//初始化
void STackInit(ST* ps);
//销毁
void STackDesTroy(ST* ps);

//入栈---栈顶
void STackPush(ST* ps,STDataType x);
//出栈---栈顶
void STackPop(ST* ps);
//取栈顶元素
STDataType STackTop(ST* ps);

//获取栈中有效元素个数
int STacksize(ST* ps);
//栈是否为空
bool STackEmpty(ST* ps);

2.Stack.c

说一下有些函数没有断言,主要讲述重要的地方

2.1 STackDesTroy(ST* ps)

功能:把栈清空

代码展示

c 复制代码
//销毁
void STackDesTroy(ST* ps)
{
  if(ps->arr)
		free(ps->arr);
	ps->arr =NULL;
	ps->capacity = ps->top = 0;
}

我们需要判断栈里是否为空,才能free里的内容

2.2STackPush(ST* ps, STDataType x)

功能:入栈

代码展示

c 复制代码
//入栈---栈顶
void STackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity == ps->top)
	{
	//增容
		int newcapacity = ps->arr == NULL ? 4 : 2 * ps->capacity;
		//扩容用realloc,用malloc前面的会消失
		STDataType* tmp = (STDataType*)realloc(ps->arr,sizeof(STDataType)* newcapacity);
		if (tmp == NULL) {
			perror("malloc fial");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity =newcapacity;
	}
	ps->arr[ps->top++] = x;
}

增容:判断栈是否为空,为空返回4字节否则返回2倍原字节

扩容用realloc不用malloc

原因:malloc是重新启用空间会把原来栈的数据清空

然后给栈赋值,记得更新栈顶和容量

2.3 STackEmpty(ST* ps)

功能:判断栈是否为空

代码展示

c 复制代码
bool STackEmpty(ST* ps)
{
 assert(ps);
 //用top判断栈是否为空
 return ps->top == 0;
}

要判断一个东西建议用bool类型的函数

判断栈为空就是判断栈顶top是否为0

2.4 STackPop(ST* ps)

功能:出栈

c 复制代码
//出栈---栈顶
 void STackPop(ST* ps)
 {
 //判断栈是否为空
 assert(!STackEmpty(ps));
 --ps->top;
}
要出栈要判断栈是否为空
出栈实际上是给栈顶减减

## 2.5 STackTop(ST* ps)
功能:得到栈顶的元素
```c
//取栈顶元素
 STDataType STackTop(ST* ps)
 {
	 //判断栈是否为空
	 assert(!STackEmpty(ps));
	 //取的是ps->arr[ps->top - 1](栈顶的元素)而不是栈顶数
	 return ps->arr[ps->top - 1];
}

既然要取栈顶元素就要判断栈是否为空

直接返回栈顶元素即可(返回的下标是top - 1)

2.5 STacksize(ST* ps)

功能:获取栈中存储的有效个数

代码展示

c 复制代码
//获取栈中有效元素个数
 int STacksize(ST* ps)
 {
 assert(ps);
 return ps->top;
}

栈中的有效个数就是栈顶的值


3.Queue.h

展示函数功能

代码展示
点我展开

c 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;
//队列节点的结构
typedef struct queueNode
{
  QDataType val;
  struct queueNode* next;
  //
}QueueNode;
//队列的结构
typedef struct queue
{
  QueueNode* phead;
  QueueNode* ptail;
  //int size;//队列中有效数据的个数
}Queue;

//初始化
void QueueInit(Queue* pq);
//销毁队列
void QueueDesTroy(Queue* pq);

//入队------队尾
void QueuePush(Queue* pq, QDataType x);


//出队------队头
void QueuePop(Queue* pq);
//队列判空
bool QueueTmpty(Queue* pq);
//队列有效元素个数
int QueueSize(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);

>队列是由两个指针组成的结构体,包括头phead和尾ptail >队列里是单链表组成的 ```

4.Queue.c

实现队列功能

4.1QueueInit(Queue* pq)

功能:初始化队列

代码展示

c 复制代码
//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
}


把头尾指针置空

##  4.2QueueDesTroy(Queue* pq)

功能:销毁队列里的数据
代码展示
```c
//销毁队列
void QueueDesTroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
}

给个next保存下一位的地址完成节点的销毁

最后给头指针和尾指针置空

4.3QueuePush(Queue* pq, QDataType x)

功能:入队(尾入队)

代码展示

c 复制代码
//入队------队尾
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fial");
		exit(1);
	}
	newnode->val = x;
	newnode->next = NULL;
	//队列为空
	if (pq->phead == NULL) {
		pq->phead = pq->ptail = newnode;
	}
	else {
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	//ps->size++;
}

每次入队都创建一个节点把val赋好next指向NULL

如果队列为空就把头指针(phead)和尾指针(ptail)被赋值为newnode指针,若不是就把尾指针指向newnode再把ptail赋值为newnode指针

4.4QueueTmpty(Queue* pq)

功能:判断队列是否为空

代码展示

c 复制代码
//队列判空
bool QueueTmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

判断队列为空就是看头指针是否等于NULL

4.5 QueuePop(Queue* pq)

功能:出队(头指针chu队列)

代码展示

c 复制代码
//出队------队头
void QueuePop(Queue* pq)
{
	assert(!QueueTmpty(pq));
	//只有一个节点,phead-ptai都置为空
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else {
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	//pq->size--;
}

要出队列先判断队列是否为空

如果只有一个节点就free头结点后置空

不是则给个next指针(找到新的头结点)然后free(phead),把phead赋值为next

4.6QueueFront(Queue* pq)

功能:获取队头信息

代码展示

c 复制代码
//取对头数据
QDataType QueueFront(Queue* pq)
{
//队列判空
 assert(!QueueTmpty(pq));
 return pq->phead->val;
}

判断队列是否为空,然后返回对头数据

4.7 QueueBack(Queue* pq)

功能:获取队尾信息

代码展示

c 复制代码
//取队尾数据
QDataType QueueBack(Queue* pq)
{
//队列判空
	assert(!QueueTmpty(pq));
	return pq->ptail->val;
}

判断队列是否为空,返回队尾数据

4.8QueueSize(Queue* pq)

功能:获取队列有多少有效数据

方案1.

把队列多加int size,当出队入队是加加减减(前面代码有注释)

具体代码在方案2中也有注释

方案2.

遍历队列返回有效个数

代码展示

c 复制代码
//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	//第一种方案遍历链表------适用于不会频繁调用队列有效个数的场景
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)
	{
		++size;
		pcur = pcur->next;
	}
	return size;

	//第二种方式:遍历链表------适用于频繁调用有效数据的场景
	//return pq->size;
}

方案1适用于不常调用有效个数的情况

方案2适用于常调用有效个数的情况

这篇文章在这里就结束了,希望对你有所帮助!