目录
1.栈
1.1 栈的概念及结构
1.1.1 概念
-
栈 是一种特殊的线性表,其只允许在固定的一段进行元素的插入和删除操作。**进行数据插入和删除的一端称为栈顶,另一端称为栈底。**栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
-
压栈:栈的插入操作称为进栈/压栈/入栈,压入的数据在栈顶。
-
出栈:栈的删除操作叫做出栈,出数据也在栈顶。
1.1.2 结构
1.2 栈的实现
栈的实现一般可以使用数组或者链表,但栈的操作都是在栈顶上(数组尾端)操作的,因此使用数组来进行实现会方便一些。
#pragma once
typedef int DataType;
//动态存储的栈
//非动态增长,容量不足需要扩容
typedef struct Stack
{
DataType* array;
int Size;
int Capacity;
}Stack;
//初始化栈
void StackInit(Stack* ps);
//增容
void StackInse(Stack* ps);
//入栈
void StackPush(Stack* ps,DataType data);
//出栈
void StackPop(Stack* ps);
//监测栈是否为空
int IsStackEmpty(Stack* ps);
//获取栈顶元素
DataType StackTop(Stack* ps);
//获取栈中有效元素的个数
int StackSize(Stack* ps);
//获取栈容量
int StackCapacity(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);
代码实现
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
void StackInit(Stack* ps)
{
assert(ps);
ps->array = (DataType*)malloc(sizeof(DataType)* 3);
if (NULL == ps->array)
{
assert(0);
return;
}
ps->Capacity = 3;
ps->Size = 0;
}
void StackInse(Stack* ps)
{
assert(ps);
if (ps->Size == ps->Capacity)
{
ps->array = (DataType*)realloc(ps->array, sizeof(DataType)*ps->Capacity * 2);
ps->Capacity = ps->Capacity * 2;
}
}
void StackPush(Stack* ps, DataType data)
{
assert(ps);
StackInse(ps);
ps->array[ps->Size++] = data;
}
void StackPop(Stack* ps)
{
assert(ps);
if (IsStackEmpty(ps))
{
assert(0);
return;
}
ps->Size--;
}
int IsStackEmpty(Stack* ps)
{
assert(ps);
if (0 == ps->Size)
return 1;
return 0;
}
DataType StackTop(Stack* ps)
{
assert(ps);
return ps->array[ps->Size - 1];
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->Size;
}
int StackCapacity(Stack* ps)
{
assert(ps);
return ps->Capacity;
}
void StackDestroy(Stack* ps)
{
assert(ps);
ps->Size = 0;
ps->Capacity = 0;
free(ps->array);
ps->array = NULL;
}
2.队列
2.1 队列的概念及结构
2.1.1 概念
队列:只允许在一段进入插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特性。
- 入队列:进行插入操作的一端称为队尾
- 出队列:进行删除操作的一端称为对头
2.1.2 结构
2.2 队列的实现
队列同样也可以用数组或者链表的结构实现,因为队列的操作主要是在队头和队尾完成的,而对队头元素的操作使用数组效率较低,因此我们考虑使用链表的结构来进行实现
#pragma once
typedef int DataType;
//链式结构:表示队列
typedef struct QNode
{
DataType val;
struct Node* next;
}Node;
//队列的结构
typedef struct Queue
{
Node* front;//标记队头
Node* tail;//标记队尾
}Queue;
//创建队列新节点
Node* BuyQueueNode(DataType data);
//初始化队列
void QueueInit(Queue* q);
//检测队列是否为空
int IsQueueEmpty(Queue* q);
//队尾入队列
void QueuePush(Queue* q, DataType data);
//队头出队列
void QueuePop(Queue* q);
//获取队头元素
DataType QueueFront(Queue* q);
//获取队尾元素
DataType QueueTail(Queue* q);
//获取队列中有效元素的个数
int QueueSize(Queue* q);
//销毁队列
void QueueDestroy(Queue* q);
代码实现:
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
Node* BuyQueueNode(DataType data)
{
Node* NewNode = (Node*)malloc(sizeof(Node));
if (NULL == NewNode)
{
assert(0);
}
NewNode->next = NULL;
NewNode->val = data;
return NewNode;
}
//选择带头链表,队头操作更加方便
void QueueInit(Queue* q)
{
assert(q);
q->front = BuyQueueNode(0);
q->tail = q->front;
}
int IsQueueEmpty(Queue* q)
{
assert(q);
if (q->tail == q->front)
return 1;
return 0;
}
void QueuePush(Queue* q, DataType data)
{
assert(q);
q->tail->next = BuyQueueNode(data);
q->tail = q->tail->next;
}
void QueuePop(Queue* q)
{
assert(q);
if (IsQueueEmpty(q))
{
assert(0);
return;
}
Node* cur = q->front->next;
q->front->next = cur->next;
if (NULL == cur->next)
q->tail = q->front;
free(cur);
}
DataType QueueFront(Queue* q)
{
assert(q);
if (IsQueueEmpty(q))
{
printf("NULL!!\n");
return -1;
}
return q->front->next->val;
}
DataType QueueTail(Queue* q)
{
assert(q);
if (IsQueueEmpty(q))
{
printf("NULL!!\n");
return -1;
}
return q->tail->val;
}
int QueueSize(Queue* q)
{
assert(q);
int count = 0;
Node* cur = q->front->next;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
void QueueDestroy(Queue* q)
{
assert(q);
Node* delNode = q->front;
while (delNode)
{
q->front = q->front->next;
free(delNode);
delNode = q->front;
}
}
3.环形队列
3.1概念和结构
3.1.1 概念
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。(来源:力扣(LeetCode))
内存上没有环形的结构,因此环形队列实际上是以数组的线性空间来实现的。当数据到了尾部时,它将转回到0位置来处理。这个的转回是通过取模操作来执行的。利用一个入队下标和一个出队下标来定制一个数组而构造一个环形队列。
3.1.2 结构
3.2 环形队列的实现
设计循环队列 OJ链接
//环形队列一般是固定大小的
typedef struct {
int* array;
int front;
int rear;
int size;
int capacity;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* mcq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
mcq->array = (int*)malloc(sizeof(int)*k);
if (NULL == mcq)
{
assert(0);
}
mcq->capacity = k;
mcq->size = mcq->front = mcq->rear = 0;
return mcq;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
assert(obj);
return obj->size == obj->capacity;
}
//一般认为front=tail队列已满(循环队列不空的前提下)
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
assert(obj);
if (obj->front == obj->rear&&!myCircularQueueIsFull(obj))
return true;
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
assert(obj);
if (myCircularQueueIsFull(obj))
return false;
if (obj->rear == obj->capacity)
obj->rear = 0;
obj->array[obj->rear] = value;
obj->rear++;
if (obj->rear == obj->capacity)
obj->rear = 0;
obj->size++;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
assert(obj);
if (myCircularQueueIsEmpty(obj))
return false;
obj->front++;
if (obj->front == obj->capacity)
obj->front = 0;
obj->size--;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
assert(obj);
if (myCircularQueueIsEmpty(obj))
return -1;
return obj->array[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
assert(obj);
if (myCircularQueueIsEmpty(obj))
{
assert(0);
return -1;
}
if (0 == obj->rear)
obj->rear = obj->capacity;
return obj->array[obj->rear - 1];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->array);
free(obj);
}