数据结构 栈(C语言)

数据结构 栈

一、栈
1.栈是一种操作受限制的线性表,其仅能在表尾进行插入和删除操作。我们把这一端称为栈顶,相对地,把另一端称为栈底。因此栈是一种“后进先出”的数据形式。
在这里插入图片描述

二、链栈
1.带头结点的链栈:由于栈是一种“后进先出”的数据形式,所以第n个进入栈的元素a_n为第一个元素,a_(n-1)为第二个元素,以此类推,a_1为最后一个元素。
在这里插入图片描述

带头结点的链栈
在这里插入图片描述

不带头结点的链栈

2.链栈的存储结构定义:

typedef int Item;
typedef struct node
{
    Item item;            //栈的数据域
    struct node * next;   //栈的指针域,指向栈中的下一个结点
}Node;
typedef Node * Stack;

该定义中通过typedef为某一类型自定义名称。用Item作为int的别名(这样做更加通用),如果以后需要其他数据形式的链栈,可以重新定义Item类型。用Node作为struct node的别名,链栈的结点类型名是Node。用Stack作为Node *的别名,Stack作为该类型(Node)的指针名,若有Stack S;则表示创建了一个链栈(S表示指向链栈的头指针,即表示链栈)。

3.链栈的初始化:将链栈初始化为空。

void InitStack(Stack * S)  //形参:指向Stack类型的指针
{
     *S=(Node *)malloc(sizeof(Node));   //建立头结点
     (*S)->next=NULL;                   //头结点的指针域设置为NULL
}
带头结点的链栈初始化
void InitStack(Stack * S)  //形参:指向Stack类型的指针
{
	 *S=NULL;     //链栈头指针设置为NULL
}
不带头结点的链栈初始化

带头结点的链栈初始化前/后:(初始化后链栈为空)
在这里插入图片描述

4.链栈的判空:

bool StackIsEmpty(const Stack * S)  //形参:指向Stack类型的指针,由于该函数不修改栈中内容,使用const修饰符对指针所指向的内容进行保护
{
     if((*S)->next==NULL)  //判断链栈头结点的指针域是否为NULL
        return true;
     else
        return false;
}

5.链栈的进栈操作:

bool Push(Stack * S,Item item)  //形参:1.指向Stack类型的指针  2.Item类型的变量item,用于为新结点的数据域赋值
{
     Node * temp;  //指向Node类型的指针temp
     temp=(Node *)malloc(sizeof(Node));  //申请一个结点的空间,并将其地址赋给结构指针temp
     if(temp==NULL)  //若申请结点不成功,则返回false
         return false;
     temp->item=item;        //为新结点的数据域赋值
     temp->next=(*S)->next;  //将头结点的指针域赋给新结点的指针域
     (*S)->next=temp;        //头结点的指针域指向新结点
     return true;
}

在这里插入图片描述

6.链栈的出栈操作:

bool Pop(Stack * S,Item * item)  //形参:1.指向Stack类型的指针 2.指向Item类型的指针,带出出栈结点的数据域
{
     Node * temp;      //指向Node类型的指针temp
     temp=(*S)->next;  //指针temp指向链栈的首元结点
     if(temp==NULL)    //若链栈为空,则返回false
        return false;
     (*S)->next=temp->next;  //将首元结点的指针域赋给头结点的指针域(即头结点的指针域指向第二结点)
     *item=temp->item;       //将出栈结点的数据域通过指针item带出
     free(temp);             //释放出栈结点所占用的空间
     return true;
}

在这里插入图片描述

7.链栈取栈顶元素:
取链栈的顶部元素赋给item所指向的单元,也称读栈顶。与Pop不同之处在于GetTop不改变栈顶的位置(即不会将栈顶元素出栈)。

bool GetTop(Stack * S,Item * item)  //形参:1.指向Stack类型的指针 2.指向Item类型的指针,取栈顶元素赋给item所指向的单元
{
     Node * temp;      //指向Node类型的指针temp
     temp=(*S)->next;  //指针temp指向链栈的首元结点
     if(temp==NULL)    //若链栈为空,则返回false
        return false;  
     *item=temp->item; //取栈顶元素赋给item所指向的单元
     return true;
}

8.统计栈中元素个数:

int StackItemCount(const Stack * S)  //形参:指向Stack类型的指针,由于该函数不修改栈中内容,使用const修饰符对指针所指向的内容进行保护
{
    int count=0;  //定义一个计数器count
    Node * temp;  //指向Node类型的指针temp
    temp=(*S)->next;   //指针temp指向链栈的首元结点
    while(temp!=NULL)  //遍历栈,递增计数器
    {
        count++;
        temp=temp->next;
    }
    return count;
}

9.链栈样例:

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

typedef int Item;
typedef struct node
{
    Item item;
    struct node * next;
}Node;
typedef Node * Stack;

void InitStack(Stack * S);
void output(const Stack * S);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool StackIsEmpty(const Stack * S);
bool GetTop(Stack * S,Item * item);
int StackItemCount(const Stack * S);

int main()
{
    Stack S;
    int a,b,c;

    InitStack(&S);
    if(StackIsEmpty(&S)==true)
        printf("栈为空!\n");
    printf("请输入一个整数:");
    while(scanf("%d",&a)==1)
    {
        if(Push(&S,a)==true)
            printf("%d入栈!\n",a);
        else
        {
            printf("栈已满!");
            break;
        }
        printf("请输入一个整数:");
    }
    printf("栈中有 %d个元素。\n",StackItemCount(&S));
    printf("栈中元素为:\n");
    output(&S);
    GetTop(&S,&b);
    printf("\n栈顶元素为: %d\n\n",b);
    printf("连续出栈三个元素。\n");
    for(int i=1;i<=3;i++)
    {
        if(Pop(&S,&c)==true)
            printf("出栈元素为: %d\n",c);
        else
            printf("栈为空!\n");
    }
    GetTop(&S,&b);
    printf("\n现栈顶元素为: %d\n",b);
    printf("现栈中有 %d个元素。\n",StackItemCount(&S));
    printf("现栈中元素为:\n");
    output(&S);

    return 0;
}

void InitStack(Stack * S)
{
     *S=(Node *)malloc(sizeof(Node));
     (*S)->next=NULL;
}

bool StackIsEmpty(const Stack * S)
{
     if((*S)->next==NULL)
        return true;
     else
        return false;
}

bool Push(Stack * S,Item item)
{
     Node * temp;
     temp=(Node *)malloc(sizeof(Node));
     if(temp==NULL)
         return false;
     temp->item=item;
     temp->next=(*S)->next;
     (*S)->next=temp;
     return true;
}

bool Pop(Stack * S,Item * item)
{
     Node * temp;
     temp=(*S)->next;
     if(temp==NULL)
        return false;
     (*S)->next=temp->next;
     *item=temp->item;
     free(temp);
     return true;
}

bool GetTop(Stack * S,Item * item)
{
     Node * temp;
     temp=(*S)->next;
     if(temp==NULL)
        return false;
     *item=temp->item;
     return true;
}

int StackItemCount(const Stack * S)
{
    int count=0;
    Node * temp;
    temp=(*S)->next;
    while(temp!=NULL)
    {
        count++;
        temp=temp->next;
    }
    return count;
}

void output(const Stack * S)
{
     Node * temp;
     temp=(*S)->next;
     while(temp!=NULL)
     {
         printf("%d\t",temp->item);
         temp=temp->next;
     }
}

输出结果:
在这里插入图片描述

10.括号匹配算法:
在检验算法中可设置一个栈,读入表达式的当前字符:
①若是左括号,则直接入栈,等待相匹配的同类右括号;
②若是右括号,则将它与栈顶左括号相比较:
若栈已空,则说明表达式中括号不匹配;返回
若栈非空,且栈顶的左括号与刚读入的右括号同类型,则二者匹配,此时将栈顶的左括号出栈;
若栈非空,且栈顶的左括号与刚读入的右括号不同类型,说明表达式不合法。返回
③重复上述过程,直到表达式结束。若此时栈中仍有等待匹配的左括号,说明表达式不合法。返回。
④当输入序列和栈同时变为空时,说明所有括号完全匹配。

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

#define SIZE 100

typedef char Item;
typedef struct node
{
    Item character;
    struct node * next;
}Node;
typedef Node * Stack;

void InitStack(Stack * S);
bool StackIsEmpty(Stack * S);
bool Match(char ch1,char ch2);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool GetTop(Stack * S,Item * item);
void BracketMatch(Stack * S,char * str);

int main()
{
    Stack S;
    char str[SIZE];

    InitStack(&S);
    printf("请输入一个字符串:");
    gets(str);
    BracketMatch(&S,str);

    return 0;
}

void InitStack(Stack * S)
{
     *S=(Node *)malloc(sizeof(Node));
     (*S)->next=NULL;
}

bool StackIsEmpty(Stack * S)
{
     if((*S)->next==NULL)
        return true;
     else
        return false;
}

bool Push(Stack * S,Item item)
{
     Node * temp;
     temp=(Node *)malloc(sizeof(Node));
     if(temp==NULL)
         return false;
     temp->character=item;
     temp->next=(*S)->next;
     (*S)->next=temp;
     return true;
}

bool Pop(Stack * S,Item * item)
{
     Node * temp;
     temp=(*S)->next;
     if(temp==NULL)
        return false;
     (*S)->next=temp->next;
     *item=temp->character;
     free(temp);
     return true;
}

bool GetTop(Stack * S,Item * item)
{
     Node * temp;
     temp=(*S)->next;
     if(temp==NULL)
        return false;
     *item=temp->character;
     return true;
}

bool Match(char ch1,char ch2)
{
    if((ch1=='('&&ch2==')')||(ch1=='['&&ch2==']')||(ch1=='{'&&ch2=='}'))
        return true;
    else
        return false;
}

void BracketMatch(Stack * S,char * str)
{
    char ch;
    for(int i=0;str[i]!='\0';i++)
    {
        switch(str[i])
        {
            case '(':Push(S,str[i]);break;
            case '[':Push(S,str[i]);break;
            case '{':Push(S,str[i]);break;
            case ')':
            case ']':
            case '}':
                     if(StackIsEmpty(S)==true)
                     {
                        printf("右括号多余!\n");
                        return ;
                     }
                     else
                     {
                        GetTop(S,&ch);
                        if(Match(ch,str[i])==true)
                        Pop(S,&ch);
                        else
                        {
                            printf("对应的左右括号不同类!\n");
                            return ;
                        }
                     }
        }//switch
    }//for
    if(StackIsEmpty(S)==true)
        printf("括号匹配!\n");
    else
        printf("左括号多余!\n");
}

输出结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、顺序栈
1.顺序存储结构的栈,即利用一组地址连续的存储单元依次存放栈的数据元素。栈顶指针top:动态地指示栈顶元素在顺序栈中的位置。通常以top=-1表示空栈。
在这里插入图片描述

2.顺序栈的存储结构定义:

#define SIZE 20

typedef char Item;
typedef struct{
        Item elem[SIZE];  //存放栈元素
        int top;  //标记栈顶元素下标,top=-1时栈为空
}Stack;

该定义中通过typedef为某一类型自定义名称。用Item作为char的别名(这样做更加通用),如果以后需要其他数据形式的顺序栈,可以重新定义Item类型。使用top标记栈顶元素下标,top=-1时栈为空。通过define定义SIZE,作为栈的容量大小。

3.顺序栈的初始化:将top置为-1。

void InitStack(Stack * S)  //形参:指向Stack类型的指针
{
     S->top=-1;  //top置为-1
}

在这里插入图片描述

4.顺序栈判空和判满:
①:顺序栈判空:

bool StackIsEmpty(const Stack * S)  //形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护
{
     if(S->top==-1)  //若top=-1则栈为空,返回true,否则返回false
        return true;
     else
        return false;
}

②:顺序栈判满:

bool StackIsFull(const Stack * S)  //形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护
{
     if(S->top==SIZE-1)  //若栈容量大小-1与top相等,则返回true,否则返回false
        return true;
     else
        return false;
}

5.顺序栈的入栈操作:

bool Push(Stack * S,Item item)  //形参:1.指向Stack类型的指针 2.Item类型的变量item,用于为top所标记的空间赋值
{
     if(S->top==SIZE-1)  //若栈已满,则返回false
        return false;
     S->top++;  //更新top,使top指向新的栈顶元素下标
     S->elem[S->top]=item;  //为top标记的数组空间赋值
     return true;
}

在这里插入图片描述

6.顺序栈的出栈操作:

bool Pop(Stack * S,Item * item)  //形参:1.指向Stack类型的指针 2.指向Item类型的指针,带出出栈空间的元素
{
     if(S->top==-1)  //若栈为空,则返回false
        return false;
     *item=S->elem[S->top];  //通过指针item将出栈元素带出
     S->top--;  //修改top,使top指向新的栈顶元素下标
     return true;
}

在这里插入图片描述

7.顺序栈取栈顶元素:

bool GetTop(const Stack * S,Item * item)  //1.形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护 2.指向Item类型的指针,取栈顶元素赋给item所指向的单元
{
     if(S->top==-1)  //若栈为空,则返回false
        return false;
     *item=S->elem[S->top];  //取栈顶元素赋给item所指向的单元
     return true;
}

8.顺序栈样例:

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

#define SIZE 20

typedef char Item;
typedef struct{
        Item elem[SIZE];
        int top;
}Stack;

void InitStack(Stack * S);
void output(const Stack * S);  //显示栈中元素
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool StackIsEmpty(const Stack * S);
int StackElemCount(const Stack * S);  //统计栈中元素个数
bool GetTop(const Stack * S,Item * item);

int main()
{
    Stack S;
    char a,b,c;

    InitStack(&S);
    if(StackIsEmpty(&S)==true)
        printf("顺序栈为空!\n");
    printf("请输入一个字符,输入#结束:");
    while(scanf("%c",&a)&&a!='#')
    {
        if(Push(&S,a)==true)
            printf("%c入栈!\n",a);
        else
        {
            printf("顺序栈已满!\n");
            break;
        }
        getchar();
        printf("请输入一个字符,输入#结束:");
    }
    printf("顺序栈中有 %d个元素。\n",StackElemCount(&S));
    printf("顺序栈中元素为:\n");
    output(&S);
    GetTop(&S,&b);
    printf("\n栈顶元素为: %c\n\n",b);
    printf("连续出栈三个元素。\n");
    for(int i=1;i<=3;i++)
    {
        if(Pop(&S,&c)==true)
            printf("出栈元素为: %c\n",c);
        else
            printf("栈为空!\n");
    }
    GetTop(&S,&b);
    printf("\n现栈顶元素为: %c\n",b);
    printf("顺序栈中有 %d个元素。\n",StackElemCount(&S));
    printf("现顺序栈中元素为:\n");
    output(&S);

    return 0;
}

void InitStack(Stack * S)
{
     S->top=-1;
}

bool StackIsEmpty(const Stack * S)
{
     if(S->top==-1)
        return true;
     else
        return false;
}


bool Push(Stack * S,Item item)
{
     if(S->top==SIZE-1)
        return false;
     S->top++;
     S->elem[S->top]=item;
     return true;
}

bool Pop(Stack * S,Item * item)
{
     if(S->top==-1)
        return false;
     *item=S->elem[S->top];
     S->top--;
     return true;
}

bool GetTop(const Stack * S,Item * item)
{
     if(S->top==-1)
        return false;
     *item=S->elem[S->top];
     return true;
}

int StackElemCount(const Stack * S)  //
{
    int count;
    count=S->top+1;
    return count;
}

void output(const Stack * S) 
{
     int temp;
     temp=S->top;
     while(temp>=0)
     {
         printf("%c\t",S->elem[temp]);
         temp=temp-1;
     }
}

输出结果:
在这里插入图片描述

9.使用栈判别回文字符串。(回文字符串:正读反读均相同的字符序列,其结构呈中心对称)

#include<stdio.h>
#include<string.h>
#include<stdbool.h>

#define SIZE 100

typedef char Item;
typedef struct{
        Item elem[SIZE];
        int top;
}Stack;

void InitStack(Stack * S);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);

int main()
{
    Stack S;
    int len,mid,next;
    char c,str[SIZE];

    InitStack(&S);
    printf("请输入一个字符串:");
    scanf("%s",str);
    len=strlen(str);
    mid=len/2;
    for(int i=0;i<mid;i++)
    {
        Push(&S,str[i]);
    }
    if(len%2==0)
        next=mid;
    else
        next=mid+1;
    for(int i=next;i<len;i++)
    {
        Pop(&S,&c);
        if(str[i]!=c)
            break;
    }
    if(S.top==-1)
        printf("\n该字符串 (%s) 是回文字符串!",str);
    else
        printf("\n该字符串 (%s) 不是回文字符串!",str);

    return 0;
}

void InitStack(Stack * S)
{
     S->top=-1;
}

bool Push(Stack * S,Item item)
{
     if(S->top==SIZE-1)
        return false;
     S->top++;
     S->elem[S->top]=item;
     return true;
}

bool Pop(Stack * S,Item * item)
{
     if(S->top==-1)
        return false;
     *item=S->elem[S->top];
     S->top--;
     return true;
}

输出结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值