栈专题(基本操作)
一、什么是栈
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=-1;
while(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];
}
总结
今天我们学习了栈的基本操作以及基本应用,而栈的另外一大应用还有递归,让我们下节再探讨栈的递归应用。