数据结构——栈(1)

栈专题(基本操作)



一、什么是栈

1.定义

栈是一种特殊的线性表,满足线性表的特点(特殊性:FILO先进后出

2.结构

(1)栈顶开口,栈底封口:无论出栈还是入栈,都必须在栈顶完成操作;栈底不可以出栈。
(2)特殊性:结构特殊➡️操作特殊。

栈顶指针:指向栈顶元素的指针(top指向最后一个入栈的元素),栈顶指针是动态的,不是指向栈顶位置。

在这里插入图片描述

3.栈的操作

(1)空栈:栈中没有存放任何数据元素(top==-1)。
(2)入栈(push):
栈满条件: top==MaxSize-1;(不可入栈,否则上溢)
在这里插入图片描述
(2)出栈(pop):
出栈运算:top–;
在这里插入图片描述

4.栈中元素:

(1)一切看top位置
(2)栈空间只决定栈中可以存放多少数据元素
(3)栈顶元素不出栈,其他元素无法出栈
(4)读栈顶元素:s[top]

//入栈操作
top=-1while(top-(MaxSize-1){
	s[++top]=入栈元素;
}
//出栈操作
while(top!=-1){
	s[top--];
}

二、栈的算法应用(一)

1.栈的结构应用——浪费空间换取时间效率。

例:设head指向一个非空单向链表,将单向链表所有结点数值逆向输出
(1)方案一

void PrintLink(ElemSN *h){
	ElemSN *end=NULL,*p,*h;
	while(end-h){
		for(p=h;p->next-end;p=p->next){
			printf("%d",p->data);
			end=p;
		}
	}
}

(2)方案二:用栈FILO

方案一中我们可以发现时间复杂度是O(n²),空间复杂度是O(1),而我们刚学的栈,就是浪费空间来换取时间效率,同时栈的特点还是先进后出,可以达到我们题目的逆序输出,所以我们可以尝试用栈来解决。

void PopPrintLint(ElemSN *h){
	int *s;
	int top=-1;
	ElemSN *p;
	//申请栈空间
	s=(int *)malloc(100*sizeof(int));
	//将链表所有数据压到栈中
	for(p=h;p&&s[++top]=p->data;p=p->next);
	//出栈输出打印数值
	while(top!=-1){
		printf("%5d",s[top--]);
	}
	//将栈所占空间释放
	free(s);
}

而我们又想到,如果数据类型过于复杂,我们直接在栈中存数据就会有麻烦,所以我们可以用栈来存放地址,解决这一问题。
地址的类型是ElemSN *,所以栈的类型就是ElemSN **

void PopPrintLint(ElemSN *h){
	ElemSN **s,*p;
	int top=-1;
	//申请栈空间
	s=(ElemSN **)malloc(100*sizeof(ElemSN *));
	//将链表所有数据的地址压到栈中
	for(p=h;p&&s[++top]=p;p=p->next);
	//出栈输出打印数值
	while(top!=-1){
		p=s[top--];
		printf("%5d",p->next);
	}
	//将栈所占空间释放
	free(s);
}

2.判断两个非空单向链表是否存在公共交点

在这里插入图片描述

分析:1和2,我们在之前链表是否带环问题中也分析过,1和2都有两个后继,地址没办法存放,所以1和2是不存在的,所以若两条单向链表存在公共交点,只可能是3。

例:
在这里插入图片描述
(1)方案一:

分析:设置cut=L1-L2,
(1)统计h1结点数cut++,减去h2的结点数cut–;
(2)长链表跑(cut-1)个结点;
(3)两个链表再同时跑,当结点相同时,即找到公共点。

ElemSN *FindGGD(ElemSN *h1,ElemSN *h2){
	ElemSN *p1,*p2;
	int cut=0;
	for(p1=h1;p1&&(cut++);p1=p1->next);
	for(p2=h2;p2&&(cut--);p2=p2->next);
	for(p1=h1;(cut-1)--;p1=p1->next);
	for(p2=h2;p1&&p1-p2;p1=p1->next,p2=p2->next);
	return p1;
}

(2)方案二:
在这里插入图片描述

用栈s1,s2先全部将两个链表的元素地址入栈(push),然后输出(pop),在出栈的时候判断是否是同一结点。

ElemSN *FindPublic(ElemSN *h1,ElemSN *h2){
	ElemSN **s1;
	ElemSN **s2;
	int top1=top2=-1;
	ElemSN *p1,*p2;
	//申请栈空间
	s1=(ElemSN **)malloc(100*sizeof(ElemSN *));
	s2=(ElemSN **)malloc(100*sizeof(ElemSN *));
	//h1入栈
	for(p1=h1;s[++top1]=p1;p1->next);
	//h2入栈
	for(p2=h2;s[++top2]=p2;p2->next);
	//h1,h2同时出栈,并且比较有无公共结点
	for(;top1!=-1&&top2!=-1&&(s1[top1]-s2[top2]);top1--,top2--);
	return s1[top1];
}



总结

今天我们学习了栈的基本操作以及基本应用,而栈的另外一大应用还有递归,让我们下节再探讨栈的递归应用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值