数据结构自学Day6 栈与队列
1. 栈
其实栈与队列仍然属于线性表(有n个元素构成的集合,逻辑结构呈现线形)
线形表:顺序表,链表,栈,队列,串(字符串)
栈(Stack)是一种线性数据结构,进行数据插入和删除的一段成为栈顶,另外一段称为栈底,数据元素遵守“后进先出” (LIFO, Last In First Out)
栈的插入数据 --压栈/进栈,入数据在栈顶
栈的删除数据 -- 出栈,出数据也在栈顶。
这里栈如何实现呢?考虑(LIFO: 后进先出)
如果是双向链表的话,无所谓栈顶与栈底的位置。
2. 栈的实现
栈的实现利用数组实现提高内存访问效率
1、栈的初始化
typedef int STDataType; #define Ini_capacity 5typedef struct Stack {int* _val;int _size;int _capacity; }Stack;void StackInit(Stack* pst){assert(pst);// pst->_val = NULL;// pst->_capacity = 0;// pst->_size = 0;pst->_val = (STDataType*) malloc(Ini_capacity*sizeof(STDataType));if(pst->_val == NULL){perror("malloc");exit(-1);}pst->_size = 0;pst->_capacity =Ini_capacity;}
2、压栈(入栈操作)
// 入栈 void StackPush(Stack* pst,STDataType Val){assert(pst);if(pst->_size == pst->_capacity){//增容pst->_capacity = 2*pst->_capacity;STDataType* tmp = realloc(pst->_val,pst->_capacity*sizeof(STDataType));pst->_val = tmp;tmp = NULL;}pst->_val[pst->_size] = Val;pst->_size++; }
3、出栈操作
void StackPop(Stack* pst){assert(pst && pst->_size > 0);--pst->_size; }
4 、返回栈内数据个数,是否为空,以及栈顶元素
//获取数据个数 int StackSize(Stack* pst){assert(pst);return(pst->_size); } //返回1 是空,返回0是非空 int StackEmpty(Stack* pst){assert(pst);// return pst->_size == 0 ? 1 : 0;return !pst->_size; } //获取栈顶数据 STDataType StackTop(Stack* pst){assert(pst && pst->_size>0);return pst->_val[pst->_size-1]; }
5、栈的摧毁,释放空间
//栈的摧毁 void StackDestroy(Stack* pst){assert(pst);free(pst->_val);pst->_val = NULL;pst->_size =pst->_capacity = 0; }
3、栈的常见应用:
1、函数调用(函数栈帧)
2、括号匹配(如表达式合法性)
3、 浏览器历史记录(后退/前进)
4、深度优先搜索(DFS)迷宫问题
4、队列
队列(Queue)是一种线性数据结构:一个典型的队列有两个端:Front(队首):元素被取出的地方 Rear(队尾):元素被加入的地方。它的特点是:先进先出(FIFO, First In First Out)。
同样,队列的实现也可以通过数组和链表进行实现。?考虑(FIFO: 后进先出)。
数列出队列有些麻烦:需要挪动数据,因为队头的数据出队列后,队尾数据需要补充。
单链表入队列只需要尾插,出队列只需要将头节点给到下一个节点,然后free即可。
5、队列的实现
队列的实现利用单向链表
1、队列的初始化 (保存队列的头指针,尾指针)
//利用单向链表的形式实现栈 typedef int QeDataType;typedef struct QueueNode {QeDataType _data;struct QueueNode* next; }QueueNode; //存储队列的头,尾指针用于插入和删除队列元素 typedef struct Queue {QueueNode* _head;QueueNode* _tail; }Queue;//队列的初始化 void QueueInit(Queue* pq){assert(pq);pq->_head = pq->_tail = NULL; }
2、队列新增元素
//队列插入元素 void QueuePush(Queue* pq, QeDataType x){assert(pq);QueueNode*NewNode = (QueueNode*)malloc(sizeof(QueueNode));if(NewNode == NULL){perror("malloc");exit(-1);}NewNode->next=NULL;NewNode->_data = x;if(pq->_head == NULL){pq->_head = pq->_tail = (QueueNode*)malloc(sizeof(QueueNode));}else{pq->_tail->next = NewNode;pq->_tail = NewNode;} }
3、队列删除元素
//队列删除元素 void QueuePop(Queue* pq){assert(pq);if(pq->_head == NULL){printf("队列为空\n");exit(-1);}QueueNode* head_next = pq->_head->next;free(pq->_head);pq->_head = head_next;if(pq->_head == NULL){pq->_tail = NULL;} }
4、取出队列头数据和尾数据
//取出队头数据 QeDataType QueueFront(Queue* pq){assert(pq);if(pq->_head ==NULL){return NULL;}return pq->_head->_data; } //取出队尾数据 QeDataType QueueBack(Queue* pq){assert(pq);if(pq->_tail ==NULL){return NULL;}return pq->_tail->_data; }
5、检查队列是否为空,返回队列大小
//检查队列是否为空,返回队列大小 int QueueEmpty(Queue* pq){assert(pq);return !pq->_head; } int QueueSize(Queue* pq){assert(pq);if(pq == NULL){return 0;}QueueNode* Cur = pq->_head;int count =0;while(Cur || Cur != pq->_tail) {count++;Cur = Cur->next;}return count; }
6、队列的常见应用
应用场景 | 描述 |
---|---|
操作系统调度 | CPU 任务调度用就绪队列 |
消息队列系统 | 线程/服务之间的数据传输 |
广度优先搜索(BFS) | 图的遍历 |
打印任务排队 | 打印服务器依次处理任务 |
缓存机制(例如先进先出缓存) | 维护历史数据 |
银行/售票排队系统 | 模拟现实中等待排队的流程 |
栈与队列,是程序运行背后的“隐形骨架”,掌握它们,你就掌握了高效处理顺序、回退、排队等核心能力,是走向算法高手的第一步。