赞
踩
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include<stdbool.h>
- // 支持动态增长的栈
- typedef int STDataType;
- typedef struct Stack
- {
- STDataType* _a;
- int _top; // 栈顶
- int _capacity; // 容量
- }Stack;
- // 初始化栈
- void StackInit(Stack* ps);
- // 入栈
- void StackPush(Stack* ps, STDataType data);
- // 出栈
- void StackPop(Stack* ps);
- // 获取栈顶元素
- STDataType StackTop(Stack* ps);
- // 获取栈中有效元psd素个数
- int StackSize(Stack* ps);
- // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
- bool StackEmpty(Stack* ps);
- // 销毁栈
- void StackDestroy(Stack* ps);
- //栈打印
- void StackPrint(Stack ps);
- #include"stack.h"
-
- // 初始化栈
- void StackInit(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- ps->_a = NULL; // 初始化栈指针为NULL
- ps->_capacity = 0; // 初始化栈容量为0
- ps->_top = -1; // 初始化栈顶元素下标为-1
- }
-
- // 入栈操作
- void StackPush(Stack* ps, STDataType data)
- {
- assert(ps); // 断言栈指针不为空
- // 判断栈是否已满,如果已满,则扩容
- if (ps->_capacity == (ps->_top+1))
- {
- int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2; // 如果栈容量为0,则新容量为4,否则新容量为原容量的2倍
- STDataType* temp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity); // 重新分配内存空间
- if (temp == NULL) // 如果分配失败,则输出错误信息
- {
- perror("realloc fail");
- return NULL;
- }
- ps->_a = temp; // 更新栈指针
- ps->_capacity = newcapacity; // 更新栈容量
- }
- ps->_top++; // 栈顶元素下标加1
- ps->_a[ps->_top] = data; // 将新元素入栈
- }
-
- // 出栈操作
- void StackPop(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- assert(ps->_top > -1); // 断言栈非空
- ps->_top -= 1; // 栈顶元素下标减1,即出栈
- }
-
- // 获取栈顶元素
- STDataType StackTop(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- assert(ps->_top > -1); // 断言栈非空
- //assert(ps->_top > 0); // 错误的断言,因为栈顶元素下标可能为0
- return ps->_a[ps->_top]; // 返回栈顶元素
- }
-
- // 获取栈的大小
- int StackSize(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- return ps->_top+1; // 返回栈的大小,即栈顶元素下标加1
- }
-
- // 判断栈是否为空
- bool StackEmpty(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- return ps->_top == -1; // 如果栈顶元素下标为-1,则栈为空
- }
-
- // 销毁栈
- void StackDestroy(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- free(ps->_a); // 释放栈指针指向的内存空间
- ps->_a = NULL; // 将栈指针置为NULL
- ps->_capacity = 0; // 将栈容量置为0
- ps->_top = -1; // 将栈顶元素下标置为-1
- }
-
- // 打印栈的元素
- void StackPrint(Stack* ps)
- {
- assert(ps); // 断言栈指针不为空
- if (ps->_top == -1) // 如果栈为空,则输出NULL
- {
- printf("NULL\n");
- }
- for (int i = 0; i <= ps->_top; i++) // 遍历栈的元素,并输出
- {
- printf("%d ", ps->_a[i]);
- }
- }
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头。
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include<stdbool.h>
- // 链式结构:表示队列
-
- typedef int QDataType;
- typedef struct QListNode
- {
- struct QListNode* _next;
- QDataType _data;
- }QNode;
-
- // 队列的结构
-
- typedef struct Queue
- {
- QNode* _front;
- QNode* _rear;
- int size;
- }Queue;
-
- void QueuePrint(Queue* q);
- // 初始化队列
- void QueueInit(Queue* q);
- // 队尾入队列
- void QueuePush(Queue* q, QDataType data);
- // 队头出队列
- void QueuePop(Queue* q);
- // 获取队列头部元素
- QDataType QueueFront(Queue* q);
- // 获取队列队尾元素
- QDataType QueueBack(Queue* q);
- // 获取队列中有效元素个数
- int QueueSize(Queue* q);
- // 检测队列是否为空,如果为空返回非零结果,如果非空返回0
- bool QueueEmpty(Queue* q);
- // 销毁队列
- void QueueDestroy(Queue* q);
- #include"queue.h"
-
- // 初始化队列
- void QueueInit(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- q->_front = q->_rear = NULL; // 初始化队列的头指针和尾指针为NULL
- q->size = 0; // 初始化队列的大小为0
- }
-
- // 打印队列的元素
- void QueuePrint(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- QNode* cur = q->_front; // 定义一个指针指向队列的头节点
- while (cur) // 遍历队列的元素,并输出
- {
- printf("%d ", cur->_data);
- cur = cur->_next;
- }
- }
-
- // 销毁队列
- void QueueDestroy(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- QNode* cur = q->_front; // 定义一个指针指向队列的头节点
- while (cur) // 释放队列的所有节点
- {
- QNode* next = cur->_next;
- free(cur);
- cur = next;
- }
- q->_front = q->_rear = NULL; // 将队列的头指针和尾指针置为NULL
- q->size = 0; // 将队列的大小置为0
- }
-
- // 入队操作
- void QueuePush(Queue* q, QDataType data)
- {
- assert(q); // 断言队列指针不为空
- QNode* newnode = (QNode*)malloc(sizeof(QNode)); // 分配新节点的内存空间
- if (newnode == NULL) // 如果分配失败,则输出错误信息
- {
- perror("malloc fail");
- return ;
- }
- newnode->_data = data; // 将数据存入新节点
- newnode->_next = NULL; // 将新节点的指针域置为NULL
- if (q->_front == NULL) // 如果队列为空,则新节点即为队列的头指针和尾指针
- {
- q->_rear = q->_front = newnode;
- }
- else // 如果队列不为空,则将新节点插入到队列的尾部
- {
- q->_rear->_next = newnode;
- q->_rear = q->_rear->_next;
- }
- q->size += 1; // 队列的大小加1
- }
-
- // 出队操作
- void QueuePop(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- assert(q->_front); // 断言队列非空
- QNode* del = q->_front; // 定义一个指针指向队列的头节点
- q->_front = q->_front->_next; // 将头指针指向下一个节点
- free(del); // 释放原头节点的内存空间
- del = NULL; // 将指针置为NULL
- if (q->_front == NULL) // 如果队列为空,则将尾指针也置为NULL
- q->_rear =q->_front;
- q->size -= 1; // 队列的大小减1
- }
-
- // 获取队头元素
- QDataType QueueFront(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- assert(q->_front); // 断言队列非空
- return q->_front->_data; // 返回队列的头节点数据
- }
-
- // 获取队尾元素
- QDataType QueueBack(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- assert(q->_rear); // 断言队列非空
- return q->_rear->_data; // 返回队列的尾节点数据
- }
-
- // 获取队列的大小
- int QueueSize(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- return q->size; // 返回队列的大小
- }
-
- // 判断队列是否为空
- bool QueueEmpty(Queue* q)
- {
- assert(q); // 断言队列指针不为空
- return q->_front == NULL; // 如果队列的头指针为NULL,则队列为空
- }
另外扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。
关于栈与队列的的知识就先到此为止!!! 喜欢博主博客的可以 点赞+关注 我们下期见~~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。