• 关于栈的学习


    原创博文,转载请注明出处

    栈(Stack)是一种线性表,但是只允许在一端进行插入或删除操作。

    栈的顺序存储成为顺序栈,它是利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶的位置。

    栈的顺序存储类型可描述为

    1 #define MaxSize 50
    2 typedef struct{
    3         Elemtype data[MaxSize];
    4         int top    
    5 }SqStack

    初始时设置S.top=-1,栈顶元素:S.data[S.top]

    栈空条件:S.top==-1;栈满条件:S.top==MaxSize-1;栈长:S.top+1

    关于进栈和出栈的操作比较简单(只需要操作栈顶指针)在这里就不再描述。

    利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维数据空间,将两个栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸。在进行出栈和进栈操作时要注意栈顶指针的操作。

    栈的链式存储结构:采用链式存储,便于多个栈共享存储空间和提高效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行。链栈的操作与链表类似。需注意对于带头结点和不带头结点的链栈之间的区别。

    试题精选:

                1、3个不同元素依次进栈,能得到( )种不同的出栈序列。

                     对于n个不同元素进栈,出栈序列的个数为 (1/n+1)Cn2n=(1/n+1)((2n)! / (n!)*(n!)) 本题答案为5。

               2、若一个栈的输入序列是P1, P2, P3,...,Pn,其输出序列是1,2,3,...,n。若P3=1,则P1的值( )

                   A、可能是2           B、一定是2         C、不可能是2         D、不可能是3

                   由于 P3=1,即P1、P2、P3 连续入栈后,第一个出栈元素是P3,第二个出栈元素是2,而此时P1不是栈顶元素,因此P1的元素不可能是2。

              3、设栈的初始状态为空,当字符序列“n 1 _”作为栈的输入时,输出长度为3,且可用做C语言标识符的序列有(  )个。

                  标识符的第一个字符必须是大小写字母或下划线,而不能是数字。则符合规定的标识符有 n1_、n_1、_1n、_n1四种形式。根据 栈的操作特性,_n1这种情况是不可能出现的。

              4、元素 a、b、c、d、e依次进入初始为空的栈中,若元素进栈后可停留、可出栈,知道所有元素都出栈,则在所有可能的出栈序列中,以元素d开头的序列个数是( )。

                   出栈序列必是 d_c_b_a,e的顺序不定,在任意一个“_”上都有可能。

        5、设单链表的表头指针为h,结点结构由data和next两个域构成,其中 data 域为字符型。试设计算法判断该链表的前n个字符是否中心对称。例如 xyx、xyyx 都是中心对称。

                  思路:使用栈来判断表中的数据是否中心对称。将链表的前一半元素依次进栈。在处理链表的后一半元素时,当访问到链表的一个元素后,就从栈中弹出一个元素,两个元素比较,若相等,接着进行下一个元素的比较,一直到链表尾部。若这时栈是空栈,则证明是中心对称。

     1 int dc( LinkList ,int n ){
     2       char s[n/2];
     3       p=L->next;
     4       for( i=0;i<=n/2;i++ ){
     5             s[i]=p->next;
     6             p=p->next;
     7     }
     8      i--;
     9      if( n%2==1 )
    10            p=p->next;
    11      while(p!=NULL&&s[i]==p->data){
    12      i--;
    13      p=p->next;
    14     }
    15     if(i==-1)
    16        return 1;
    17     else
    18        return 0;
    19 }

          6、设有两个栈s1、s2都采用顺序栈方式,并且共享一个存储区[0,...,maxsize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向、迎面增长的存储方式。试设计s1、s2有关入栈和出栈的操作算法。

         思路:

                算法的关键在于两个栈入栈和退栈时栈顶指针的计算。s1栈与通常意义下的栈操作一样,而s2入栈时,其栈顶指针要减1(左移),退栈操作时 要加1 (右移)。

    1 #define maxsize
    2 typedef struct{
    3           ElemType stack[maxsize];
    4           int top[2];                       //2个栈顶指针
    5 }stk;
    6 stk s;

         (1) 入栈操作

     1 int push(int i, int x){
     2  //i 是栈号,i=1表示s1栈,i=2表示s2栈。成功返回1,失败返回0
     3      if(i<1||i>2){
     4         printf("栈号输入不对,请输入1或2
    ");
     5         exit(0);
     6      }
     7      if(s.top[1]-s.top[0]==1){
     8         printf(" 栈已满
     ")
     9         return 0;
    10      }
    11      switch(i){
    12         case 1: s.stack[++s.top[0]]=x;return 1;break;
    13         case 2: s.stack[--s.top[1]]=x;return 1;break;
    14     }
    15 }

           (2)退栈操作

     1 int pop(int i){
     2      if(i<1||i>2){
     3          printf("栈号输入不对
    ");
     4          exit(0);
     5        }
     6       switch(i){
     7           case 1:
     8                  if(s.top[0]==-1){
     9                      printf("栈空
    ");
    10                      return -1;
    11                  }
    12                 else
    13                     return s.stack[s.top[0]--];
    14           calse 2;
    15                  if(s.top[1]==maxsize){
    16                      printf("栈空
    ");
    17                      return -1;
    18                  }
    19                 else
    20                     return s.stack[s.top[1]++];                 
    21     }
    22 }

          7、假设一个算数表达式中包含圆括号、方括号、花括号三种类型的括号,编写一个算法来判别表达式中的括号是否配对,以字符“”作为算数表达式的结束符。

             括号匹配是栈的一个经典应用,基本思想是扫描每个字符,遇到三种括号的左括号进栈,遇到三种括号的右括号时检查栈顶元素是否为相应的左括号,若是,退栈,否则配对错误。最后栈不为空也为错误。

     1 bool check(char *str){
     2           InitStack(S);i=1;
     3           Push(S,str[0]);
     4           while(str[i]!=''){
     5               switch(str[i]){
     6                    case '(' : Push(S,'(');break;
     7                    case '[' : Push(S,'[');break;
     8                    case '{' : Push(S,'{');break;
    
    9 case ')' : Pop(S,e): 10 if (e!='(') return false; 11  break; 12 case ']' : Pop(S,e): 13 if (e!=']') return false; 14  break; 15 case '}' : Pop(S,e): 16 if (e!='}') return false; 17 break; 18  default; 19  break; 20 } 21 i++ 22 } 23 if (! isEmpty(s)){ 24 printf("括号不匹配 "); 25 return false; 26 } 27 else{ 28 printf("括号匹配 "); 29 return true; 30 } 31 }

           8、在递归调用的过程中,系统为每一层的返回点、局部变量、传入实参等开辟了递归工作栈来进行数据存储,递归次数过多容易造成栈溢出等。而其效率不高时因为递归调用过程中包含过多重复的计算。其优点就在于代码简单,容易理解。

            利用一个栈实现以下递归函数的非递归计算:

     

         思路:设置一个栈用于保存n和对应的Pn(x)值,然后边出栈边计算Pn(x),栈空后值就计算出来了。

     1 double p(int n, double x){
     2        struct stack{
     3            int no;   //保存n
     4            double val;  //保存Pn(x)的值
     5     }st[maxsize]
     6      int top=-1,i;
     7      double fv1=1,fv2=2*x; //当n=0 和n=1时的初值
     8      for(i=n;i>=2;i--){
     9          top++;
    10          st[top].no=i
    11     }
    12      while(top>0){
    13           st[top].val=2*x*fv2-2*(st[top-1].no -1)*fv1;
    14           fv1=fv2;
    15           fv2=st[top].val
    16           top--; 
    17     }
    18     return fv2;
    19 }

    上面的这种方法 需要栈的长度至少为n,还有一种方法只需要栈的长度为3,st[2]的值是Pn(x)的值,而st[0],st[1]分别存储着Pn-2(x)和Pn-1(x)的值,这三个值会跟随递归运算而发生变化。但是这样只能得到三个结果。不能存储各个对应值。

    由于栈的内容比较简单,所以就写这些吧。

  • 相关阅读:
    springboot2.0整合logback日志(详细)
    关于Logstash中grok插件的正则表达式例子
    feign多文件上传
    HBase API(新版本)
    HBase基础知识
    Hive数据操作和数据查询
    Hive数据定义
    Hive基础知识
    Hive安装
    Spark词频统计,求TOP值,文件排序,二次排序
  • 原文地址:https://www.cnblogs.com/tracylining/p/3446435.html
Copyright © 2020-2023  润新知