数据结构之三:栈和队列

线性表:有个n个元素的集合,逻辑上成线性结构。(顺序表、链表、栈、队列、串)。

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。

进行数据插入和删除操作的一端称为栈顶,另一端称为栈底

栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

数组来实现:

链表来实现:

  • 如果是双向链表,那么哪边是栈顶,哪边是栈底都无所谓。
  • 如果是单链表:

实现栈数组更加简单(对于当代的计算机,内存开辟带来的时间开销可以忽略不计)。

头文件
cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int STDataType;
#define N 4

/*
静态
struct Stack
{
	int* _a[N};
	int _size;//
};
*/
typedef struct Stack
{
	STDataType* _a;
	int _top;		//栈顶下标
	int _capacity;	//容量
}Stack;

void StackInit(Stack* pst);
void StackDestory(Stack* ppst);
void StackPush(Stack* pst, STDataType x);
void StackPop(Stack* pst);
int StackSize(const Stack* pst);

//返回1是空,返回0是非空
int StackEmpty(Stack* pst);
//获取栈顶数据
STDataType StackTop(Stack* pst);
实现
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

#include "stack.h"

void StackInit(Stack* pst)
{
	assert(pst);
	pst->_a = (STDataType*)malloc(sizeof(int) * N);
	pst->_capacity = N;
	pst->_top = 0;
	//初始0:top在栈顶的下一个位置
	//初始1:top在栈顶位置
}

void StackDestory(Stack* pst)
{
	assert(pst);
	free(pst->_a);
	pst->_a = NULL;
	pst->_capacity = 0;
	pst->_top = -1;

}

void StackPush(Stack* pst, STDataType x)
{
	assert(pst);
	if (pst->_top == pst->_capacity)
	{
		pst->_capacity *= 2;
		STDataType* tmp= (STDataType*)realloc(pst->_a, sizeof(STDataType) * pst->_capacity);
		if (tmp == NULL)
		{
			printf("内存不足\n");
			exit(-1);
		}
		else
		{
			pst->_a = tmp;
		}
	}
	pst->_a[pst->_top] = x;
	pst->_top++;
}

void StackPop(Stack* pst)
{
	assert(pst);
	assert(pst->_top > 0);
	//if(pst->_top>0)
	pst->_top--;
}

int StackSize(const Stack* pst)
{
	assert(pst);
	return pst->_top;
}
STDataType StackTop(Stack* pst)
{
	assert(pst);
	assert(pst->_top > 0);
	return pst->_a[pst->_top - 1];
}
int StackEmpty(Stack* pst)
{
	assert(pst);
	return !pst->_top;
}

队列

队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表

队列具有先进先出FIFO(First In First Out)

  • 入队列 :进行插入操作的一端称为队尾。
  • 出队列 :进行删除操作的一端称为队头。

数组来实现:无论是哪一边做队头,都需要挪动数据,开销大效率低。(不挪动数据相对复杂)。

链表实现

头文件
cpp 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* _next;
	QDataType _data;
}QueueNode;

typedef struct Queue
{
	QueueNode* _head;
	QueueNode* _tail;
}Queue;


void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);
//出入队
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);


//返回1是空,返回0是非空
int QueueEmpty(Queue* pst);
//获取栈顶数据
QDataType QueueTop(Queue* pst);
实现
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->_head = pq->_tail = NULL;
}
void QueueDestory(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->_head;
	while (cur)
	{
		QueueNode* next = cur->_next;
		free(cur);
		cur = next;
	}
	pq->_head = pq->_tail = NULL;
}
//出入队
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		exit(-1);
	}
	newnode->_data = x;
	newnode->_next = NULL;
	if (pq->_head == NULL)
	{
		pq->_head = pq->_tail = newnode;
	}
	else
	{
		pq->_tail->_next = newnode;
		pq->_tail = newnode;
	}
}
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->_head);
	QueueNode* next = pq->_head->_next;
	free(pq->_head);
	pq->_head = next;
	if (pq->_head == NULL)
	{
		pq->_tail = NULL;
	}
}
QDataType QueueFront(Queue* pq)
{
	assert(pq&&pq->_head);
	return pq->_head->_data;
}
QDataType QueueBack(Queue* pq)
{
	assert(pq && pq->_tail);
	return pq->_tail->_data;
}


//返回1是空,返回0是非空
int QueueEmpty(Queue* pq)
{
	return pq->_head == NULL ? 1 : 0;
}
//获取栈顶数据
QDataType QueueTop(Queue* pq)
{
	assert(pq);
	int sz = 0;
	QueueNode* cur = pq->_head;
	while (cur)
	{
		sz++;
		cur = cur->_next;
	}
	return sz;
}

数据结构的栈和堆和内存中的堆栈有什么区别?

  • 数据结构的栈、堆:**存储和管理数据,**解决一些一些问题。
  • 内存中的堆栈虚拟进程地址空间分段。一段内存区域的划分。

数据结构的栈和内存的栈都满足"后进先出"的规则。

循环队列

循环队列用数组实现更容易判断队列的空满。

cpp 复制代码
typedef struct {
    int*_a;
    int front;
    int rear;
    int k;
} MyCircularQueue;

bool myCircularQueueIsFull(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    q->_a=(int*)malloc(sizeof(int)*(k+1));
    q->front=q->rear=0;
    q->k=k;
    return q;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
        
    }
    else
    {
        obj->_a[obj->rear]=value;
        obj->rear = (obj->rear+1)%(obj->k+1);
        return true;
    }
    
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return false;
    }
    else
    {
        obj->front = (obj->front+1)%(obj->k+1);
        return true;
    }
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return -1;
    }
    return obj->_a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return -1;
    }
    int tail=obj->rear-1;
    if(tail==-1)
    {
        tail=obj->k;
    }
    return obj->_a[tail];
}


bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1)==obj->front;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->_a);
    free(obj);
}
相关推荐
张胤尘21 分钟前
算法每日一练 (9)
数据结构·算法
头发尚存的猿小二1 小时前
二叉树(顺序结构:堆)---数据结构
数据结构
橘颂TA2 小时前
每日一练之移除链表元素
数据结构·链表
Coder Zhang2 小时前
后序线索化二叉树,并找到指定结点前驱,非递归逆序输出
数据结构·算法
iFulling5 小时前
【数据结构】第六章:图
数据结构·笔记·算法
原来是猿6 小时前
蓝桥备赛(九)- 结构体和类
数据结构·c++·算法
Murphy_lx9 小时前
数据结构(回顾)
开发语言·数据结构
Vect.12 小时前
常见排序算法鉴赏(原理剖析+动图演示)
数据结构·算法·排序算法
葵野寺14 小时前
【Java---数据结构】栈和队列【Stack & Queue】
java·开发语言·数据结构·算法
幸运小圣14 小时前
单链表封装 - 使用JavaScript封装
javascript·数据结构·算法