数据结构
文章目录
不透明指针
定义
不透明指针是指指向一个数据结构的指针,但该数据结构的内部细节对外部代码是不可见的。外部代码只能通过提供的接口函数来操作该数据结构,而无法直接访问其内部成员。
优点
- 封装性:隐藏数据结构的内部实现细节,防止外部代码直接修改数据结构,提高代码的安全性和稳定性。
- 模块化:将数据结构和操作函数分离,便于模块化设计和代码复用。
- 可扩展性:可以在不修改外部代码的情况下,修改数据结构的内部实现,提高代码的可扩展性。
应用场景
不透明指针广泛应用于各种需要封装和模块化的场景,包括但不限于:
- 库开发:在库中使用不透明指针,隐藏内部数据结构,只暴露必要的接口函数。
- 数据结构实现:在实现复杂数据结构时,使用不透明指针隐藏内部细节,提高代码的可维护性。
- 操作系统:在操作系统中使用不透明指针,隐藏内部数据结构,提高系统的安全性和稳定性。
不透明指针的实现
定义不透明指针类型
首先,定义一个不透明指针类型,通常使用 typedef
关键字。例如:
typedef struct _MyData MyData;
这里,MyData
是一个不透明指针类型,struct _MyData
的内部细节对外部代码是不可见的。
链表
知识点
链表由一系列的节点(Node)构成,每个节点包含数据和指向下一个节点的指针。链表的主要优点是插入和删除操作的时间复杂度为 O(1),但访问特定元素的时间复杂度为 O(n)。
节点(Node)
- 链表的基本单元是节点,每个节点包含两个部分:
- 数据域:存储数据。
- 指针域:指向下一个节点的指针。
由于我们不知道用户的数据是怎么存储的,所以我们可以,单独讲节点独立出来,仅仅保留指针域,该指针域将在用户的数据前四个字节。
头节点(Head)
链表的第一个节点称为头节点(Head)。头节点用于标识链表的起始位置。
尾节点(Tail)
链表的最后一个节点称为尾节点(Tail)。尾节点的指针域通常指向 NULL
,表示链表的结束。
单向链表
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义链表的别名
typedef void* LinkList;
// 节点结构体设计
typedef struct LinkNode {
// 维护指针域
struct LinkNode* next;
} LinkNode_t;
// 初始化链表
LinkList init_LinkList(void);
// 插入节点
void insert_LinkList(LinkList list, int pos, void* data);
// 遍历链表
void foreach_LinkList(LinkList list, void (*myprint)(void*));
// 销毁链表
void destroy_LinkList(LinkList list);
// 根据位置删除节点
void removeByPos_LinkList(LinkList list, int pos);
// 根据值删除节点
void removeByValue_LinkList(LinkList list, void* data, int (*myCompare)(void*, void*));
#include "list.h"
// 链表结构体设计
typedef struct {
LinkNode_t pHeader; // 头节点
int m_Size; // 链表大小
} LinkList_t;
/**
* @brief 初始化链表
*
* @return LinkList 返回初始化后的链表指针,如果内存分配失败则返回NULL
*/
LinkList init_LinkList(void) {
// 分配链表结构体内存
LinkList_t* mylist = malloc(sizeof(LinkList_t));
if (mylist == NULL) {
// 内存分配失败,返回NULL
return NULL;
}
// 初始化链表属性
mylist->m_Size = 0;
mylist->pHeader.next = NULL;
return mylist;
}
/**
* @brief 插入节点
*
* @param list 链表指针
* @param pos 插入位置
* @param data 要插入的数据指针
*/
void insert_LinkList(LinkList list, int pos, void* data) {
if (list == NULL || data == NULL) {
// 链表或数据为空,直接返回
return;
}
LinkList_t* mylist = (LinkList_t*)list;
if (pos < 0 || pos > mylist->m_Size) {
// 无效位置,默认插入到链表末尾
pos = mylist->m_Size;
}
// 取出用户数据的前四个空间
LinkNode_t* myNode = (LinkNode_t*)data;
// 找到待插入数据位置
LinkNode_t* pCurrent = &mylist->pHeader;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
// 更改指针指向
myNode->next = pCurrent->next;
pCurrent->next = myNode;
// 更新链表大小
mylist->m_Size++;
}
/**
* @brief 遍历链表
*
* @param list 链表指针
* @param myprint 打印函数指针
*/
void foreach_LinkList(LinkList list, void (*myprint)(void*)) {
if (list == NULL || myprint == NULL) {
// 链表或打印函数为空,直接返回
return;
}
LinkList_t* myList = (LinkList_t*)list;
LinkNode_t* pCurrent = myList->pHeader.next;
for (int i = 0; i < myList->m_Size; i++) {
// pCurrent就是用户数据首地址
myprint(pCurrent);
pCurrent = pCurrent->next;
}
}
/**
* @brief 销毁链表
*
* @param list 链表指针
*/
void destroy_LinkList(LinkList list) {
if (list == NULL) {
// 链表为空,直接返回
return;
}
LinkList_t* myList = (LinkList_t*)list;
LinkNode_t* pCurrent = myList->pHeader.next;
while (pCurrent != NULL) {
LinkNode_t* pNext = pCurrent->next;
free(pCurrent);
pCurrent = pNext;
}
// 释放链表结构体内存
free(myList);
}
/**
* @brief 根据位置删除节点
*
* @param list 链表指针
* @param pos 删除位置
*/
void removeByPos_LinkList(LinkList list, int pos) {
if (list == NULL) {
// 链表为空,直接返回
return;
}
LinkList_t* myList = (LinkList_t*)list;
if (pos < 0 || pos >= myList->m_Size) {
// 无效位置,直接返回
return;
}
// 找到待删除节点的前驱节点
LinkNode_t* pCurrent = &myList->pHeader;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
// 获取待删除节点
LinkNode_t* pDel = pCurrent->next;
// 建立节点之间的关系
pCurrent->next = pDel->next;
// 释放待删除节点的内存
// free(pDel); pDel是用户的,我们没资格free
// 更新链表大小
myList->m_Size--;
}
/**
* @brief 根据值删除节点
*
* @param list 链表指针
* @param data 要删除的数据指针
* @param myCompare 比较函数指针
*/
void removeByValue_LinkList(LinkList list, void* data, int (*myCompare)(void*, void*)) {
if (list == NULL || data == NULL || myCompare == NULL) {
// 链表、数据或比较函数为空,直接返回
return;
}
LinkList_t* myList = (LinkList_t*)list;
// 找到待删除节点的前驱节点
LinkNode_t* pCurrent = &myList->pHeader;
for (int i = 0; i < myList->m_Size; i++) {
if (myCompare(pCurrent->next, data)) {
// 找到匹配的节点
LinkNode_t* pDel = pCurrent->next;
// 建立节点之间的关系
pCurrent->next = pDel->next;
// 释放待删除节点的内存
// free(pDel);
// 更新链表大小
myList->m_Size--;
return;
}
pCurrent = pCurrent->next;
}
}
双链表
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义链表的别名
typedef void* LinkList;
// 节点结构体设计
typedef struct LinkNode {
struct LinkNode* prev; // 指向前一个节点的指针
struct LinkNode* next; // 指向下一个节点的指针
} LinkNode_t;
// 链表结构体设计
typedef struct {
LinkNode_t pHeader; // 头节点
int m_Size; // 链表大小
} LinkList_t;
// 初始化链表
LinkList init_LinkList(void);
// 插入节点
void insert_LinkList(LinkList list, int pos, void* data);
// 遍历链表
void foreach_LinkList(LinkList list, void (*myprint)(void*));
// 销毁链表
void destroy_LinkList(LinkList list);
// 根据位置删除节点
void removeByPos_LinkList(LinkList list, int pos);
// 根据值删除节点
void removeByValue_LinkList(LinkList list, void* data, int (*myCompare)(void*, void*));
#include "list.h"
/**
* @brief 初始化链表
*
* @return LinkList 返回初始化后的链表指针,如果内存分配失败则返回NULL
*/
LinkList init_LinkList(void) {
LinkList_t* mylist = malloc(sizeof(LinkList_t));
if (mylist == NULL) {
return NULL;
}
mylist->m_Size = 0;
mylist->pHeader.prev = &mylist->pHeader; // 头节点的 prev 指针指向自身
mylist->pHeader.next = &mylist->pHeader; // 头节点的 next 指针指向自身
return mylist;
}
/**
* @brief 插入节点
*
* @param list 链表指针
* @param pos 插入位置
* @param data 要插入的数据指针
*/
void insert_LinkList(LinkList list, int pos, void* data) {
if (list == NULL || data == NULL) {
return;
}
LinkList_t* mylist = (LinkList_t*)list;
if (pos < 0 || pos > mylist->m_Size) {
pos = mylist->m_Size;
}
LinkNode_t* myNode = (LinkNode_t*)data;
LinkNode_t* pCurrent = &mylist->pHeader;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
myNode->next = pCurrent->next;
myNode->prev = pCurrent;
pCurrent->next->prev = myNode; // 更新后继节点的前驱指针
pCurrent->next = myNode;
mylist->m_Size++;
}
/**
* @brief 遍历链表
*
* @param list 链表指针
* @param myprint 打印函数指针
*/
void foreach_LinkList(LinkList list, void (*myprint)(void*)) {
if (list == NULL || myprint == NULL) {
return;
}
LinkList_t* myList = (LinkList_t*)list;
LinkNode_t* pCurrent = myList->pHeader.next;
for (int i = 0; i < myList->m_Size; i++) {
myprint(pCurrent);
pCurrent = pCurrent->next;
}
}
/**
* @brief 销毁链表
*
* @param list 链表指针
*/
void destroy_LinkList(LinkList list) {
if (list == NULL) {
return;
}
LinkList_t* myList = (LinkList_t*)list;
LinkNode_t* pCurrent = myList->pHeader.next;
while (pCurrent != &myList->pHeader) { // 遍历到头节点为止
LinkNode_t* pNext = pCurrent->next;
free(pCurrent);
pCurrent = pNext;
}
free(myList);
}
/**
* @brief 根据位置删除节点
*
* @param list 链表指针
* @param pos 删除位置
*/
void removeByPos_LinkList(LinkList list, int pos) {
if (list == NULL) {
return;
}
LinkList_t* myList = (LinkList_t*)list;
if (pos < 0 || pos >= myList->m_Size) {
return;
}
LinkNode_t* pCurrent = &myList->pHeader;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
LinkNode_t* pDel = pCurrent->next;
pCurrent->next = pDel->next;
pDel->next->prev = pCurrent; // 更新后继节点的前驱指针
myList->m_Size--;
}
/**
* @brief 根据值删除节点
*
* @param list 链表指针
* @param data 要删除的数据指针
* @param myCompare 比较函数指针
*/
void removeByValue_LinkList(LinkList list, void* data, int (*myCompare)(void*, void*)) {
if (list == NULL || data == NULL || myCompare == NULL) {
return;
}
LinkList_t* myList = (LinkList_t*)list;
LinkNode_t* pCurrent = &myList->pHeader;
for (int i = 0; i < myList->m_Size; i++) {
if (myCompare(pCurrent->next, data)) {
LinkNode_t* pDel = pCurrent->next;
pCurrent->next = pDel->next;
pDel->next->prev = pCurrent; // 更新后继节点的前驱指针
myList->m_Size--;
return;
}
pCurrent = pCurrent->next;
}
}
动态数组
动态数组(Dynamic Array)是一种可以根据需要动态调整大小的数组。与静态数组不同,动态数组的大小在运行时可以改变,从而避免了静态数组固定大小的限制。动态数组通常通过在堆内存中分配空间来实现,可以使用指针和动态内存分配函数(如 malloc
、realloc
和 free
)来管理内存。
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
// 定义动态数组的别名
typedef void* DynamicArray;
// 初始化数组 返回值数组指针
DynamicArray init_dynamicArray(int capacity);
// 插入数组
void insert_dynamicArray(DynamicArray arr, void* data, int pos);
// 遍历
void foreach_dynamicArray(DynamicArray arr, void (*myPrint)(void*));
// 根据位置删除
void removeByPos_dynamicArray(DynamicArray arr, int pos);
// 根据值删除
void removeByValue_dynamicArray(DynamicArray arr, void* data, int (*myCompare)(void*, void*));
// 销毁数组
void destroy_dynamicArray(DynamicArray arr);
#endif // DYNAMICARRAY_H
#include "dynamicArray.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 动态数组结构体
typedef struct {
// 真实在堆区开辟的数组的指针
void** pAddr;
// 数组容量
int m_Capacity;
// 数组大小
int m_Size;
} dynamicArray_t;
/**
* @brief 初始化数组
*
* @param capacity 数组的初始容量
* @return DynamicArray 返回初始化后的数组指针,如果内存分配失败则返回NULL
*/
DynamicArray init_dynamicArray(int capacity) {
if (capacity <= 0) {
return NULL;
}
// 给数组分配内存
dynamicArray_t* arr = malloc(sizeof(dynamicArray_t));
if (arr == NULL) {
return NULL;
}
// 给属性初始化
arr->m_Capacity = capacity;
arr->pAddr = malloc(sizeof(void*) * capacity);
if (arr->pAddr == NULL) {
free(arr);
return NULL;
}
arr->m_Size = 0;
return arr;
}
/**
* @brief 插入数组
*
* @param arr 数组指针
* @param data 要插入的数据指针
* @param pos 插入位置
*/
void insert_dynamicArray(DynamicArray arr, void* data, int pos) {
if (arr == NULL || data == NULL) {
return;
}
dynamicArray_t* myArr = (dynamicArray_t*)arr;
if (pos < 0 || pos > myArr->m_Size) {
// 尾插
pos = myArr->m_Size;
}
// 判断数组是否满了
if (myArr->m_Size == myArr->m_Capacity) {
int newCapacity = myArr->m_Capacity * 2;
// 开辟新空间
void** newSpace = malloc(sizeof(void*) * newCapacity);
if (newSpace == NULL) {
return;
}
// 将原空间内容拷贝到新空间下
memcpy(newSpace, myArr->pAddr, myArr->m_Size * sizeof(void*));
// 释放原空间
free(myArr->pAddr);
// 更改指针指向
myArr->pAddr = newSpace;
// 更新容量
myArr->m_Capacity = newCapacity;
}
// 移动元素
for (int i = myArr->m_Size - 1; i >= pos; i--) {
myArr->pAddr[i + 1] = myArr->pAddr[i];
}
// 插入数据
myArr->pAddr[pos] = data;
myArr->m_Size++;
}
/**
* @brief 遍历数组
*
* @param arr 数组指针
* @param myPrint 打印函数指针
*/
void foreach_dynamicArray(DynamicArray arr, void (*myPrint)(void*)) {
if (arr == NULL || myPrint == NULL) {
return;
}
dynamicArray_t* myArr = (dynamicArray_t*)arr;
for (int i = 0; i < myArr->m_Size; i++) {
myPrint(myArr->pAddr[i]);
}
}
/**
* @brief 根据位置删除数组元素
*
* @param arr 数组指针
* @param pos 删除位置
*/
void removeByPos_dynamicArray(DynamicArray arr, int pos) {
if (arr == NULL) {
return;
}
dynamicArray_t* myArr = (dynamicArray_t*)arr;
if (pos < 0 || pos >= myArr->m_Size) {
return;
}
// 删除指定位置,从前往后移动
for (int i = pos; i < myArr->m_Size - 1; i++) {
myArr->pAddr[i] = myArr->pAddr[i + 1];
}
myArr->m_Size--;
}
/**
* @brief 根据值删除数组元素
*
* @param arr 数组指针
* @param data 要删除的数据指针
* @param myCompare 比较函数指针
*/
void removeByValue_dynamicArray(DynamicArray arr, void* data, int (*myCompare)(void*, void*)) {
if (arr == NULL || data == NULL || myCompare == NULL) {
return;
}
dynamicArray_t* myArr = (dynamicArray_t*)arr;
for (int i = 0; i < myArr->m_Size; i++) {
// 利用回调函数,让用户告诉我们如何对比数据
if (myCompare(myArr->pAddr[i], data)) {
removeByPos_dynamicArray(arr, i);
break;
}
}
}
/**
* @brief 销毁数组
*
* @param arr 数组指针
*/
void destroy_dynamicArray(DynamicArray arr) {
if (arr == NULL) {
return;
}
dynamicArray_t* myArr = (dynamicArray_t*)arr;
// 内部维护在堆区的数组指针先释放
if (myArr->pAddr != NULL) {
free(myArr->pAddr);
myArr->pAddr = NULL;
}
free(myArr);
}
队列
队列是一种线性数据结构,元素从队列的尾部插入,从队列的头部删除。队列遵循先进先出的原则,即最先插入的元素最先被删除。
队列的链式存储
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义不透明指针类型
typedef struct LinkQueue* LinkQueuePtr;
// 定义链表节点结构(内部结构,不对外暴露)
typedef struct LinkNode {
struct LinkNode* next; // 指向下一个节点的指针
} LinkNode_t;
// 初始化队列
LinkQueuePtr init_LinkQueue(void);
// 判断队列是否为空
int isEmpty_LinkQueue(LinkQueuePtr queue);
// 入队操作
void push_LinkQueue(LinkQueuePtr queue, void* data);
// 出队操作
void* pop_LinkQueue(LinkQueuePtr queue);
// 返回队头元素
void* front_LinkQueue(LinkQueuePtr queue);
// 返回队尾元素
void* back_LinkQueue(LinkQueuePtr queue);
// 返回队列大小
int size_LinkQueue(LinkQueuePtr queue);
// 销毁队列
void destroy_LinkQueue(LinkQueuePtr queue);
#include "LinkQueue.h"
// 定义队列结构(内部结构,不对外暴露)
typedef struct LinkQueue {
LinkNode_t header; // 头节点
int m_Size; // 队列大小
LinkNode_t* pTail; // 尾节点指针
} LinkQueue_t;
// 初始化队列
LinkQueuePtr init_LinkQueue(void) {
LinkQueue_t* myQueue = (LinkQueue_t*)malloc(sizeof(LinkQueue_t));
if (myQueue == NULL) {
printf("内存分配失败\n");
return NULL;
}
myQueue->header.next = NULL;
myQueue->m_Size = 0;
myQueue->pTail = &myQueue->header; // 初始时尾节点指向头节点
return myQueue;
}
// 判断队列是否为空
int isEmpty_LinkQueue(LinkQueuePtr queue) {
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
if (myQueue == NULL) {
return -1; // 返回-1表示错误
}
return myQueue->m_Size == 0;
}
// 入队操作
void push_LinkQueue(LinkQueuePtr queue, void* data) {
if (queue == NULL || data == NULL) {
return;
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
LinkNode_t* newNode = (LinkNode_t*)data;
// 新节点的next指针置为NULL
newNode->next = NULL;
// 如果队列为空,头节点的next指向新节点
if (isEmpty_LinkQueue(queue)) {
myQueue->header.next = newNode;
}
else {
// 否则,尾节点的next指向新节点
myQueue->pTail->next = newNode;
}
// 更新尾节点
myQueue->pTail = newNode;
myQueue->m_Size++;
}
// 出队操作
void* pop_LinkQueue(LinkQueuePtr queue) {
if (queue == NULL) {
return NULL;
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
// 如果队列为空,返回NULL
if (isEmpty_LinkQueue(queue)) {
return NULL;
}
// 获取第一个有数据的节点
LinkNode_t* ptr = myQueue->header.next;
// 更新头节点的next指针
myQueue->header.next = ptr->next;
// 如果队列中只有一个元素,更新尾节点
if (myQueue->m_Size == 1) {
myQueue->pTail = &myQueue->header;
}
myQueue->m_Size--;
return ptr;
}
// 返回队头元素
void* front_LinkQueue(LinkQueuePtr queue) {
if (queue == NULL) {
return NULL;
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
// 如果队列为空,返回NULL
if (isEmpty_LinkQueue(queue)) {
return NULL;
}
return myQueue->header.next;
}
// 返回队尾元素
void* back_LinkQueue(LinkQueuePtr queue) {
if (queue == NULL) {
return NULL;
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
// 如果队列为空,返回NULL
if (isEmpty_LinkQueue(queue)) {
return NULL;
}
return myQueue->pTail;
}
// 返回队列大小
int size_LinkQueue(LinkQueuePtr queue) {
if (queue == NULL) {
return -1; // 返回-1表示错误
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
return myQueue->m_Size;
}
// 销毁队列
void destroy_LinkQueue(LinkQueuePtr queue) {
if (queue == NULL) {
return;
}
LinkQueue_t* myQueue = (LinkQueue_t*)queue;
// 释放队列中的所有节点
while (!isEmpty_LinkQueue(queue)) {
LinkNode_t* ptr = pop_LinkQueue(queue);
free(ptr);
}
// 释放队列本身的内存
free(myQueue);
queue = NULL;
}
队列的顺序存储
#pragma once
// 定义队列的别名
typedef void* SeqQueue;
// 初始化队列
SeqQueue init_SeqQueue(void);
// 入队
void enqueue_SeqQueue(SeqQueue queue, void* data);
// 出队
void dequeue_SeqQueue(SeqQueue queue);
// 返回队首元素
void* front_SeqQueue(SeqQueue queue);
// 返回队列大小
int size_SeqQueue(SeqQueue queue);
// 判断队列是否为空
int isEmpty_SeqQueue(SeqQueue queue);
// 销毁队列
void destroy_SeqQueue(SeqQueue queue);
#include "seqQueue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define QUEUE_MAX_SIZE 1024 // 定义队列的最大容量
// 队列结构体
typedef struct SQueue {
// 队列中数组
void* data[QUEUE_MAX_SIZE];
int m_Front; // 队首指针
int m_Rear; // 队尾指针
int m_Size; // 队列大小
} SeqQueue_t;
/**
* @brief 初始化队列
*
* @return SeqQueue 返回初始化后的队列指针,如果内存分配失败则返回NULL
*/
SeqQueue init_SeqQueue(void) {
// 分配队列结构体内存
SeqQueue_t* myQueue = malloc(sizeof(SeqQueue_t));
if (myQueue == NULL) {
// 内存分配失败,返回NULL
return NULL;
}
// 初始化队列属性
myQueue->m_Front = 0;
myQueue->m_Rear = 0;
myQueue->m_Size = 0;
memset(myQueue->data, 0, sizeof(void*) * QUEUE_MAX_SIZE);
return myQueue;
}
/**
* @brief 入队
*
* @param queue 队列指针
* @param data 要入队的数据指针
*/
void enqueue_SeqQueue(SeqQueue queue, void* data) {
SeqQueue_t* myQueue = (SeqQueue_t*)queue;
// 判断队列是否满了
if (myQueue->m_Size == QUEUE_MAX_SIZE) {
// 队列满,无法入队
return;
}
// 数据进行尾插
myQueue->data[myQueue->m_Rear] = data;
myQueue->m_Rear = (myQueue->m_Rear + 1) % QUEUE_MAX_SIZE;
myQueue->m_Size++;
}
/**
* @brief 出队
*
* @param queue 队列指针
*/
void dequeue_SeqQueue(SeqQueue queue) {
SeqQueue_t* myQueue = (SeqQueue_t*)queue;
if (myQueue->m_Size == 0) {
// 队列空,无法出队
return;
}
// 出队操作
myQueue->data[myQueue->m_Front] = NULL;
myQueue->m_Front = (myQueue->m_Front + 1) % QUEUE_MAX_SIZE;
myQueue->m_Size--;
}
/**
* @brief 返回队首元素
*
* @param queue 队列指针
* @return void* 返回队首元素的指针,如果队列为空则返回NULL
*/
void* front_SeqQueue(SeqQueue queue) {
SeqQueue_t* myQueue = (SeqQueue_t*)queue;
if (myQueue->m_Size == 0) {
// 队列空,返回NULL
return NULL;
}
// 返回队首元素
return myQueue->data[myQueue->m_Front];
}
/**
* @brief 返回队列大小
*
* @param queue 队列指针
* @return int 返回队列的大小
*/
int size_SeqQueue(SeqQueue queue) {
SeqQueue_t* myQueue = (SeqQueue_t*)queue;
return myQueue->m_Size;
}
/**
* @brief 判断队列是否为空
*
* @param queue 队列指针
* @return int 返回1表示队列为空,返回0表示队列不为空,返回-1表示队列指针为空
*/
int isEmpty_SeqQueue(SeqQueue queue) {
SeqQueue_t* myQueue = (SeqQueue_t*)queue;
if (myQueue == NULL) {
// 队列为空,返回-1
return -1;
}
if (myQueue->m_Size == 0) {
// 队列为空,返回1
return 1;
}
// 队列不为空,返回0
return 0;
}
/**
* @brief 销毁队列
*
* @param queue 队列指针
*/
void destroy_SeqQueue(SeqQueue queue) {
if (queue == NULL) {
// 队列为空,直接返回
return;
}
// 释放队列结构体内存
free(queue);
queue = NULL;
}
栈
栈的顺序存储
#pragma once
// 定义栈的别名
typedef void* SeqStack;
// 初始化栈
SeqStack init_SeqStack(void);
// 入栈
void push_SeqStack(SeqStack stack, void* data);
// 出栈
void pop_SeqStack(SeqStack stack);
// 返回栈顶元素
void* top_SeqStack(SeqStack stack);
// 返回栈大小
int size_SeqStack(SeqStack stack);
// 判断栈是否为空
int isEmpty_SeqStack(SeqStack stack);
// 销毁栈
void destroy_SeqStack(SeqStack stack);
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STACK_MAX_SIZE 1024 // 定义栈的最大容量
// 栈结构体
typedef struct SStack {
// 栈中数组
void* data[STACK_MAX_SIZE];
int m_Size; // 栈的大小
} SeqStack_t;
/**
* @brief 初始化栈
*
* @return SeqStack 返回初始化后的栈指针,如果内存分配失败则返回NULL
*/
SeqStack init_SeqStack(void) {
// 分配栈结构体内存
SeqStack_t* myStack = malloc(sizeof(SeqStack_t));
if (myStack == NULL) {
// 内存分配失败,返回NULL
return NULL;
}
// 初始化栈属性
myStack->m_Size = 0;
memset(myStack->data, 0, sizeof(void*) * STACK_MAX_SIZE);
return myStack;
}
/**
* @brief 入栈
*
* @param stack 栈指针
* @param data 要入栈的数据指针
*/
void push_SeqStack(SeqStack stack, void* data) {
SeqStack_t* myStack = (SeqStack_t*)stack;
// 判断栈是否满了
if (myStack->m_Size == STACK_MAX_SIZE) {
// 栈满,无法入栈
return;
}
// 数据进行尾插
myStack->data[myStack->m_Size++] = data;
}
/**
* @brief 出栈
*
* @param stack 栈指针
*/
void pop_SeqStack(SeqStack stack) {
SeqStack_t* myStack = (SeqStack_t*)stack;
if (myStack->m_Size == 0) {
// 栈空,无法出栈
return;
}
// 出栈操作
myStack->data[--myStack->m_Size] = NULL;
}
/**
* @brief 返回栈顶元素
*
* @param stack 栈指针
* @return void* 返回栈顶元素的指针,如果栈为空则返回NULL
*/
void* top_SeqStack(SeqStack stack) {
SeqStack_t* myStack = (SeqStack_t*)stack;
if (myStack->m_Size == 0) {
// 栈空,返回NULL
return NULL;
}
// 返回栈顶元素
return myStack->data[myStack->m_Size - 1];
}
/**
* @brief 返回栈大小
*
* @param stack 栈指针
* @return int 返回栈的大小
*/
int size_SeqStack(SeqStack stack) {
SeqStack_t* myStack = (SeqStack_t*)stack;
return myStack->m_Size;
}
/**
* @brief 判断栈是否为空
*
* @param stack 栈指针
* @return int 返回1表示栈为空,返回0表示栈不为空,返回-1表示栈指针为空
*/
int isEmpty_SeqStack(SeqStack stack) {
SeqStack_t* myStack = (SeqStack_t*)stack;
if (myStack == NULL) {
// 栈为空,返回-1
return -1;
}
if (myStack->m_Size == 0) {
// 栈为空,返回1
return 1;
}
// 栈不为空,返回0
return 0;
}
/**
* @brief 销毁栈
*
* @param stack 栈指针
*/
void destroy_SeqStack(SeqStack stack) {
if (stack == NULL) {
// 栈为空,直接返回
return;
}
// 释放栈结构体内存
free(stack);
stack = NULL;
}
栈的链式存储
#pragma once
// 链表节点结构体
typedef struct linkNode {
// 维护指针域
struct linkNode* next;
} LinkNode_t;
// 定义栈的别名
typedef void* LinkStack;
// 初始化栈
LinkStack init_LinkStack(void);
// 入栈
void push_LinkStack(LinkStack stack, void* data);
// 出栈
void pop_LinkStack(LinkStack stack);
// 返回栈顶元素
void* top_LinkStack(LinkStack stack);
// 判断栈是否为空
int isEmpty_LinkStack(LinkStack stack);
// 销毁栈
void destroy_LinkStack(LinkStack stack);
#include "liststack.h"
#include <stdio.h>
#include <stdlib.h>
// 栈结构体
typedef struct {
LinkNode_t pHeader; // 头节点
int m_Size; // 栈的大小
} LinkStack_t;
/**
* @brief 初始化栈
*
* @return LinkStack 返回初始化后的栈指针,如果内存分配失败则返回NULL
*/
LinkStack init_LinkStack(void) {
// 分配栈结构体内存
LinkStack_t* myStack = malloc(sizeof(LinkStack_t));
if (myStack == NULL) {
// 内存分配失败,返回NULL
return NULL;
}
// 初始化栈属性
myStack->pHeader.next = NULL;
myStack->m_Size = 0;
return myStack;
}
/**
* @brief 入栈
*
* @param stack 栈指针
* @param data 要入栈的数据指针
*/
void push_LinkStack(LinkStack stack, void* data) {
if (stack == NULL || data == NULL) {
// 栈或数据为空,直接返回
return;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
// 取出用户的前四个字节
LinkNode_t* newNode = (LinkNode_t*)data;
// 建立节点之间的关系 头插入
newNode->next = myStack->pHeader.next;
myStack->pHeader.next = newNode;
// 更新栈的大小
myStack->m_Size++;
}
/**
* @brief 出栈
*
* @param stack 栈指针
*/
void pop_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,直接返回
return;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
// 本质头删
if (myStack->m_Size == 0) {
// 栈为空,无法出栈
return;
}
// 创建指向第一个节点的指针
LinkNode_t* pFirst = myStack->pHeader.next;
// 更新节点指向
myStack->pHeader.next = pFirst->next;
// 更新栈的大小
myStack->m_Size--;
}
/**
* @brief 返回栈顶元素
*
* @param stack 栈指针
* @return void* 返回栈顶元素的指针,如果栈为空则返回NULL
*/
void* top_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,返回NULL
return NULL;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
// 本质头删
if (myStack->m_Size == 0) {
// 栈为空,返回NULL
return NULL;
}
// 返回栈顶元素
return myStack->pHeader.next;
}
/**
* @brief 判断栈是否为空
*
* @param stack 栈指针
* @return int 返回1表示栈为空,返回0表示栈不为空,返回-1表示栈指针为空
*/
int isEmpty_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,返回-1
return -1;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
if (myStack->m_Size == 0) {
// 栈为空,返回1
return 1;
}
// 栈不为空,返回0
return 0;
}
/**
* @brief 销毁栈
*
* @param stack 栈指针
*/
void destroy_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,直接返回
return;
}
// 释放栈结构体内存
free(stack);
stack = NULL;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
// 本质头删
if (myStack->m_Size == 0) {
// 栈为空,无法出栈
return;
}
// 创建指向第一个节点的指针
LinkNode_t* pFirst = myStack->pHeader.next;
// 更新节点指向
myStack->pHeader.next = pFirst->next;
// 更新栈的大小
myStack->m_Size--;
}
/**
* @brief 返回栈顶元素
*
* @param stack 栈指针
* @return void* 返回栈顶元素的指针,如果栈为空则返回NULL
*/
void* top_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,返回NULL
return NULL;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
// 本质头删
if (myStack->m_Size == 0) {
// 栈为空,返回NULL
return NULL;
}
// 返回栈顶元素
return myStack->pHeader.next;
}
/**
* @brief 判断栈是否为空
*
* @param stack 栈指针
* @return int 返回1表示栈为空,返回0表示栈不为空,返回-1表示栈指针为空
*/
int isEmpty_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,返回-1
return -1;
}
LinkStack_t* myStack = (LinkStack_t*)stack;
if (myStack->m_Size == 0) {
// 栈为空,返回1
return 1;
}
// 栈不为空,返回0
return 0;
}
/**
* @brief 销毁栈
*
* @param stack 栈指针
*/
void destroy_LinkStack(LinkStack stack) {
if (stack == NULL) {
// 栈为空,直接返回
return;
}
// 释放栈结构体内存
free(stack);
stack = NULL;
}