• 数据结构-----栈


    今天来介绍一下栈。本文先从栈的基本概念和结构入手,接着讲解基本操作,最后通过一个回文数的例子来巩固今天学的栈操作

    一、栈的基本概念

    栈: 只允许在一端进行插入或删操作的线性表。首先栈是一种线性表,但是限定这种线性表只能在某一段进行插入和删除操作

    栈顶:线性表允许进行插入和删除的那一端

    栈底:固定的,不允许进行插入和删除的另一端

    空栈:不含任何元素的空表

    二、栈的操作

    队列是FIFO(先进先出),栈是FILO(先进后出 或者 后进先出)

    最先进栈的元素,是不是就只能是最后出栈呢

    答案是不一定,要看什么情况。栈对线性表的插入和删除的位置进行了限制,并没有对元素进出的时间进行限制,也就是说,在不是所有元素都进栈的情况下,进去的元素也可以出栈,只要保证是栈顶元素出栈就可以,那么变化就很多了,举例来说:

    如果我们有3个整形数字元素1、2、3依次进栈,会有哪些出栈次序呢?

    • 第一种:1、2、3进,再3、2、1出。这事最简单的最好理解的一种,出栈次序为321
    • 第二种:1进,1出,2进,2出,3进,3出,出栈次序为123
    • 第三种:1进,2进,2出,1出,3进,3出,出栈次序为213
    • 第四种:1进,1出,2进,3进,3出,2出,出栈次序为132
    • 第五种:1进,2进,2出,3进,3出,1出,出栈次序为231

    有没有可能是312这样的次序出栈呢,答案是不可能的,因为3先出栈,就意味着3曾经进栈,既然3进栈了,那也意味着1和2已经进栈了,此时,2一定是在1的上面,就是更接近栈顶,那么出栈只可能是321,不然不满足123一次进栈的要求,所以此时不会发生1比2先出栈的情况

    栈的基本操作

    InitStack(&S):初始化一个空栈S 
    StackEmpty(S):判断一个栈是否为空,若栈S为空返回true,否则返回false 
    Push(&S,x):进栈,若栈S未满,将x加入使之成为新栈顶 
    Pop(&S,&x):出栈,若栈S非空,弹出栈顶元素,并用x返回 
    GetTop(S,&x):读栈顶元素,若栈S非空,用x返回栈顶元素 
    ClearStack(&S):销毁栈,并释放栈S占用的存储空间。

    (符号“&”是C艹特有的,用来宝石引用,有的采用C语言中的指针类型“*”,也可以达到传址的目的)

    如果没有特殊要求,可以直接用这些基本的操作函数

    三、栈的存储结构

    3.1、顺序存储结构

    #define MaxSize 50              //定义栈中元素的最大个数
    typedef struct{
        Elemtype data[MaxSize];     //存放栈中元素
        int top;                    //栈顶指针
    }SqStack;

    共享栈

    利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一位数据空间,将两个栈的栈底分别设置在共享空间的两端,两个栈向共享空间的中间延伸。

    两个栈的栈顶指针都指向栈顶元素,top0=-1时0号栈为空,top1=MaxSize时1号栈为空,当且仅当两个栈顶的指针相邻时,判断为占满。当0号栈进栈时top0先加1再复制,1号栈进栈时top1先减1再复制;出栈时刚好相反。

    共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被占满时才发生上溢。其存取数据的时间复杂度均为O(1)所以对存取效率没有什么影响。

    事实上使用遮掩的数据结构,通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。就像买卖股票一样,你买入时,一定是有一个你不知道的人在做卖出操作。有人赚钱,就一定有人赔钱。这样使用两栈共享空间存储方法再有比较大的意义。

    当然,这里指两个具有相同数据类型的栈,类型不同不适用这种方法。

    3.2、栈的链式存储结构(链栈)

    typedef struct Linknode{
        ElemType data;          //数据域
        struct Linknode *next;  //指针域
    } *LinkStack;               //栈类型定义

    四、实战

    以上就是栈的基本介绍,其实主要就记住三点------栈的FILO、栈的顺序存储结构和栈的链式存储结构

    下面来,利用栈的操作,判断输入的字符串是否为回文数

    (所谓的回文数,就是输入的字符串是否对称),下面采用两种方法判别

    4.1、不采用栈来操作(个人第一反应的方法),代码如下

    #include<stdio.h>
    #include<string.h>
    #define N 101
    
    // 判断是否为回文数
    
    int main()
    {
        char str[N];
        int i,middle,length,flag;
        
        while(gets(str))
        {        
            length = strlen(str);
            middle = length/2;    // 取中位数
            flag = 1;     // 用0标记不是回文数  1标记回文数 
            for(i=0;i<middle;++i)
            {
                if(str[i]!=str[length-i-1])
                {
                    flag = 0;
                    break;                
                }
            } 
            if(flag==1)
                printf("YES
    ");
            else
                printf("NO
    ");    
        }
        
        return 0;
    } 

    4.2、采用栈(顺序栈)来操作

    #include<stdio.h>
    #include<string.h>
    #define MaxSize 101
    
    // 采用栈来判断回文数
    
    typedef struct{
        char data[MaxSize];    // 存放栈中元素
        int top;               // 栈顶指针 
    }Stack;
    
    int main()
    {
        Stack s;
        char array[MaxSize];
        int i,middle,len,next;
        
        while(gets(array))
        {
            len = strlen(array);
            middle = len/2;
            s.top = 0;  // 栈初始化
            // 将middle 前的字符依此入栈
            for(i=0;i<middle;++i)
            {
                s.data[++s.top] = array[i];
            }
            
            // 判断字符串的长度是奇数还是偶数,并找出需要进行字符匹配的起始下标         
            if(len%2==0)
                next = middle + 1;
            else
                next = middle + 2;
            
            // 开始匹配
            for(i=next-1;i<len;++i)
            {
                if(array[i]!=s.data[s.top])
                    break;
                s.top--;    
            }        
        
            // 如果top的值为0,则说明栈呢所有字符都被一一匹配了
            if(s.top==0)
                printf("YES
    ");
            else
                printf("NO
    ");     
        }
        
        return 0;
    } 

    不管是队列还是栈,一般采用顺序存储的较多。就跟上面的例子一样,不采用栈来的更快,更简洁些,代码风格因人而异!本人菜鸟一枚,欢迎拍砖赐教

  • 相关阅读:
    java基础---多线程---volatile详解
    java基础---多线程---线程的几种状态及其转换,wait,notify,sleep,yield,join
    java基础---设计一个死锁
    count(1) and count(*),count(字段)区别及效率比较
    mysql之字段约束-第五篇
    mysql之数据表基本操作-第四篇
    mysql之数据类型-第三篇
    mysql之存储引擎-第二篇
    mysql之数据库操作-第一篇
    Redis详解
  • 原文地址:https://www.cnblogs.com/guohaoblog/p/9220363.html
Copyright © 2020-2023  润新知