数据结构之栈详解

什么是栈?

栈(Stack)是一种基本的数据结构,它是一种后进先出(LIFO)的数据结构,它允许在一端插入和删除元素。栈的应用非常广泛,例如在编程语言中用于存储函数调用和返回地址,以及在操作系统中用于管理进程的内存分配等。

栈的实现方式

栈可以使用数组或链表来实现。使用数组实现栈时,需要定义一个固定大小的数组,并使用一个指针来跟踪栈顶。pushstack 操作将元素添加到数组的末尾,然后将指针向上移动一位,而 popstack 操作则将指针向下移动一位并返回数组的最后一个元素。使用链表实现栈时,每个节点都包含一个数据元素和一个指向下一个节点的指针。pushstack 操作将一个新节点添加到链表的头部,而 popstack 操作则将头节点删除并返回其数据元素。

下面我们分别来看一下使用数组和链表实现栈的代码。

使用数组实现栈

以下是使用数组实现栈的示例代码:

#include <stdio.h>
#include <stdlib.h>


//构造顺序栈结构体

struct seqstack
{
    int data[20];
    int size;
    int top;//栈顶指针

};

//创建顺序栈

struct seqstack * create()
{
    //顺序栈创建
    struct seqstack *p = malloc(sizeof(struct seqstack));
    
    //初始化顺序栈
    p->size = 20;
    p->top = 0; 
    
    return p;
}

//入栈
void pushstack(struct seqstack *stack,int data)
{
    //栈满,不入栈
    if(stack->top == stack->size)
    {
        printf("栈满\n");
        return;
    }
    
    //入栈
    //先插入数据
    stack->data[stack->top] = data;
    //top栈顶进行移动
    stack->top++;
}

//出栈
int popsack(struct seqstack *stack)
{
    //栈空,不出栈
    if(stack->top == 0)
    {
        printf("栈空\n");
        return -1;
    }

    //出栈
    //先把栈顶指针往前一个位置移动
    stack->top--;
    //删除(由于是顺序栈即数组连续空间,数据覆盖即删除)
    return stack->data[stack->top];
}

//遍历
void show(struct seqstack * stack)
{
    for(int i = stack->top;i >= 0;i--)
    {
        printf("%d ",stack->data[i]);
    }
    printf("\n");

}

//主函数
int main()
{

	struct seqstack * stack = create();


	show(stack);
	popstack(stack);

	pushstack(stack,1);
	pushstack(stack,2);
	pushstack(stack,3);
	pushstack(stack,4);
	
	show(stack);

	printf("当前出栈 %d\n",popstack(stack));
	printf("当前出栈 %d\n",popstack(stack));

	pushstack(stack,10);
	pushstack(stack,20);
	show(stack);
	return 0;
}

在这个示例代码中,我们使用一个数组 data来存储栈中的元素,使用变量 top 来跟踪栈顶的位置。在 pushstack 操作中,我们首先检查栈是否已满,如果已满则输出错误信息。如果栈未满,则将元素添加到栈顶,并将 top 指针上移一位。在 popstack 操作中,我们首先检查栈是否为空,如果为空则输出错误信息并返回 -1。如果栈非空,则将栈顶元素弹出并返回。在show操作中,则是遍历顺序栈的所有元素。最后调用了主函数来进行了简单的测试顺序栈的插入、删除、遍历功能。

使用链表实现栈

以下是使用链表实现栈(头结点为栈顶)的示例代码:

#include <stdio.h>
#include <stdlib.h>

//构造结点
struct Node
{
    int data;
    struct linkstack *next;

};

//创建链表栈,要得到头结点的地址(存储了栈顶位置)
struct Node *create()
{
    //创建空栈
	//创建头结点,存储栈顶的地址
    struct Node *head = malloc(sizeof(struct Node));
    head->next = NULL;
    return head;

}


//入栈
void pushstack(struct Node *head,int data)
{
    //创建一个新结点
    struct Node *new = malloc(sizeof(struct Node));
    new->data = data;
    //设置新结点存储当前栈顶
    new->next = head->next;
    //设置新结点为栈顶
    head->next = new;
}

//出栈
void popstack(struct Node *head)
{
    //判断是否为空
    if(head->next == NULL)
    {
        printf("空栈\n");
        return;
    }
    //出栈
    struct Node *p = head->next;
    head->next = p->next;
    printf("出栈元素:%d\n",p->data);
    free(p);
}

//遍历
void show(struct Node *head)
{
    struct Node *p = head;
    while(p->next != NULL)
    {
        p = p->next;
        printf("%d ",p->data);
    }
    printf("\n");
}

//主函数
int main()
{
	struct Node * stack = create();

	popstack(stack);

	pushstack(stack,1);
	popstack(stack);
	popstack(stack);
	
	pushstack(stack,10);
	pushstack(stack,20);
	pushstack(stack,30);
    show(stack);
	popstack(stack);
	popstack(stack);

	return 0;
}

在这个示例代码中,我们使用一个链表来实现栈。每个节点包含一个数据元素和一个指向下一个节点的指针。在 pushstack 操作中,我们创建一个新节点,并将其头结点作为 top 节点。然后在此位置进行元素的插入,始终将入栈元素插入到头结点后面。在 popstack 操作中,我们首先检查栈是否为空,如果为空则输出为空信息。如果栈非空,则定义一个新结点来储存头结点后一个结点(出栈元素)后进行删除操作,输出当前节点的数据元素,并释放该结点。在show操作中,则是遍历顺序栈的所有元素。最后调用了主函数来进行了简单的测试顺序栈的插入、删除、遍历功能。

栈的应用场景

栈是一种非常有用的数据结构,它可以用于许多不同的应用程序。以下是一些常见的应用场景:

  • 函数调用和返回地址的存储:在编程语言中,栈用于存储函数调用和返回地址。每当一个函数被调用时,其返回地址被压入栈中。当函数返回时,返回地址被弹出栈。
  • 表达式求值:在编译器中,栈用于求解表达式。当遇到一个运算符时,需要将其压入栈中。当遇到一个操作数时,需要将其弹出栈,执行相应的操作,并将结果压入栈中。
  • 内存分配:在操作系统中,栈用于管理进程的内存分配。每当一个进程被创建时,其栈被分配一定的内存空间。当进程调用函数或分配局部变量时,栈的大小会相应地增加。
  • 浏览器历史记录:在浏览器中,栈用于存储浏览器历史记录。每当用户浏览一个新页面时,其 URL 被压入栈中。当用户点击“后退”按钮时,栈顶元素被弹出栈,并返回到上一个页面。

总之,栈是一种非常有用的数据结构,它可以用于许多不同的应用程序。无论是使用数组还是链表实现栈,都需要注意一些常见的问题和错误,以确保代码的正确性和可靠性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值