【数据结构与算法】栈

栈 Stack

  • 栈顶(Top):表尾(即 a n a_n an端)
  • 栈底(Base):表头(即 a 1 a_1 a1端)
  • 入栈(PUSH):插入元素到栈顶的操作
  • 出栈(POP):从栈顶删除最后一个元素的操作

插入只能在表尾,删除只能在表尾

后进先出(LIFO)结构

顺序栈的表示和实现

#define MAXSIZE 100
typedef struct{
    SElemTypeb *base;//栈底指针
    SElemTypeb *top;//栈顶指针
    int stacksize;//栈可用最大容量
}SqStack;

存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端。

  • 附设top指针,指示栈顶元素在顺序栈中的位置
  • 另设base指针,指示栈底元素在顺序栈中的位置

但是,为了方便操作,通常top指示真正的栈顶元素之上的下标地址

另外,用stacksize表示栈可使用的最大容量

  • 空栈:base==top
  • 栈满:top-base==stacksize

栈满时的处理方法:

  1. 报错,返回操作系统
  2. 分配更大的空间,作为栈的存储空间,将原栈的内容移入新栈

使用数组作为顺序栈存储方式的特点:简单、方便、但易产生溢出(数组大小固定)

  • 上溢(overflow):栈已经满,仍要压入元素
  • 下溢(underflow):栈已经空,仍要弹出元素

顺序栈操作的函数

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
#define Status int
#define SElemType int
#define MaxSize 100
//栈数据结构
typedef struct Stack
{
	SElemType *base;//栈底指针 不变
	SElemType *top;//栈顶指针 一直在栈顶元素上一个位置
	int stacksize;//栈可用的最大容量
}SqStack;
//**************************************基本操作函数************************************//
//初始化函数
Status InitStack(SqStack &s)
{
	s.base=new SElemType[MaxSize];//动态分配最大容量
	if(!s.base)
	{
		printf("分配失败\n");
		return 0;
	}
	s.top=s.base;//栈顶指针与栈底相同
	s.stacksize=MaxSize;
	return 1;
}
//入栈
Status Push(SqStack &s,SElemType e)
{
	if(s.top-s.base==s.stacksize) return 0;//栈满
	*(s.top++)=e;//先入栈,栈顶指针再上移
	/*
	*s.top=e;
	s.top++;
	*/
	return 1;	
}
//出栈 用e返回值
Status Pop(SqStack &s,SElemType &e)
{
	if(s.top==s.base) return 0;//栈空
	e=*--s.top;//先减减 指向栈顶元素,再给e
	/*
	--S.top;
	e=*S.top;
	*/
	return 1;	
}
//得到栈顶元素,不修改指针
bool GetTop(SqStack s,SElemType &e)
{
	if(s.top==s.base) return false;//栈空			
	else e=*--s.top;
	return true;
		
}
//顺序栈长度
Status StackLength(SqStack S){
	return S.top-S.base;
} 
//销毁顺序栈(未使用) 
Status DestroyStack(SqStack &S){
	if(S.base){
		delete S.base;
		S.stacksize=0;
		S.base=S.top=NULL;
	}
	return 1;
} 
//********************************功能实现函数**************************************//
//菜单
void menu()
{
   printf("********1.入栈      2.出栈*********\n");
   printf("********3.取栈顶    4.是否为空*****\n");
   printf("********5.栈长      6.清空*********\n");
   printf("********7.遍历      8.查找*********\n");
   printf("**************0.退出***************\n");
}
//入栈功能函数 调用Push函数
void PushToStack(SqStack &s)
{
	int n;SElemType e;int flag;
	printf("请输入入栈元素个数(>=1):\n");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
	 printf("请输入第%d个元素的值:",i+1);
	 scanf("%d",&e);
	 flag=Push(s,e);
	 if(flag)printf("%d已入栈\n",e);
	 else {printf("栈已满!!!\n");break;}
	}
}
//出栈功能函数 调用Pop函数
void PopFromStack(SqStack &s)
{
	int n;SElemType e;int flag;
	printf("请输入出栈元素个数(>=1):\n");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
	 flag=Pop(s,e);
	 if(flag)printf("%d已出栈\n",e);
	 else {printf("栈已空!!!\n");break;}
	}
}
//取栈顶功能函数 调用GetTop函数 
void GetTopOfStack(SqStack &s)
{
	SElemType e;bool flag; 
	flag=GetTop(s,e);
	if(flag)printf("栈顶元素为:%d\n",e);
	else printf("栈已空!!!\n");
}
//判断栈是否为空
void IsStackEmpty(SqStack S){
	if(S.top==S.base)
	cout<<"栈为空"<<endl;
	else
	cout<<"栈不为空"<<endl;
}
//获取栈长功能函数 调用StackLength函数 
void GetStackLength(SqStack S){
	int length=StackLength(S);
	printf("栈的长度为%d\n",length);
}
//清空顺序栈
void ClearStack(SqStack &S){
	if(S.base){
		S.top=S.base;
	}
	cout<<"栈已清空!"<<endl;
}
//遍历整个栈
void Show(SqStack &S){
	if (S.top==S.base)
		cout <<"栈为空!"<<endl;
	int* temp=S.top;	//定义一个临时指针
	while (temp!=S.base){
		SElemType e=*--temp;
		cout<<e<<" ";
	}
	cout<<endl;
}
//查找栈中的元素是否存在(存在则返回对应下标)
void find(SqStack S){
	int key,index=0,flag=0;
	cout<<"请输入您要查找的元素:"<<endl;
	cin>>key; 
	if(S.top==S.base){
		cout<<"栈为空!"<<endl;
	}
	else{
	int* temp=S.top;
	while (temp!=S.base){
		SElemType e=*--temp;
		index++;
		if(e==key){
			flag=1;
		    cout<<"此元素的位置为(自顶向下):"<<index<<endl;
		    break;
		}
	}
	if(flag==0){
		cout<<"查无此元素!"<<endl;
	}
    }
}
//主函数
int main(){
 SqStack s;int choice;
 InitStack(s);
 while(1)
 {
  menu();
  printf("请输入菜单序号:\n");
  scanf("%d",&choice);
  if(choice==0) break;
  switch(choice)
  {
  case 1:PushToStack(s);break;
  case 2:PopFromStack(s);break;
  case 3:GetTopOfStack(s);break;
  case 4:IsStackEmpty(s);break;
  case 5:GetStackLength(s);break;
  case 6:ClearStack(s);break;
  case 7:Show(s);break;
  case 8:find(s);break;
  default:printf("输入错误!!!\n");
  }
 }
 return 0;
 }

链栈的表示和实现

typedef struct StackNode{
    SElemType data;
    struct StackNode *next;
}StackNode,*LinkStack;
LinkStack S;

链栈是运算受限的单链表,只能在链表头部进行操作

注意链栈中指针的方向

  • 链表的头指针就是栈顶
  • 不需要头结点
  • 基本不存在栈满的情况
  • 空栈相当于头指针指向空
  • 插入和删除仅在栈顶处执行

链栈操作的函数

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
#define Status int
#define SElemType int
//链栈结点数据结构
typedef struct StackNode
{
	SElemType data;//数据域
	struct StackNode *next;//指针域
}StackNode,*LinkStack;
//**************************基本操作函数***************************//
//初始化函数
Status InitStack(LinkStack &S)
{
 S = NULL;//生成空栈 以单链表表头为栈顶 注意,链栈没有像链表似的头结点
 return 1;
}
//入栈函数 将e压入栈
Status Push(LinkStack &S,SElemType e)
{
	StackNode *p;
	p=new StackNode;//生成新节点
	p->data=e;      //赋值
	p->next=S;      //压入栈顶
	S=p;
	return 1;
}
//出栈函数  栈顶出栈用e返回 注意释放空间
bool Pop(LinkStack &S,SElemType &e)
{
	LinkStack p;
	if(S==NULL)return false;//栈空
	e=S->data;
	p=S;
	S=S->next;
	free(p);
	return true;
}
//取栈顶函数 用e返回
bool GetTop(LinkStack &S,SElemType &e) //严蔚敏版(人民邮电出版社) 61页有误
{
	if(S==NULL) return false;//栈顶为空
	e=S->data;
	return true;
}
//栈长 
int  lengthStack(LinkStack S){
	StackNode* p=S;
	int i=0;
	while(p){
		i++;
		p=p->next;
	}
	return i;
}
//按值查找-根据指定数据获取该数据所在的位置序号
Status LocateElem(LinkStack S,SElemType e) {
	StackNode* p=S;int j=1;
	while(p&&p->data!=e){
		p=p->next;
		j++;
	}
	if(p)
	return j;
	else
	return 0;
}

//**************************功能实现函数***************************//
//菜单
void menu()
{
   printf("********1.入栈      2.出栈*********\n");
   printf("********3.取栈顶    4.是否为空*****\n");
   printf("********5.栈长      6.清空*********\n");
   printf("********7.遍历      8.查找*********\n");
   printf("**************0.退出***************\n");
}
//入栈功能函数 调用Push函数 
void PushToStack(LinkStack &S)
{
	int n;SElemType e;int flag;
	printf("请输入入栈元素个数(>=1):\n");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
	 printf("请输入第%d个元素的值:",i+1);
	 scanf("%d",&e);
	 flag=Push(S,e);
	 if(flag)printf("%d已入栈\n",e);
	}
}
//出栈功能函数 调用Pop函数
void PopFromStack(LinkStack &S)
{
	int n;SElemType e;int flag;
	printf("请输入出栈元素个数(>=1):\n");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
	 flag=Pop(S,e);
	 if(flag)printf("%d已出栈\n",e);
	 else {printf("栈已空!!!\n");break;}
	}
}
//取栈顶功能函数 调用GetTop函数
void GetTopOfStack(LinkStack S)
{
	SElemType e;bool flag; 
	flag=GetTop(S,e);
	if(flag)printf("栈顶元素为:%d\n",e);
	else printf("栈已空!!!\n");
}
//判断栈是否为空
void IsStackEmpty(LinkStack S){
	if(S==NULL) cout<<"栈为空!"<<endl;
	else cout<<"栈不为空!"<<endl;
}
//取栈长功能函数
void LengthStack(LinkStack S){
	int len=lengthStack(S);
	if(len) cout<<"栈长为"<<len<<endl;
	else cout<<"栈为空!"<<endl;
}
//遍历栈 
void PrintStack(LinkStack S)
{
	LinkStack p=S;
	if(lengthStack(S))
	{
		cout<<"当前栈所有元素(自顶向下):"<<endl;
		while(p)
		{
			cout<<p->data<<" ";
			p=p->next;
		}
		cout<<endl;
	}
	else
	{
		cout<<"栈已空!"<<endl;
	}
}
//清空栈 
void ClearStack(LinkStack &S){
	StackNode *p,*q;
	p=S->next;
	while(p){
		q=p->next;
		delete p;
		p=q;
	}
	S=NULL;
	PrintStack(S);
}
//查找 
void Search(LinkStack S)
{
  SElemType e;int q;
  cout<<"请输入要查找的值:"<<endl;
  cin>>e;
  q=LocateElem(S,e);
  if(q) 
  {
	cout<<"找到该元素!该元素的位置(自顶向下)是"<<q<<endl;
  }
  else
	cout<<"未找到该元素!"<<endl;
}

//主函数
int main()
{
 LinkStack S;int choice;
 InitStack(S);
 while(1)
 {
  menu();
  printf("请输入菜单序号:\n");
  scanf("%d",&choice);
  if(choice==0) break;
  switch(choice)
  {
  case 1:PushToStack(S);break;
  case 2:PopFromStack(S);break;
  case 3:GetTopOfStack(S);break;
  case 4:IsStackEmpty(S);break;
  case 5:LengthStack(S);break;
  case 6:ClearStack(S);break;
  case 7:PrintStack(S);break;
  case 8:Search(S);break;
  default:printf("输入错误!!!\n");
  }
 }
 return 0;
}

栈与递归

【数据结构与算法】递归

函数调用过程

调用前,系统完成:

  1. 将实参,返回地址等传递给被调用函数
  2. 为被调用函数的局部变量分配存储区
  3. 将控制转移到被调用函数的入口

调用后,系统完成:

  1. 保存被调用函数的计算结果
  2. 释放被调用函数的数据区
  3. 依照被调用函数保存的返回地址将控制转移到调用函数
#include<stdio.h>
void fun1(int n){
	if(n!=0){
		printf("%d\n",n);
		fun1(n-1);
	}
} 
void fun2(int n){
	if(n!=0){
		fun2(n-1);
		printf("%d\n",n);
	}
}
int main(){
	fun1(6);
	printf("\n");
	fun2(6);
	return 0;
}

栈与卡特兰数

卡特兰数(Catalan Number)

【数学】卡特兰数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值