目录
前言
栈和队列实际上都是一种特殊的线性表,即二者都是一种特殊的存取结构
一、栈
1.1栈的概念和结构
栈是一种特殊的线性结构,其只允许在规定的一端进行插入、删除操作。栈中元素的存取遵循后进先出的原则(LIFO)。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小
#include <assert.h> #include <stdio.h> typedef int DataType; typedef struct Stack { DataType* arry; int capacity; int top; }Stack; //创建一个栈并返回地址 Stack* stack_creat() { Stack* obj = (Stack*)malloc(sizeof(Stack)); obj->capacity = 2; obj->top = -1; //将top值赋值为-1是为了区分空与只含一个元素的情况 obj->arry = (DataType *)malloc(sizeof(DataType) * obj->capacity); assert(obj && obj->arry); return obj; } //扩容函数,当达到栈空间上线后还要入栈,则需扩容 void extend_capacity(Stack* obj) { obj->capacity *= 2; obj->arry = (DataType*)realloc(obj->arry,sizeof(DataType) * obj->capacity); assert(obj->arry); printf("扩容成功\n"); } //入栈,要注意判满 void Push_stack(Stack *obj,DataType x) { if (obj->top == obj->capacity - 1) { extend_capacity(obj); } obj->arry[++obj->top] = x; //top的初始值为-1,所以要先加一在使用 } //出栈,要注意判空 DataType Pop_stack(Stack* obj) { assert(-1 != obj->top); return obj->arry[obj->top--]; } //展示元素 void display(Stack* obj) { int i; for (i = 0;i <= obj->top;i++) { printf("%d ", obj->arry[i]); } } //判空 bool is_empty(Stack* obj) { return -1 == obj->top; } int main() { Stack* obj = stack_creat(); Push_stack(obj, 1); Push_stack(obj, 2); Push_stack(obj, 3); Push_stack(obj, 4); display(obj); printf("\n"); Pop_stack(obj); Pop_stack(obj); Pop_stack(obj); Pop_stack(obj); printf("%d\n", is_empty(obj)); Pop_stack(obj); display(obj); return 0; }
二、队列
2.1 队列的基本概念与结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。
2.2队列的实现
#define _CRT_SECURE_NO_WARNINGS 1 #pragma warning(disable:6031) #include <stdlib.h> #include <assert.h> #include <stdio.h> typedef int DataType; typedef struct que_node { DataType data; struct que_node* next; }Node; typedef struct que { Node* head; Node* tail; int que_sz; }Que; //这里以有头节点的队列为例 Que *que_creat() { Que* obj = (Que*)malloc(sizeof(Que)); obj->head = (Node*)malloc(sizeof(Node)); assert(obj&&obj->head); obj->tail = obj->head; obj->que_sz = 0; return obj; } //存入数据 void que_push(Que* obj,DataType x) { Node* tmp = (Node*)malloc(sizeof(Node)); assert(tmp); tmp->data = x; tmp->next = NULL; obj->tail->next = tmp; obj->tail = obj->tail->next; obj->que_sz++; } //弹出数据(注意:我们在设计队列的时候,设计了一个哨兵位) void que_pop(Que* obj) { Node* tmp=obj->head->next; assert(tmp); obj->head->next = tmp->next; obj->que_sz--; free(tmp); } //判断队列是否为空 bool is_empty(Que *obj) { return obj->tail == obj->head; } //销毁队列 void destroy_que(Que *obj) { assert(obj); Node* cur = obj->head->next; Node* cur_next; while (cur) { cur_next = cur->next; free(cur); cur = cur_next; } free(obj->head); free(obj); } //展示队列 void display_que(Que *obj) { Node* tmp=obj->head->next; while (tmp) { printf("%d ", tmp->data); tmp = tmp->next; } printf("\n"); } //输入数据测试 int main() { Que* obj = que_creat(); que_push(obj, 1); que_push(obj, 2); display_que(obj); que_pop(obj); display_que(obj); printf("%d ", obj->que_sz); return 0; }
2.3循环队列
typedef struct circular_que { int *que; int head; int rear; int sz; } MyCircularQueue; MyCircularQueue* myCircularQueueCreate(int k) { MyCircularQueue *que=(MyCircularQueue *)malloc(sizeof(MyCircularQueue)); que->que=(int *)malloc(sizeof(int)*(k+1)); que->head=que->rear=0; que->sz=k+1; return que; } bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { if((obj->rear+1)%obj->sz!=obj->head) { obj->que[obj->rear]=value; obj->rear=(obj->rear+1)%obj->sz; return true; } return false; } bool myCircularQueueDeQueue(MyCircularQueue* obj) { if(obj->head==obj->rear) { return false; } else { obj->head=(obj->head+1)%obj->sz; return true; } } int myCircularQueueFront(MyCircularQueue* obj) { if(obj->head!=obj->rear) { return obj->que[obj->head]; } else { return -1; } } int myCircularQueueRear(MyCircularQueue* obj) { if(obj->head!=obj->rear) { return obj->que[(obj->rear-1+obj->sz)%obj->sz]; } else { return -1; } } bool myCircularQueueIsEmpty(MyCircularQueue* obj) { if(obj->head==obj->rear) { return true; } else { return false; } } bool myCircularQueueIsFull(MyCircularQueue* obj) { if((obj->rear+1)%(obj->sz)==obj->head) { return true; } else { return false; } } void myCircularQueueFree(MyCircularQueue* obj) { free(obj->que); free(obj); }
总结
在设计栈和队列的时候要特别注意指针的越界问题,特别是在遍历队列和栈的时候。此外,还要多加练习。