【C语言】基本数据结构-栈(链表实现和数组实现)

目录

1. 栈的介绍

1.1 栈的概念

1.2 栈的优点

1.3 栈的实现方式

2. 栈的链表实现

2.1 初始化栈

2.2 栈的判空

2.3 入栈(PUSH)

2.4 出栈(POP)

2.5 获取栈顶元素

3. 栈的数组实现

3.1 初始化栈

3.2 栈的判空

3.3 入栈(PUSH)

3.4 出栈(POP)

3.5 获取栈顶元素


1. 栈的介绍

1.1 栈的概念

        栈是插入和删除只能在一个位置上进行的线性表,该位置是线性表的末端,被称为栈顶。

1.2 栈的优点

(1)栈具有先进后出的特性,并且只能操作栈顶的元素,这个特性使得栈能够实现快顺序存储。

(2)对于局部变量和函数参数而言,它们被声明时会被存储在栈上,函数结束之后便被释放,这样极大的节省了空间。

1.3 栈的实现方式

        栈的实现方式一共有两种,一种是用链表实现,另外一种是用数组实现。我个人建议使用链表来实现栈,因为用数组实现栈时需要事先确定存储空间的大小,如果存储空间过小,可能会写入数据失败。

2. 栈的链表实现

2.1 初始化栈

        初始化栈就是创建一个空栈,用链表实现时,先创建一个头节点,然后头节点的指针域指向NULL即可。如果对链表不够熟悉,或者不理解为什么申请内存需要用二级指针,可以先看下面这两篇文档。

【C语言】常用的数据结构-单链表-CSDN博客

【C语言】二级指针的应用-CSDN博客

//节点声明
struct node 
{
    int element;       //数据域
    struct node* next; //指针域
}


//栈的初始化
void init_stack(struct node **pNode)
{
    *pNode = (struct node*)malloc(sizeof(struct node));
    if(NULL == *pNode)
    {
        printf("栈初始化申请内存失败");
        return NULL;
    }
    *pNode ->next = NULL;
}
 
//测试用例
struct node *pStack = NULL;
init_list(&pStack);

2.2 栈的判空

        对于用链表实现的栈来说,判空这个操作非常简单,只需对头节点的下一个节点判空即可。

//栈判空  1-空 0-非空
bool is_empty(struct node *pHead)
{
    assert(NULL != pHead));
    return (NULL == pHead)->next);
}

//测试用例
struct node *pStack;
is_empty(pStack);

2.3 入栈(PUSH)

        用链表实现入栈,实际上就是用链表插入新元素,而链表插入一个元素又分为头插法和尾插法。

        头插法是将链表头节点的后一个节点作为栈顶,这样做的好处的插入和删除的速度比较快。尾插法将最后一个元素作为栈顶,这样做的好处是便于理解,缺点是每次插入和删除都需要从头节点开始遍历整个链表再进行插入删除,速度很明显不如头插法,因此我个人建议使用头插法来入栈。

//入栈函数
void push(struct node *pHead, int element)
{
    //校验入参
    assert(NULL == pHead);
    //入参指针不要直接使用
    struct node *pNode = pHead;

    //创建新节点
    struct node *pNew = NULL;
    pNew = (struct node*)malloc(sizeof(struct node));
    if(NULL == pNew)
    {
        printf("新节点申请内存失败");
        return;
    }
    pNew->element = element;
    
    //插入操作
    if(is_empty(pNode))    //插入前是空栈
    {   
        pNode->next = pNew;
        pNew->next = NULL;
    }
    else    //插入前不是空栈
    {   
        pNode->next = pNew;
        pNew->next = pNode->next;
    }
}

//测试用例
struct node *pStack;
push(pStack, 10);

2.4 出栈(POP)

        上面使用了头插法来插入,即默认头节点的下一个元素为栈顶,那么我们出栈操作也要删除头节点的后一个元素。

//出栈函数
void pop(struct node *pHead)
{
    //校验入参
    assert(NULL == pHead);
    //入参指针不要直接使用
    struct node *pNode = pHead;
    
    //插入操作
    if(is_empty(pNode))   //插入前是空栈
    {   
        printf("空栈,无法删除");
        return;
    }
    else    //插入前不是空栈
    {   

        pNode->next = pNode->next->next;
        free(pNode->next);
    }
}

//测试用例
struct node *pStack;
pop(pStack);

2.5 获取栈顶元素

        获取栈顶元素非常简单,只需要读取头节点的下一个节点值即可。

//获取栈顶元素
int get_topElement(struct node *pHead)
{
    //校验入参
    assert(NULL == pHead);
    //不要直接使用指针
    struct node *pNode = pHead;
    
    //判断是否空栈
    if(is_empty(pNode)) 
    {   
        printf("空栈,无栈顶元素");
        return 0;
    }
    else   
    {   
        return pNode->next->element;
    }
}

//测试用例
struct node *pStack;
get_topElement(pStack);

3. 栈的数组实现

        栈的数组实现避免了指针,是一种简单的方法。但是存在的问题如前文所说,需要提前声明一个数组的大小,如果没有充足开销的话不建议使用这种方法。

3.1 初始化栈

        和链表实现栈的方法不同,用数组实现的栈不需要指针域,但是需要添加额外的栈顶下标TopIdx来跟踪栈顶索引,同时要定好栈的最大容量Maxsize。

//栈结构体
struct Stack
{
	int Data[Maxsize];   //栈数据
	int TopIdx;          //栈顶下标
}

//栈初始化
void init_stack(struct node *stack)
{
	stack.TopIdx = -1;
}

//测试用例
int MaxElement = 100;
struct Stack stack;
init_stack(&stack);

3.2 栈的判空

        用数组实现的栈的判空实际上就是判断栈顶下标是否合法,如果栈顶下标小于0,则说明这是一个空栈。

//栈的判空函数  1-空  0-非空
void is_stackEmpty(struct node *stack)
{
    return (-1 == (*stack).TopIdx);
}

3.3 入栈(PUSH)

        入栈前需要校验栈是否是已满,如果栈未满的话则正常写入数据,并将栈顶元素++。

//入栈函数
void Push(struct node *stack, int element)
{
	if((*stack)[TopIdx] >= (MaxSize - 1))
    {
        printf("栈已满,无法插入数据");
        return;
    }

    (*stack).Data[TopIdx++] = element;
}

//测试用例
Push(&stack, 20);

3.4 出栈(POP)

        出栈前需要校验栈是否是空栈,如果不是的话将栈顶数据请零,并将栈顶下标--。

//出栈函数
void Pop(struct node *stack)
{
	if(is_stackEmpty(stack))
    {
		printf("栈空,无法出栈"); 
	}

    stack.Data[TopIdx--] = 0;
}

//测试用例
Pop(&stack);

3.5 获取栈顶元素

        获取栈顶元素需要判断当前栈是否为空,不为空直接读取即可。

//获取栈顶元素
int get_topElement(struct node *stack)
{ 
	if(is_stackEmpty(stack))
    {
		printf("栈空,无栈顶元素"); 
	}
    return (*stack).Data[TopIdx];
}

//测试用例
int value = get_topElement(&stack);

  • 37
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电脑玩家饮水机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值