栈
以链表形式实现栈
入栈=头插、出数据=头删
如果是双向链表,哪边是栈顶,哪边是栈底都可以
单链表实现的栈,有头节点,入栈一个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++