数据结构学习笔记之栈

     栈(stack)  是限定仅在表尾进行插入或删除操作的线性表。因此,对栈来说,表尾端有其特殊含义,称为栈项(top),相应地,表头端称为栈底(bottom)。不含元素的空表称为空栈。

     栈有两种存储表示方法:顺序栈和链栈。顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。通常的习惯做法是以top=0表示空栈,鉴于C语言中数组的下标约定从0开始,则当以C作描述语言时,如此设定会带来很大不便;另一方面,由于栈在使用过程中所需最大空间的大小很难估计,因此,一般来说,在初始化设空栈时不应限定栈的最大容量。一个较合理的做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。为此,可设定两个常量:STACK_INIT_SIZE(存储空间初始分配量)和STACKINCREMENT(存储空间分配增量),并以下述类型说明作为顺序栈的定义。

typedef struct {

        SElemType    *base;

        SElemType     *top;

         int    stacksize;

}SqStack;

其中,stacksize指示栈的当前可使用的最大容量。栈的初始化操作为:按设定的初始分配量进行第一次存储分配,base可称为栈底指针,在顺序栈中,它始终指向栈底的位置,若base的值为NULL,则表明栈结构不存在。称top为栈顶指针,其初值指向栈底,即top=base可作为栈空的标记,每当插入新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。图1展示了顺序栈中数据元素和栈顶指针之间的对应关系。

                                                                                              图1 栈顶指针和栈中元素之间的关系      

栈的应用举例 

       由于栈结构具有后进先出的固有特性,致使栈成为程序设计中的有用工具。下面将讨论几个栈应用的典型例子。

1、数制转换

       十进制数N和其他d进制数的转换是计算机实现计算的基本问题,其解决方法很多其中一个简单算法基于下列原理:

        N = (N div d)*d+N mod d (其中:div为整除运算,mod为求余运算)

        例如:(1348)10 = (2504)8 ,其运算过程如下:

                                                                                  N                                  N div 8                                 N mod 8

                                                                                 1348                                 168                                       4

                                                                                  168                                    21                                        0

                                                                                   21                                       2                                         5

                                                                                   2                                          0                                        2

         假设现要编制一个满足下列要求的程序:对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数。由于上述计算过程是从低位到高位顺序产生八进制数的各个数位,而打印输出,一般来说应从高位到低位进行,恰好和计算过程相反。因此,若将计算过程中得到的八进制数的各位顺序进栈,则按出栈序列打印输出的即为与输入对应的八进制数。 这是利用栈后进先出特性的最简单例子。在这个例子中,栈操作的序列是直线式的,即先一味地入栈,然后一味地出栈。

#include<stdio.h>
#include <malloc.h>
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;

#define STACK_INIT_SIZE 10
#define STACKINCREMENT 2

typedef struct{
	int *base;              //
	int *top;
	int stacksize;
}SqStack;
Status InitStack(SqStack *S)
{
	/* 构造一个空栈S */
	(*S).base = (int*)malloc(STACK_INIT_SIZE*sizeof(int));
	if(!(*S).base)
		exit(OVERFLOW);      /* 存储分配失败 */
	(*S).top = (*S).base;
	(*S).stacksize = STACK_INIT_SIZE;
	return OK;
}
Status DestroyStack(SqStack *S)
{
	/*销毁栈S,S不再存在*/
	free((*S).base);
	(*S).base = NULL;
	(*S).top = NULL;
	(*S).stacksize = 0;
	return OK;

}
Status ClearStack(SqStack *S)
{
	/* 把S置为空栈 */
	(*S).top = (*S).base;
	return OK;
}
Status StackEmpty(SqStack S)
{
/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
	if(S.top==S.base)
		return TRUE;
	else
		return FALSE;
}
int StackLength(SqStack S)
{
	/* 返回S的元素个数,即栈的长度 */
	return S.top-S.base;
}

Status GetTop(SqStack S,int *e)
{
	/* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
	if(S.top>S.base)
	{
		*e = *(S.top-1);
		return OK;
	}
	else
		return ERROR;
}
Status Push(SqStack *S,int e)
{
	if((*S).top-(*S).base>=(*S).stacksize)/*栈满,追加存储空间*/
	{
		(*S).base = (int *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(int));
		if(!(*S).base)
			exit(OVERFLOW);
		(*S).top = (*S).base + (*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++=e;
	return OK;
}
Status Pop(SqStack *S,int *e)
{
	/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
   if((*S).top==(*S).base)
	   return ERROR;
   *e=*--(*S).top;
   return OK;
}
Status StackTraverse(SqStack S,Status (*visit)(int))
{
	/* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */
	/* 一旦visit()失败,则操作失败 */
	while(S.top>S.base)
		visit(*S.base++);
	printf("\n");
	return OK;
}
 void conversion() /* 算法3.1 */
 { /* 对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数 */
   SqStack s;
   unsigned n; /* 非负整数 */
   int e;
   InitStack(&s); /* 初始化栈 */
   printf("n(>=0)=");
   scanf("%u",&n); /* 输入非负十进制整数n */
   while(n) /* 当n不等于0 */
   {
     Push(&s,n%8); /* 入栈n除以8的余数(8进制的低位) */
     n=n/8;
   }
   while(!StackEmpty(s)) /* 当栈不空 */
   {
     Pop(&s,&e); /* 弹出栈顶元素且赋值给e */
     printf("%d",e); /* 输出e */
   }
   printf("\n");
 }
void main()
{
	conversion();
}
2、括号匹配的检验

//括号匹配代码
#include<stdio.h>
#include <malloc.h>
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;

#define STACK_INIT_SIZE 10
#define STACKINCREMENT 2

typedef struct{
	char *base;              //
	char *top;
	int stacksize;
}SqStack;
Status InitStack(SqStack *S)
{
	/* 构造一个空栈S */
	(*S).base = (char*)malloc(STACK_INIT_SIZE*sizeof(char));
	if(!(*S).base)
		exit(OVERFLOW);      /* 存储分配失败 */
	(*S).top = (*S).base;
	(*S).stacksize = STACK_INIT_SIZE;
	return OK;
}
Status DestroyStack(SqStack *S)
{
	/*销毁栈S,S不再存在*/
	free((*S).base);
	(*S).base = NULL;
	(*S).top = NULL;
	(*S).stacksize = 0;
	return OK;

}
Status ClearStack(SqStack *S)
{
	/* 把S置为空栈 */
	(*S).top = (*S).base;
	return OK;
}
Status StackEmpty(SqStack S)
{
/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
	if(S.top==S.base)
		return TRUE;
	else
		return FALSE;
}
int StackLength(SqStack S)
{
	/* 返回S的元素个数,即栈的长度 */
	return S.top-S.base;
}

Status GetTop(SqStack S,char *e)
{
	/* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
	if(S.top>S.base)
	{
		*e = *(S.top-1);
		return OK;
	}
	else
		return ERROR;
}
Status Push(SqStack *S,char e)
{
	if((*S).top-(*S).base>=(*S).stacksize)/*栈满,追加存储空间*/
	{
		(*S).base = (char *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(char));
		if(!(*S).base)
			exit(OVERFLOW);
		(*S).top = (*S).base + (*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++=e;
	return OK;
}
Status Pop(SqStack *S,char *e)
{
	/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
   if((*S).top==(*S).base)
	   return ERROR;
   *e=*--(*S).top;
   return OK;
}
Status StackTraverse(SqStack S,Status (*visit)(char))
{
	/* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */
	/* 一旦visit()失败,则操作失败 */
	while(S.top>S.base)
		visit(*S.base++);
	printf("\n");
	return OK;
}
Status bracket_match() /* 算法3.1 */
 {
	 SqStack ss;
	 char input[16],*temp,c;
	 //char test[11];
	 InitStack(&ss);
	 gets(input);
	 temp = input;
	 while(*temp)
	 {
		 switch(*temp)
		 {
		 case '(':
		 case '[':Push(&ss,*temp++);
			      break;
		 case ')':
		 case ']':if(!StackEmpty(ss))
				  {
					  Pop(&ss,&c);
					  if(*temp == ')'&& c != '(' || *temp == ']' && c != '[')
					  {
						  printf("左右括号不配对\n");
						  exit(ERROR);
					  }
					  else
					  {
						  temp++;
						  break;
					  }
				  }
				  else
				  {
					  printf("缺乏左括号\n");
					  exit(ERROR);
				  }
		 default:temp++;
		 }
	 }
	 if(StackEmpty(ss))
			 printf("括号匹配\n");
		 else
			 printf("括号不匹配\n");
 }
void main()
{
	bracket_match();
}

3、表达式求值

 /* algo3-6.c 表达式求值(输入、输出和中间结果均只能是0~9) */
#include<stdio.h>
#include <malloc.h>
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char SElemType;

#define STACK_INIT_SIZE 10
#define STACKINCREMENT 2

typedef struct{
	SElemType *base;              //
	SElemType *top;
	int stacksize;
}SqStack;
Status InitStack(SqStack *S)
{
	/* 构造一个空栈S */
	(*S).base = (SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
	if(!(*S).base)
		exit(OVERFLOW);      /* 存储分配失败 */
	(*S).top = (*S).base;
	(*S).stacksize = STACK_INIT_SIZE;
	return OK;
}
Status DestroyStack(SqStack *S)
{
	/*销毁栈S,S不再存在*/
	free((*S).base);
	(*S).base = NULL;
	(*S).top = NULL;
	(*S).stacksize = 0;
	return OK;

}
Status ClearStack(SqStack *S)
{
	/* 把S置为空栈 */
	(*S).top = (*S).base;
	return OK;
}
Status StackEmpty(SqStack S)
{
/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
	if(S.top==S.base)
		return TRUE;
	else
		return FALSE;
}
int StackLength(SqStack S)
{
	/* 返回S的元素个数,即栈的长度 */
	return S.top-S.base;
}

Status GetTop(SqStack S,SElemType *e)
{
	/* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
	if(S.top>S.base)
	{
		*e = *(S.top-1);
		return OK;
	}
	else
		return ERROR;
}
Status Push(SqStack *S,SElemType e)
{
	if((*S).top-(*S).base>=(*S).stacksize)/*栈满,追加存储空间*/
	{
		(*S).base = (SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));
		if(!(*S).base)
			exit(OVERFLOW);
		(*S).top = (*S).base + (*S).stacksize;
		(*S).stacksize += STACKINCREMENT;
	}
	*((*S).top)++=e;
	return OK;
}
Status Pop(SqStack *S,SElemType *e)
{
	/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
   if((*S).top==(*S).base)
	   return ERROR;
   *e=*--(*S).top;
   return OK;
}
Status StackTraverse(SqStack S,Status (*visit)(SElemType))
{
	/* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */
	/* 一旦visit()失败,则操作失败 */
	while(S.top>S.base)
		visit(*S.base++);
	printf("\n");
	return OK;
}

 SElemType Precede(SElemType t1,SElemType t2)
 { /* 根据教科书表3.1,判断两符号的优先关系 */
   SElemType f;
   switch(t2)
   {
     case '+':
     case '-':if(t1=='('||t1=='#')
                f='<';
              else
                f='>';
              break;
     case '*':
     case '/':if(t1=='*'||t1=='/'||t1==')')
                f='>';
              else
                f='<';
              break;
     case '(':if(t1==')')
              {
                printf("ERROR1\n");
                exit(ERROR);
              }
              else
                f='<';
              break;
     case ')':switch(t1)
              {
                case '(':f='=';
                         break;
                case '#':printf("ERROR2\n");
                         exit(ERROR);
                default: f='>';
              }
              break;
     case '#':switch(t1)
              {
                case '#':f='=';
                         break;
                case '(':printf("ERROR3\n");
                         exit(ERROR);
                default: f='>';
              }
   }
   return f;
 }

 Status In(SElemType c)
 { /* 判断c是否为运算符 */
   switch(c)
   {
     case'+':
     case'-':
     case'*':
     case'/':
     case'(':
     case')':
     case'#':return TRUE;
     default:return FALSE;
   }
 }

 SElemType Operate(SElemType a,SElemType theta,SElemType b)
 {
   SElemType c;
   a=a-48;
   b=b-48;
   switch(theta)
   {
     case'+':c=a+b+48;
             break;
     case'-':c=a-b+48;
             break;
     case'*':c=a*b+48;
             break;
     case'/':c=a/b+48;
   }
   return c;
 }

  SElemType EvaluateExpression() /* 算法3.4 */
 { /* 算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈 */
   SqStack OPTR,OPND;
   SElemType a,b,c,x,theta;
   InitStack(&OPTR);
   Push(&OPTR,'#');
   InitStack(&OPND);
   c=getchar();
   GetTop(OPTR,&x);
   while(c!='#'||x!='#')
   {
     if(In(c)) /* 是7种运算符之一 */
       switch(Precede(x,c))
       {
         case'<':Push(&OPTR,c); /* 栈顶元素优先权低 */
                 c=getchar();
                 break;
         case'=':Pop(&OPTR,&x); /* 脱括号并接收下一字符 */
                 c=getchar();
                 break;
         case'>':Pop(&OPTR,&theta); /* 退栈并将运算结果入栈 */
		 Pop(&OPND,&b);
                 Pop(&OPND,&a);
                 Push(&OPND,Operate(a,theta,b));
                 break;
       }
     else if(c>='0'&&c<='9') /* c是操作数 */
     {
       Push(&OPND,c);
       c=getchar();
     }
     else /* c是非法字符 */
     {
       printf("ERROR4\n");
       exit(ERROR);
     }
     GetTop(OPTR,&x);
   }
   GetTop(OPND,&x);
   return x;
 }

 void main()
 {
   printf("请输入算术表达式(中间值及最终结果要在0~9之间),并以#结束\n");
   printf("%c\n",EvaluateExpression());
 }


以上内容文字部分摘自严蔚敏版《数据结构(C语言版)》,程序代码为本人整理,仅供个人学习使用,勿作它用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于学习数据结构C语言笔记,我可以给你一些基本的指导和概念。数据结构是计算机科学中非常重要的一门课程,它涉及存储和组织数据的方法。C语言是一种常用的编程语言,很适合用于实现各种数据结构。 下面是一些数据结构的基本概念,你可以在学习笔记中包含它们: 1. 数组(Array):一种线性数据结构,可以存储相同类型的元素。在C语言中,数组是通过索引访问的。 2. 链表(Linked List):也是一种线性数据结构,但不需要连续的内存空间。链表由节点组成,每个节点包含数据和指向下一个节点的指针。 3. (Stack):一种后进先出(LIFO)的数据结构,类似于装满物品的箱子。在C语言中,可以使用数组或链表来实现。 4. 队列(Queue):一种先进先出(FIFO)的数据结构,类似于排队等候的队伍。同样可以使用数组或链表来实现队列。 5. 树(Tree):一种非线性数据结构,由节点和边组成。每个节点可以有多个子节点。二叉树是一种特殊的树结构,每个节点最多有两个子节点。 6. 图(Graph):另一种非线性数据结构,由节点和边组成。图可以用来表示各种实际问题,如社交网络和地图。 这只是数据结构中的一些基本概念,还有其他更高级的数据结构,如堆、哈希表和二叉搜索树等。在学习笔记中,你可以介绍每个数据结构的定义、操作以及适合使用它们的场景。 希望这些信息对你有所帮助!如果你有任何进一步的问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值