数据结构——栈(十六)

栈是一种遵循**后进先出(LIFO)原则的线性数据结构,只允许在一端(栈顶)**进行插入(入栈)和删除(出栈)操作。本篇采用尾进尾出。

一、建立栈

结构体

struct Node

{

int a;

struct Node* pNext;

struct Node* pPre;

};

  • a 是节点的数据域,用于存储实际数据。
  • pNext 是指向下一个节点的指针,若为链表末尾则指向 NULL
  • pPre 是指向前一个节点的指针,若为链表头部则指向 NULL
创建空头

struct Node* Stack()//创建空头

{

//申请节点

struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));

if (NULL == pTemp)

return pTemp;

//成员赋值

pTemp->a = -1;

pTemp->pNext = pTemp;

pTemp->pPre = pTemp;

return pTemp;

}

  • 数据域a被初始化为-1,通常用于标记头节点或无效值。
  • pNextpPre指针均指向自身,形成循环结构。
  • 函数返回初始化后的头节点指针

二、进/出栈

1、尾进栈
代码:

void Push(struct Node* pStack, int a)//尾进栈

{

//参数合法性检测

if (NULL == pStack)

return;

//申请节点

struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));

if (NULL == pTemp)

return;

//成员赋值

pTemp->a = a;

pTemp->pNext = NULL;

pTemp->pPre = NULL;

//节点链接

pTemp->pPre = pStack->pPre;

pTemp->pNext = pStack;

pStack->pPre->pNext = pTemp;

pStack->pPre = pTemp;

}

实现了一个双向链表的尾进栈操作(Push)。头节点(pStack)的pNext指向第一个实际数据节点,pPre指向最后一个实际数据节点。

步骤:

参数合法性检测

检查传入的链表头节点指针是否为空。如果为空,直接返回,避免后续操作引发错误。

申请新节点

动态申请一个新节点内存空间。如果内存分配失败(返回NULL),直接返回,避免后续操作引发错误。

成员赋值

为新节点的数据成员a赋值为传入的参数a。初始化新节点的pNext和pPre指针为NULL。

节点链接

  1. 将新节点的pPre指向链表原来的最后一个节点(pStack->pPre)。

  2. 将新节点的pNext指向头节点(pStack)。

  3. 将原来的最后一个节点的pNext指向新节点(pStack->pPre->pNext = pTemp)。

  4. 更新头节点的pPre指向新节点(pStack->pPre = pTemp)。

2、判断是否为空栈
代码:

bool IsEmpty(struct Node* pStack)//判断是否为空栈

{

if (pStack->pNext == pStack)

return true;

return false;

}

定义了一个函数 IsEmpty,用于判断栈是否为空。函数接收一个指向栈顶节点(struct Node*)的指针 pStack,通过检查其 pNext 指针是否指向自身来判断栈是否为空。

3、出栈
代码:

void Pop(struct Node* pStack)//出栈

{

if (IsEmpty(pStack))

return NULL;

//记录被删除节点

struct Node* pT = pStack->pPre;

pT->pPre->pNext = pStack;

pStack->pPre = pT->pPre;

free(pT);

}

步骤:
  1. 检查栈是否为空

    调用IsEmpty(pStack)函数判断栈是否为空。如果为空,直接返回NULL,避免对空栈执行出栈操作。

  2. 记录待删除节点

    栈顶元素是pStack->pPre(即栈顶指针的前驱节点)。将其保存到临时指针pT中,以便后续操作和释放内存。

  3. 调整链表指针

    pT的前驱节点(pT->pPre)与栈顶指针pStack连接起来,跳过待删除的节点pT

    • pT->pPre->pNext = pStack:将pT前驱节点的pNext指向pStack

    • pStack->pPre = pT->pPre:将pStackpPre指向pT的前驱节点。

  4. 释放内存

    调用free(pT)释放被删除节点的内存

三、释放

代码:

void FreeStack(struct Node** pStack)//释放链表

{

if (NULL == pStack)

return;

struct Node* pTemp = *pStack;

do

{

struct Node* pT = pTemp;

pTemp = pTemp->pNext;

free(pT);

} while (pTemp != *pStack);

*pStack = NULL;

}

步骤:
  1. 参数检查

    函数首先检查传入的 pStack 是否为 NULL。如果是,直接返回,避免对空指针解引用。

  2. 临时指针初始化
    pTemp 初始化为链表的头节点 *pStack,用于遍历链表。

  3. 循环释放节点

    使用 do-while 循环遍历链表,确保至少执行一次释放操作(即使链表只有一个节点)。

    • 在每次循环中,pT 保存当前节点的地址,pTemp 移动到下一个节点。

    • 调用 free(pT) 释放当前节点的内存。

    • 循环条件检查 pTemp 是否回到头节点 *pStack,确保循环链表的所有节点被释放。

  4. 头指针置空

    循环结束后,将 *pStack 设置为 NULL,避免悬挂指针问题。

相关推荐
延凡科技6 小时前
多场景落地复盘:端边云架构无人机智能巡检系统设计与实践
大数据·数据结构·人工智能·科技·架构·无人机·能源
皓月斯语12 小时前
B3842 [GESP202306 三级] 春游 题解
数据结构·c++·算法·题解
春日见12 小时前
算法与数据结构----哈希表
数据结构·人工智能·算法·机器学习·自动驾驶·哈希算法·散列表
萌动的小火苗13 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件
叩码以求索13 小时前
统计按位或能得到最大值的子集数目(一)
数据结构·算法
tachibana213 小时前
hot100 数组中的第K个最大元素(215)
java·数据结构·算法·leetcode
星恒随风13 小时前
C++ STL 栈详解:stack 的使用、经典题目与简单模拟实现
开发语言·数据结构·c++·笔记·学习
txzrxz13 小时前
单调队列讲解
数据结构·c++·算法·单调队列
Keven_1114 小时前
算法札记:树状数组的用途
数据结构·算法
cpp_250115 小时前
P1540 [NOIP 2010 提高组] 机器翻译
数据结构·c++·算法·队列·noip·洛谷题解