行路难!行路难!多歧路,今安在?长风破浪会有时,直挂云帆济沧海。————李白
一 .堆栈
1 什么是堆栈
堆栈是一种特殊的线性表,堆栈中的元素以及元素之间的逻辑关系和线性表完全相同。在操作上的差别是线性表允许在任意位置插入和删除元素,而堆栈只允许在固定一端插入和删除元素,堆栈中允许插入和删除元素的一端称为栈顶,另一端称为栈底。
栈顶的当前位置是动态的,用于标记栈顶当前位置的变量,称为栈顶指示器。堆栈的插入操作,通常称为入栈。堆栈的删除操作通常称为出栈。
根据堆栈的定义,我们可以发现,每次入栈的元素都放在原栈顶元素之前而成为新的栈顶元素,每次出栈的元素都是原栈顶元素。这样最后进入栈的元素总是最先退出栈的,因此堆栈也称作后进先出的线性表,或简称为后进先出表。
2 堆栈的两种实现方式
栈的实现一般可以使用数组或者链表实现
链式栈:用链表的结构来实现栈。
顺序栈:用数组的结构来实现栈。
优缺点:
单向链式结构的出栈入栈效率比较低,因为我们要先找到尾结点再行插入删除
而顺序栈只需要记录栈顶位置,进行出栈入栈十分方便,不需要多余的空间存储地址。
所以相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
3 堆栈的操作实现
3.1 栈的结构体和初始化
结构体:
#pragma once#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
初始化:
void StackInit(ST* ps)
{assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = 4;ps->top = 0;
}
3.2 销毁
void StackDestory(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
3.3入栈
// 入栈
void StackPush(ST* ps, STDataType x)
{assert(ps);// 满了-》增容if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}else{ps->a = tmp;ps->capacity *= 2;}}ps->a[ps->top] = x;ps->top++;
}
3.4出栈
// 出栈
void StackPop(ST* ps)
{assert(ps);// 栈空了,调用Pop,直接中止程序报错assert(ps->top > 0);//ps->a[ps->top - 1] = 0;ps->top--;
}
3.5判断栈是否为空
bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}
3.6取顶部数据
STDataType StackTop(ST* ps)
{assert(ps);// 栈空了,调用Top,直接中止程序报错assert(ps->top > 0);return ps->a[ps->top - 1];
}
3.7取栈中有效数据的个数
int StackSize(ST* ps)
{assert(ps);return ps->top;
}
4 完整代码
Stack.h
#pragma once#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void StackInit(ST* ps);void StackDestory(ST* ps);
// 入栈
void StackPush(ST* ps, STDataType x);
// 出栈
void StackPop(ST* ps);STDataType StackTop(ST* ps);int StackSize(ST* ps);bool StackEmpty(ST* ps);
Stack.c
#include "Stack.h"void StackInit(ST* ps)
{assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->capacity = 4;ps->top = 0;
}void StackDestory(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}// 入栈
void StackPush(ST* ps, STDataType x)
{assert(ps);// 满了-》增容if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}else{ps->a = tmp;ps->capacity *= 2;}}ps->a[ps->top] = x;ps->top++;
}// 出栈
void StackPop(ST* ps)
{assert(ps);// 栈空了,调用Pop,直接中止程序报错assert(ps->top > 0);//ps->a[ps->top - 1] = 0;ps->top--;
}STDataType StackTop(ST* ps)
{assert(ps);// 栈空了,调用Top,直接中止程序报错assert(ps->top > 0);return ps->a[ps->top - 1];
}int StackSize(ST* ps)
{assert(ps);return ps->top;
}bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}
二 .队列
1 队列的概念及结构
队列也是一种特殊的线性表,队列中的元素及元素间的逻辑关系和线性表完全相同,在操作上的差异是; 线性表允许在任意位置插入和删除元素。而队列只允许在其一端进行插入操作,在其另一端进行删除操作。
在队列中,允许进行插入操作的一端成为队尾。允许进行删除操作的一端成为队头,队头队尾,分别由队头指针和队尾指针指示。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列,根据队列的定义,我们可以把,队列想象成是一种先进先出的线性表,简称先进先出表
2 队列的实现形式
队列也可以数组和链表的结构实现,但使用链表的结构实现更优一些,因为如果使用数组的结构, 出队列在数组头上出数据,效率会比较低。
3 队列的操作实现
3.1 结构体
typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;
}Queue;
3.2 队列初始化
void QueueInit(Queue* pq)
{assert(pq);pq->head = pq->tail = NULL;
}
3.3 队列的销毁
void QueueDestory(Queue* pq)
{assert(pq);QNode* cur = pq->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;
}
3.4 入队列(队尾入)
// 队尾入
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->tail == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}
}
3.5 出队列(队头出)
// 队头出
void QueuePop(Queue* pq)
{assert(pq);assert(pq->head);if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}
}
3.6 删除队内数据
3.6.1 前删
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->head);return pq->head->data;
}
3.6.2 尾删
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->head);return pq->tail->data;
}
3.7 返回队列大小
int QueueSize(Queue* pq)
{assert(pq);int size = 0;QNode* cur = pq->head;while (cur){++size;cur = cur->next;}return size;
}
3.8 清空队列
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}
4 完整代码
queue.h:
#define _CRT_SECURE_NO_WARNINGS
#pragma once#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* head;QNode* 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);//队列大小
int QueueSize(Queue* pq);//清空队列
bool QueueEmpty(Queue* pq);
queue.c:
#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);QNode* cur = pq->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;
}// 队尾入
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}newnode->data = x;newnode->next = NULL;if (pq->tail == NULL){pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}
}// 队头出
void QueuePop(Queue* pq)
{assert(pq);assert(pq->head);if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}
}QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->head);return pq->head->data;
}QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->head);return pq->tail->data;
}int QueueSize(Queue* pq)
{assert(pq);int size = 0;QNode* cur = pq->head;while (cur){++size;cur = cur->next;}return size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;
}