前端能力模型-数据结构-栈

本文详细介绍了栈的定义、基本实现方式以及普通顺序栈和链式栈的实现过程,包括初始化、元素压入、打印栈内元素、数据节点出栈等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、栈的基本定义

1、栈是一种特殊的线性表,只能从固定的方向进出,而且栈进出的基本原则是:先进栈的元素后出栈。


2、栈顶栈底的定义:
栈顶:允许操作的一端。
栈底:不允许操作的一端。

二、栈的基本实现方式

1、使用顺序存储的方式实现栈

在这种方式下,我们采用顺序表的复用方法来实现栈的数据存储。

2、使用链式存储来实现栈


在这种方式下,我们采用单向链表的复用技术来实现链栈。

三、普通的顺序栈

1、首先定义的顺序栈中的数据节点的结构,主要包括两个部分,一部分是数据元素,另一部分是顺序栈的长度。
具体代码如下:
新建文件名:SeqList.h
typedef struct _tag_stack_
{
     int a[20];
     int top;
}Sqstack;

2、使用顺序栈之前要先初始化顺序栈。
主要是为顺序栈节点分配一个空间,然后将顺序栈的长度初始化为0。

Sqstack* InitStack ()
{
     Sqstack *ret = NULL;
     ret = (Sqstack*)malloc (sizeof(Sqstack));
     if (ret)
     {
          /*将栈的长度初始化为0*/ 
          ret -> top = 0;
     }
     return ret;
}
3、将元素压入栈,这里采用复用方式。
int Push(Sqstack *stack, int data)
{
     /*这里有一个复用方式,也就是顺序栈的长度和数组的下标进行复用s*/
     stack -> a[stack -> top] = data;
     stack -> top++;
     return 1;
}

4、将已经在栈中的元素进行打印,因为栈不是只是一种存储数据的结构,所以我们不经过弹出栈中的元素也是可以访问到栈中的元素的。
void Play (Sqstack *stack)
{
     int i = 0;
     if (stack -> top == 0)
     {
          printf ("It is empty\n");
     }
     /*stack -> top,栈的长度*/
     else
     {
          for (i = 0; i < stack -> top; i++)
          {
               printf ("栈中的数据为:%d\n", stack -> a[i]);
          }
     }
}

5、数据节点出栈
int Pop (Sqstack *stack, int *data)
{
     if (stack -> top == 0)
     {
          printf ("the stack is empty\n");
          printf ("弹出已经被改变了的u的值");
     }
     else
     {     
          stack -> top--;
          *data = stack -> a[stack -> top];
     }
     return 1;      
}

6、测试部分代码如下:
a) 把1~5步骤按顺序组合成SeqList.h文件
b) 创建StackTest.cpp文件,代码如下:
#include <stdio.h>
#include <malloc.h>
#include "SeqList.h"
int main()
{
    int h = 4;
    int p = 0;
    int i = 0;
    int u = 3;
    Sqstack* qq; 
    qq = InitStack();
    for (i = 0; i < 5; i++)
    {   
        Push (qq, i); 
    }   
    Play (qq);

    /*弹出操作*/
    Pop (qq, &u);
    printf ("弹出的元素是:%d\n", u); 
    Pop (qq, &u);
    printf ("弹出的元素是:%d\n", u); 
    Pop (qq, &u);
    printf ("弹出的元素是:%d\n", u); 
    Pop (qq, &u);
    printf ("弹出的元素是:%d\n", u); 
    Pop (qq, &u);
    printf ("弹出的元素是:%d\n", u); 
    Pop (qq, &u);
    printf ("%d\n", u); 
    return 1;
}
c) 编译与执行:
编译:g++ StackTest.cpp -o StackTest
执行:./StackTest

7、虽然顺序栈实现了栈的基本功能,毕竟是顺序存储结构,而且占用的内存空间也必须是连续的,所以还是有一定的局限性的。

四、链式栈的实现
1、定义数据节点
数据节点用结构体来封装,这个结构体中包含了每一个next元素的信息和进栈元素的地址,虽然我们在创建链表的时候已经进行了一个结构体的定义,但是我们的栈成员并不适用于那套链表,所以这里进行重新定义。
typedef struct _tag_LinkStack_
{
     LinkListNode header;
     void *item;
}TLinkStackNode;

2、销毁栈的函数
void LinkStack_Destroy(LinkStack* stack)
{
     /*调用栈清空函数*/
     LinkStack_Clear (stack);
     /*调用链表销毁函数*/
     LinkList_Destroy(stack); 
}
销毁栈的函数中主要调用了栈的清空函数和链表的销毁函数,销毁栈的前提首先要销清空栈中的每一个成员,然后在销毁栈的头。
3、栈的清空函数
void LinkStack_Clear(LinkStack* stack)
{
     while (LinkStack_Size (stack) > 0)
     {
          LinkStack_Pop (stack);
     }
}
栈的清空函数中和链表的清空函数是有区别的,在栈的清空函数中我们主要是对栈中是否还存在元素进行了判定,如果还有元素就对将栈中的元素弹出,而链表的清空只是将链表头指向NULL,将链表长度置为0。

4、将元素压入栈的操作
int LinkStack_Push(LinkStack* stack, void* item)
{
     TLinkStackNode* node = (TLinkStackNode*)malloc (sizeof (TLinkStackNode));

     int ret = (node != NULL) && (item != NULL); 
     
     if (ret)
     {
          node->item = item;
          
          ret = LinkList_Insert (stack, (LinkListNode*)node, 0);
     }

     if (!ret)
     {
          free(node);
     }
     
     return ret; 
}
在将元素压入栈的过程中,我们首先要为我们即将压入栈的元素开辟一块空间,因为是链式表,所以我们的空间不一定非要是连续的,这是采用malloc的方式。
然后进行安全性的检测,我们要判断开辟的空间是否成功,然后还要判断我们要插入的元素的地址是不是空。如果条件都成立那我们进行元素的进栈操作。
元素的进栈操作,我们将要插入的数据节点的地址赋给栈结构体的item,然后调用链表的插入函数操作,将这个栈的数据节点插入栈中,而且由于我们是把链表的头作为栈顶,所以我们插入栈元素的位置为0。
如果我们的安全性检测没有通过,那么我们就释放为了插入一个栈元素而释放的空间。

5、元素的出栈操作
void* LinkStack_Pop(LinkStack* stack)
{
     TLinkStackNode* node = (TLinkStackNode*)LinkList_Delete(stack, 0);
     void * ret = NULL;
     if (node != NULL)
     {
          ret = node->item;
          free(node);
     } 
     return ret;
}
元素的出栈操作中,首先通过调用链表的元素删除函数来删除我们要弹出栈的元素,因为栈永远都是从栈顶弹出元素,而我们进栈的方向也是从链表的0位置方向进栈的,所以我们只要删除链表中的第0个元素即可(所谓的链表第0个元素)。
然后我们判定要删除的元素是否为空,如果不为空,那么我们将返回我们要弹出栈的元素。
在将元素弹出栈以后我们就要释放为这个链表中的元素开辟的空间。而我们的链表操作的空间是在操作具体数据元素的时候才开辟空间,我们不使用链表的时候它是不占用空间的。

6、获取栈顶元素操作
void* LinkStack_Top(LinkStack* stack)
{
     TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0);
     void *ret = NULL;
     if (node != NULL)
     {
          ret = node->item;
     } 
     return ret;
}
通过LinkList_Get函数可以获得固定位置的元素,由于我们进栈的时候就是从0位置,所以在我们获取栈顶元素的时候也是从0位置开始获取。

7、测试链式栈实现代码
a) 创建一个Stack.h
#ifndef Stack_H
#define Stack_H

typedef int Item;
typedef struct node * PNode;
typedef struct node
{
    Item data;
    PNode next;
}Node;

typedef struct stack *PStack;
typedef struct stack
{
    Item size;
    PNode top;
}Stack;

/***创建空栈,并返回栈顶***/
PStack Creat_Stack();

/***判断是否为空栈***/
int Is_Empty(PStack);

/***数据项入栈***/
PStack Push_Stack(PStack,Item);

/***计算栈的大小***/
int Size_Stack(PStack);

/***返回栈顶数据项***/
Item Get_Item_Stack(PStack);

/***数据项出栈***/
Item Pop_Stack(PStack);

/***清空链栈***/
void Clear_Stack(PStack);

/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack);
#endif

b) 创建StackTest.cpp

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

/***创建空栈,并返回栈顶***/
PStack Creat_Stack()
{
     PStack P=(PStack)malloc(sizeof(Stack));
     if(NULL!=P)
     {
          P->top=NULL;
          P->size=0;
     }
     return P;
}

/***判断是否为空栈***/
int Is_Empty(PStack P)
{
     if(0==P->size && NULL==P->top)
          return 1;
     else
          return 0;
}

/***数据项入栈***/
PStack Push_Stack(PStack P,Item val)
{
     PNode PNew=(PNode)malloc(sizeof(Node));
     if(NULL==PNew)
     {
          printf("Malloc the PNew is failed.\n");
          exit(1);
     }
     else
     {
          PNew->data=val;
          PNew->next=P->top;
          P->top=PNew;
          P->size++;
     }
     return P;
}

/***计算栈的大小***/
int Size_Stack(PStack P)
{
     /*int size=0;
     PNode PCurrent=(PNode)malloc(sizeof(Node));
     PCurrent=P->top;
     while(NULL!=PCurrent)
     {
          size++;
          PCurrent=PCurrent->next;
     }
     return size;*/
     return P->size;
}

/***返回栈顶数据项***/
Item Get_Item_Stack(PStack P)
{
     if(0!=P->top->data && Is_Empty(P)==0)
          return P->top->data;
}

/***数据项出栈***/
Item Pop_Stack(PStack P)
{
     Item data;
     PNode temp=P->top;
     if(NULL==temp)
     {
          printf("The stack is empty.\n");
          exit(1);
     }
     data=temp->data;
     P->top=temp->next;
     P->size--;
     free(temp);
     return data;
}

/***清空链栈***/
void Clear_Stack(PStack P)
{
     if(Is_Empty(P))
          printf("The stack had empty.\n");
     PNode PCurrent=P->top;
     int i=P->size;
     while(i--)
     {
          P->top=PCurrent->next;
          P->size--;
          free(PCurrent);
          PCurrent=P->top;
     }
}

/***遍历栈,并自栈顶输出数据项***/
void Traverse_Stack(PStack P)
{
     PNode PCurrent = P->top;  
    int i = P->size; 
     printf("The data of stack are:");
    while(i--)  
    {  
        printf("%d  ",PCurrent->data);  
        PCurrent = PCurrent->next;  
    } 
     printf("\n");
}

int main()
{
     int size=0;
     int top_data,Pop_data;
     PStack PS;
     PS=Creat_Stack();
     if(NULL!=PS)
          printf("The stack is created.\n");

/***判断是否为空栈***/
     if(Is_Empty(PS))
          printf("The stack is empty.\n");

/***数据项入栈***/
     Push_Stack(PS,2);
     Push_Stack(PS,3);
     Push_Stack(PS,5);
     Traverse_Stack(PS);

/***计算栈的大小***/
     size=Size_Stack(PS);
     printf("The length of stack is: %d\n",size);
     
/***返回栈顶数据项***/
     top_data=Get_Item_Stack(PS);
     printf("The top of data is: %d\n",top_data);

/***数据项出栈***/
     Pop_data=Pop_Stack(PS);
     printf("The Pop of data is: %d\n",Pop_data);
     Traverse_Stack(PS);

/***清空链栈***/
     Clear_Stack(PS);
     Traverse_Stack(PS);
     
     return 0;
}


数据结构运行环境:
采用linux机器,安装gcc和g++,能够编译执行c和c++代码
c语言编译和执行操作如下:
示例
编译:gcc Hello.c -o hello
执行:./hello
c++语言编译和执行操作如下:
示例
编译:g++ Hello.cpp -o hello
执行:./hello






























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值