栈、队列1

以链表形式实现栈

入栈=头插、出数据=头删
如果是双向链表,哪边是栈顶,哪边是栈底都可以
单链表实现的栈,有头节点,入栈一个s节点时:

s->next=Top->next; Top->next=s;

在这里插入图片描述

栈:特殊的线性表-----特性:后进先出
一般情况下:栈都是通过顺序结构来实现的
实现建议用数组。
栈的作用:
1.如果有后进先出而求的地方,比如迷宫问题2.递归改成非递归

.h

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

typedef int STDataType;
//struct Stack;
//{//静态
//	int _a[N]; int _size;
//};
typedef struct Stack;
{
	STDataType*  _a[N]; int _top;//栈顶的下标
	int _capacity;
}Stack;
//初始化
void StackInit(Stack* pst);//不能传值,传指针
void StackDestory(Stack* pst);
// 入栈
void StackPush(Stack* pst,STDataType x);
// 出栈
void StackPop(Stack* pst); 
//获取数据数,
//也可以是int StackSize(Stack st),这样是直接传结构体,拷贝,不会改变结构体里指向的东西,求完大小之后,直接返回即可,
int StackSize(Stack* pst); //这样是传指针,传的量比传结构体小
// 返回1是空,返回0是非空
int StackEmpty(Stack* pst); 
// 获取栈顶的数据
STDataType StackTop(Stack* pst);

Stack.c

#include"Stack.h"
void StackInit(Stack*pst){
	assert(pst);
	/*pst->_a = NULL;pst->_top = 0;
	pst->_capacity = 0 ;*/
	pst->_a = (STDataType*)malloc(sizeof(STDataType)* 4); //申请空间
	pst->_top = 0;
	pst->_capacity = 4;
}
void StackDestory(Stack* pst){
	assert(pst);
	free(pst->_a);
	pst->_a = NULL;
	pst->_top = pst->_capacity = 0;
}
	// 入栈
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->_a[pst->_top] = x;
	pst->_top++;//指向最后1个数据的下1个
}
//出栈
void StackPop(Stack* pst){
	assert(pst);
	assert(pst->_top > 0);
	--(pst->_top);
}
//获取栈中有效元素个数
int StackSize(Stack* pst){
	assert(pst);
	return pst->_top;
}
//返回1是空,返回0是非空
int StackEmpty (Stack* pst){
assert(pst);
return pst->_top == 0 ? 1 : 0;
//return !pst->_top;
}
//获取栈顶的数据
STDataType StackTop(Stack* pst){
	assert(pst);
	assert(pst->_top > 0);//栈里无数据
	return pst->_a[pst->_top - 1];
}

.c

#include"Stack.h"
void TestStack(){
	//后进先出是相对入的时候,在栈里的数据
	Stack st;
	StackInit(&st);
	StackPush(&st,1);
	StackPush(&st,2);
	/*printf("%d ",StackTop(&st));
	StackPop(&st);*/
	StackPush(&st,3);
	StackPush(&st,4);
		while (!StackEmpty(&st)){//遍历栈
		printf("%d ",StackTop(&st));//拿到栈顶数据
		StackPop(&st);//真正“拿到”,把栈顶数据弹出去然后才能取下1个数据
	}
	printf("\n");
	StackDestory(&st);
}
int main(){
	TestStack();
		return		0;	}

逆序打印链表:
递归方式:后调用先退出,与栈特性刚好是匹配的
不是所有的递归转循环时都需要借助栈,如阶乘、求和、字符串逆序、斐波那契数列等时,实质上就是迭代,只需要:循环,不需要栈。

void printListReverse(Node* head){
	Stack s;
	StackInit(&s);
	//1.将链表中所有的节点入栈
	Node* cur = head;
	while (cur)
	{
		StackPush(&s, cur); cur = cur->next;
	}
	// 2将栈中的元素依次取出并打印
	while (!StackEmpty(&s))
	{

		printf("%d ", StackTop(&s)->data);
		StackPop(&s);
	}
	StackDestroy(&s);
}

队列

底层用单链表结构实现,
1.先进先出的场景,比如要保持序列公平,排对抽号机(抽号的人=生产者=往队列里生产序号、窗口人=消费者)
2.广度优先遍历
出队操作,一定会影响头指针,如果出队之后,队列为空,会影响尾指针。

.h

#pragma once
#include<assert.h>
#include<stdlib.h>
#include<stdio.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* pq);
int QueueSize(Queue* pq);

Queue.c

#include"Queue.h"
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)
		{     printf("内存不足\n"); 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);
					assert(pq->_head);
					return pq->_head->_data;
				}
QDataType QueueBack(Queue* pq){
					assert(pq);
					assert(pq->_tail);
					return pq->_tail->_data;
				}
				//返回1是空,返回0是非空;判断是否=空
int QueueEmpty(Queue* pq){
					assert(pq);//头空时,肯定尾=空
					return pq->_head == NULL ? 1 : 0;
				}
			}
	int QueueSize(Queue* pq){
		assert(pq);
		QueueNode* cur = pq->_head;
		int size = 0;
		while (cur){
			++size;
			cur = cur->_next;
		}
		return size;
	}			}

.c

#include"Queue.h"
void TestQueue(){
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	while (!QueueEmpty(&q)){
printf("%d ", QueueFront(&q));//取队头数据
		QueuePop(&q);
	}
	printf("\n");
	QueueDestory(&q);//最后QueueDestory,提前了就打印不出结果
}
int main(){
	TestQueue;
	return		0;	}

用链表来模拟实现队列—单链表

用不带头结点的单链表存储队列,把1节点出队,队头、队尾指针都可能要修改:
在这里插入图片描述

Queue.c

#include "q.h"

#include <stdio.h>
#include <malloc.h>
#include <assert.h>
QNode* buyQNode(QDataType data)
{
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (NULL == newNode)
	{
		assert(0);
		return NULL;
	}

	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->back = NULL;
	q->size = 0;
}

void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;//第1个结点
	while (cur)
	{
		q->front = cur->next;
		free(cur);
		cur = q->front;
	}

	q->back = NULL;
	q->size = 0;
}

// 入队列
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newNode = buyQNode(data);

	if (NULL == q->front)//空链表
	{
		q->front = newNode;
	}
	else
	{
		q->back->next = newNode; //指向newNode
	}

	q->back = newNode;//成为最后1个结点
	q->size++;
}


// 出队列
void QueuePop(Queue* q)
{
	if (QueueEmpty(q))
	{
		return;
	}
	else
	{
		QNode* delNode = q->front;
		q->front = delNode->next;//要删的结点下1个
		free(delNode);
		if (NULL == q->front)//队列=空
		{
			q->back = NULL;//如果back不置空,那么back=野指针
		}
	}

	q->size--;
}

// 获取队头元素
QDataType QueueFront(Queue* q)
{
	assert(!QueueEmpty(q));
	return q->front->data;
}

// 获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(!QueueEmpty(q));
	return q->back->data;
}

// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(!QueueEmpty(q));
	return q->size;
}

// 检测队列是否为空
int QueueEmpty(Queue* q)
{
	assert(q);
	return NULL == q->front;
}


///
void TestQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	printf("%d\n", QueueFront(&q));//1
	printf("%d\n", QueueBack(&q));//5
	printf("%d\n", QueueSize(&q));//5

	QueuePop(&q);//删除1
	QueuePop(&q);
	QueuePop(&q);
	printf("%d\n", QueueFront(&q));//4
	printf("%d\n", QueueBack(&q));//5
	printf("%d\n", QueueSize(&q));//2

	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);

	if (QueueEmpty(&q))
	{
		printf("队列已经为空\n");
	}
	else
	{
		printf("队列不为空\n");
	}
	QueueDestroy(&q);
}

.h

#pragma once

typedef int QDataType;
typedef struct QNode//结点
{
	struct QNode* next;
	QDataType data;
}QNode;

typedef struct Queue//Queue=类型名称
{
	QNode* front;   // 指向队头
	QNode* back;    // 指向队尾,最后1个结点
	int size;       // 队列中有效元素个数
}Queue;

void QueueInit(Queue* q);

void QueueDestroy(Queue* q);

// 入队列
void QueuePush(Queue* q, QDataType data);

// 出队列
void QueuePop(Queue* q);

// 获取队头元素
QDataType QueueFront(Queue* q);

// 获取队尾元素
QDataType QueueBack(Queue* q);

// 获取队列中有效元素个数
int QueueSize(Queue* q);

// 检测队列是否为空
int QueueEmpty(Queue* q);
//需要改变头指针指向时:用2级指针

/
void TestQueue();

.c

#include "q.h"
int main(){
	TestQueue();
	return 0;
}

循环队列

循环队列的存储空间为Q(1 8),初始状态为 front=rear=8。一系列正常的入队与退队操作后,front=rear=1,则循环队列中的元素个数为0或8
放满时,a出队,front++,j入队,rear++;只有a时,a入队,rear++,a出队,front++
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值