一、栈
1.栈的概念及结构
栈是一种特殊的线性表,其只允许在固定的一端进行插入删除。进行数据插入和删除的一端称为栈顶,另一端称为栈底。
特点:先进后出
入栈:
出栈:
2.栈的实现
栈可以用数组和链表实现,俩者相比,用数组结构实现更优。
//定义栈的结构,对函数进行声明
typedef int DataType;
//定义动态增长栈结构
typedef struct Stack
{
int size;
DataType* arr;
int capacity;
}Stack;
// 初始化栈
void StackInit(Stack* ps);
//检测栈的容量
int StackCheak(Stack* ps);
//增加栈的容量
void StackAdd(Stack* ps);
// 入栈
void StackPush(Stack* ps, DataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
DataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
//打印数据
void StackPrint(Stack* ps);
//测试函数
void Test();
void StackInit(Stack* ps)
{
assert(ps);
ps->arr = (DataType*)malloc(sizeof(DataType) * 3);
if (NULL == ps->arr)
{
printf("申请空间失败!!!\n");
return;
}
ps->size = 0;
ps->capacity = 3;
}
int StackCheak(Stack* ps)
{
if (ps->size == ps->capacity)
{
return 1;
}
return 0;
}
void StackAdd(Stack* ps)
{
assert(ps);
ps->arr = (Stack*)realloc(ps->arr, sizeof(DataType) * (ps->size*2));
if (ps->arr==NULL)
{
printf("新空间申请失败!!!\n");
return;
}
//ps->size = ps->capacity;
ps->capacity = ps->capacity * 2;
}
int StackEmpty(Stack* ps)
{
if (ps->size == 0)
{
return 1;
}
return 0;
}
void StackPush(Stack* ps, DataType data)
{
if (StackCheak(ps))
{
StackAdd(ps);
}
ps->arr[ps->size] = data;
ps->size++;
}
void StackPop(Stack* ps)
{
assert(ps);
if (StackEmpty(ps))
{
printf("栈为空!!!\n");
return;
}
ps->arr[--ps->size] = 0;
}
DataType StackTop(Stack* ps)
{
assert(ps);
if (StackCheak(ps))
{
return -1;
}
return ps->arr[ps->size-1];
}
int StackSize(Stack* ps)
{
return ps->size;
}
void StackDestroy(Stack* ps)
{
assert(ps);
ps->size = 0;
ps->capacity = 0;
free(ps->arr);
ps->arr = NULL;
}
void StackPrint(Stack* ps)
{
assert(ps);
for (int i = 0; i < ps->size; ++i)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
//测试函数
void Test()
{
Stack ps;
StackInit(&ps);
StackPush(&ps, 1);
StackPush(&ps, 2);
StackPush(&ps, 4);
StackPush(&ps, 0);
StackPush(&ps, 9);
printf("%d\n", StackTop(&ps));
printf("%d\n", StackSize(&ps));
StackPop(&ps);
StackPrint(&ps);
printf("%d\n", StackTop(&ps));
printf("%d\n", StackSize(&ps));
StackDestroy(&ps);
}
二、队列
1.队列的概念及结构
只允许在一端插入,另一端删除的特殊线性表。进行插入的一头称为队尾,进行删除的一端称为对头
特点:先进先出
2.队列实现
typedef int DataType;
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* next;
DataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
//队头指针和队尾指针
QNode * front;
QNode* rear;
}Queue;
//创建结点
QNode* CreateNode(DataType data);
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, DataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
DataType QueueFront(Queue* q);
// 获取队列队尾元素
DataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
//打印函数
void QueuePrint(Queue* q);
//测试函数
void Test();
//创建结点
QNode* CreateNode(DataType data)
{
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
exit(0);
}
newnode->next = NULL;
newnode->data = data;
return newnode;
}
//初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->front = NULL;
q->rear = NULL;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
if (q->front == NULL && q->rear == NULL)
{
return 1;
}
return 0;
}
// 队尾入队列
void QueuePush(Queue* q, DataType data)
{
assert(q);
//创建结点
QNode* newnode = CreateNode(data);
//队列为空
if (QueueEmpty(q))
{
q->front = newnode;
q->rear = newnode;
}
//队列不为空
else
{
q->rear->next = newnode;
q->rear = newnode;
}
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
if (QueueEmpty(q))
{
printf("队列为空!!!\n");
}
//当front和rear指向同一个元素,即队列中只有一个元素
else if (q->front == q->rear)
{
free(q->front);
q->front = NULL;
q->rear = NULL;
}
else
{
//保存front指针
QNode* del = q->front;
q->front = q->front->next;
free(del);
}
}
// 获取队列头部元素
DataType QueueFront(Queue* q)
{
assert(q);
return q->front->data;
}
// 获取队列队尾元素
DataType QueueBack(Queue* q)
{
assert(q);
return q->rear->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
QNode* cur = q->front;
int sum = 0;
while (cur)
{
sum++;
cur = cur->next;
}
return sum;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
//头删
QNode* cur = q->front;
while (cur)
{
q->front = cur->next;
free(cur);
cur = q->front;
}
q->front = NULL;
q->rear = NULL;
}
//打印函数
void QueuePrint(Queue*q)
{
if (QueueEmpty(q))
{
printf("空队列!!!\n");
return;
}
QNode* cur = q->front;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void Test()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 3);
QueuePush(&q, 5);
QueuePush(&q, 7);
QueuePush(&q, 0);
QueuePush(&q, 4);
QueuePrint(&q);
printf("size = %d\n", QueueSize(&q));
printf("front_data=%d\n", QueueFront(&q));
printf("rear_data=%d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePrint(&q);
printf("size = %d\n", QueueSize(&q));
QueueDestroy(&q);
}
3.循环队列
上述队列采用链式结构存储,是因为数组在每次出队的时候都要将队头元素后的所有元素向前搬移,时间复杂度为O(N),效率低。
当然,我们也可以用数组存储队列,为了使出队的时间复杂对达到O(1),我们可以让front指针在每次出队时候向后移动一位:
但在这时候就会出现一个问题:当front和rear指针指向相同时,此时,认为队列已满,不能继续入队,但实际上数组起始位置还有空间,这种情况就被称为假溢出。
解决假溢出问题:采用循环队列
循环队列:
对于上述俩种情况,当我们用front==rear来判断队列是否为空的时候,显然不可以,这时候,该怎么解决这个问题呢?
解决:
3.1 少用一个存储空间
3.2 使用一个标志位
3.3 使用变量count计数 (N为该队列中最多存储的元素个数)
初始:count=0
入队:count++ 出队:count--
队满:count==N 队空:count==0
4.循环队列实现
typedef struct {
int*array;
int capacity;//循环队列容量
int size; //循环队列大小
int front;
int rear;
} MyCircularQueue;
//用数组模拟实现循环队列
//初始化循环队列
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue*q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if(q==NULL)
{
return NULL;
}
q->array=(int*)malloc(sizeof(int)*k);
q->capacity=k;
q->size=0;
q->front=0;
q->rear=0;
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
assert(obj);
return obj->size==0;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
if(obj->size==obj->capacity)
{
return true;
}
return false;
}
//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
assert(obj);
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->array[obj->rear++]=value;
//当队尾指针到数组最后一个位置时,将其指向数组第一个位置
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))
{
return -1;
}
return obj->array[((obj->rear-1)+obj->capacity)%obj->capacity];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->array);
free(obj);
}