定义
栈是一种受限的线性表,栈的逻辑结构任然是一对一的关系,但只能在栈顶进行插入和删除
特点:是先进去的最后出来
栈的顺序存储结构
初始化的时候栈顶指针指向-1
//栈
//顺序栈:此时top 指向 -1
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 20
typedef struct{
int data[MaxSize];//存储栈元素
int top;//栈顶指针:指向栈顶的
}SqStack;
//初始化
bool InitStack(SqStack &s){
s.top = -1;
return true;
}
//判断栈是否为空
bool StackEmpty(SqStack s){
if(s.top == -1){
return true;
}else{
return false;
}
}
//进栈
bool Push(SqStack &s,int e){
if(s.top == MaxSize - 1){
return false;
}
s.top += 1;
s.data[s.top] = e;
return true;
}
//读取栈顶元素
bool GetTop(SqStack s,int &e){
if(s.top == -1){
return false;
}
e = s.data[s.top];
return true;
}
//出栈
bool Pop(SqStack &s,int &e){
if(s.top == -1){
return false;
}
e = s.data[s.top];
s.top -= 1;
return true;
}
int main(){
SqStack s;
int e;
int e1;
int e2;
if(InitStack(s)){
printf("初始化成功\n");
printf("请输入,入栈元素:");
scanf("%d",&e);
if(Push(s,e)){
printf("添加成功\n");
}else{
printf("添加失败\n");
}
if(GetTop(s,e2)){
printf("删除成功,此时的删除的元素为:%d\n",e2);
}
if(Pop(s,e2))
if(StackEmpty(s)){
printf("此时栈为空");
}else{
printf("此时栈不为空");
}
}
return 0;
}
初始化的时候栈顶指针指向0
//栈
//顺序栈:此时top 指向 0
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 20
typedef struct{
int data[MaxSize];//存储栈元素
int top;//栈顶指针:指向栈顶的
}SqStack;
//初始化
bool InitStack(SqStack &s){
s.top = 0;
return true;
}
//判断栈是否为空
bool StackEmpty(SqStack s){
if(s.top == 0){
return true;
}else{
return false;
}
}
//进栈
bool Push(SqStack &s,int e){
if(s.top == MaxSize){
return false;
}
s.data[s.top] = e;
s.top += 1;
return true;
}
//读取栈顶元素
bool GetTop(SqStack s,int &e){
if(s.top == 0){
return false;
}
e = s.data[s.top - 1];
return true;
}
//出栈
bool Pop(SqStack &s,int &e){
if(s.top == 0){
return false;
}
s.top -= 1;
e = s.data[s.top];
return true;
}
int main(){
SqStack s;
int e;
int e1;
int e2;
if(InitStack(s)){
printf("初始化成功\n");
printf("请输入,入栈元素:");
scanf("%d",&e);
if(Push(s,e)){
printf("添加成功\n");
}else{
printf("添加失败\n");
}
if(GetTop(s,e2)){
}
if(Pop(s,e2)){
printf("删除成功,此时的删除的元素为:%d\n",e2);
}
if(StackEmpty(s)){
printf("此时栈为空");
}else{
printf("此时栈不为空");
}
}
return 0;
}
共享栈
出现的背景:一个栈我们必须提前声明她的空间大小,当对于两个相同类型的栈,我们却可以做到最大限度地利用空间,思路:是在数组的两端,向中间靠拢
//共享栈
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 20
typedef struct{
int data[MaxSize];
int top1;//栈1的栈顶指针
int top2;//栈2的栈顶指针
}SqStack;
//初始化
bool InitSqStack(SqStack &s){
s.top1 = -1;
s.top2 = MaxSize;
}
int main(){
SqStack s;
return 0;
}
//栈满的:s.top2 - s.top1 = 1
栈的顺序存储的应用
十进制转二进制
#include <stdio.h>
#define MaxSize 20
typedef struct{
int data[MaxSize];
int top;
}Stack;
//初始化
bool InitStack(Stack &s){
s.top = -1;
return true;
}
//入栈
bool push(Stack &s,int e){
if(s.top == MaxSize - 1){
return false;
}
s.top += 1;
s.data[s.top] = e;
return true;
}
//出栈
bool pop(Stack &s,int &e){
if(s.top == -1){
return false;
}
e = s.data[s.top];
s.top -= 1;
return true;
}
//显示栈中的元素
int StackPrint(Stack s){
if(s.top == -1){
return 0;
}
while(s.top != -1){
printf("%d",s.data[s.top]);
s.top -= 1;
}
}
int main(){
Stack s;
int sum;
int e,i;
if(InitStack(s)){
printf("初始化成功\n");
printf("请输入一个十进制的数:");
scanf("%d",&sum);
while(sum){
e = sum % 2;//辗转相除法
push(s,e);//余数进栈
sum = sum / 2;
}
printf("对应的二进制:");
StackPrint(s);
}
return 0;
}
回文数
//顺序栈的实际应用
//判断是否为回文数:1221,12321
#include <stdio.h>
#define MaxSize 20
typedef struct{
int data[MaxSize];
int top;
}Stack;
//初始化
bool InitStack(Stack &s){
s.top = -1;
return true;
}
//入栈
bool push(Stack &s,int e){
if(s.top == MaxSize - 1){
return false;
}
s.top += 1;//因为数组下标从0开始,而开始指针指向-1所以要+1
s.data[s.top] = e;
return true;
}
bool pop(Stack &s,int &e){
if(s.top == -1){
return false;
}
e = s.data[s.top];
s.top -= 1;
return true;
}
int main(){
Stack s;
int sum;//回文数的个数
int team[MaxSize];
int i,e;
int temp = 0;
if(InitStack(s)){
printf("初始化成功\n");
printf("请输入回文数的个数:");
scanf("%d",&sum);
printf("请输入:");
for(i = 0;i < sum;i ++){
scanf("%d",&team[i]);
}
for(i = 0;i < sum / 2;i ++){//一半的元素进栈
push(s,team[i]);//入栈
}
if(sum % 2 == 0){
i = 0;
while(i < sum / 2){
pop(s,e);
if(e != team[sum / 2 + i]){
temp = 1;
}
i ++;
}
}
else{
i = 0;
while(i < sum / 2){
pop(s,e);
if(e != team[sum / 2 + i + 1]){
temp = 1;
}
i ++;
}
}
if(temp == 1){
printf("不是回文数");
}else{
printf("是");
}
}
return 0;
}
栈的链式存储结构
对于链栈来说,不存在栈满的情况,除非内存已经没有可以使用的内存
带头结点
L1结点入栈
L2入栈
我们发现这个S结点并没有存放数据那就是头结点
#include <stdio.h>
#include <stdlib.h>
//带有头结点的链栈
typedef struct StackNode{
int data;
struct StackNode *next;//我们会发现这个定义和单链表的定义是一样的
}StackNode,*LinkStackPtr;
//初始化
bool InitStack(LinkStackPtr &s){
s = (StackNode *)malloc(sizeof(StackNode));
if(!s){
return false;
}
s->next = NULL;//带有头结点的链栈
return true;
}
//进栈
bool push(LinkStackPtr &s,int e){
StackNode *L = NULL;
L = (StackNode *)malloc(sizeof(StackNode));
if(L == NULL){
return false;
}
L->next=NULL;//将新入栈的结点的指针域设为空
L->data = e;//将元素添加到申请的结点的数据域中
L->next = s->next;//将新添加的栈元素放到栈顶那他的指针域就存放下一个结点
s->next =L; //将栈顶指针指向栈顶元素
return true;
}
//出栈
bool pop(LinkStackPtr &s,int &e){
StackNode *p = NULL;
if(s->next == NULL){
return false;
}
p=s->next;//将s所指向的结点让p也指向他
e=p->data;
s->next = p->next;
free(p);
return true;
}
//打印栈元素
int StackPrint(LinkStackPtr s){
StackNode *p = NULL;
if(s->next == NULL){
return 0;
}
p = s->next;
while(p != NULL){
printf("元素:%d\t",p->data);
p=p->next;
}
}
int main(){
LinkStackPtr s;
int e;
int i;
if(InitStack(s)){
printf("初始化成功\n");
for(i = 0;i < 4;i ++){
printf("请输入入栈元素:");
scanf("%d",&e);
if(push(s,e)){
printf("入栈成功\n");
}
}
for(i = 0;i < 4;i ++){
pop(s,e);
printf("出栈:%d\t",e);
}
if(StackPrint(s) == 0){
printf("链栈为空\n");
}else{
StackPrint(s);
}
}
return 0;
}
不带头结点
#include <stdio.h>
#include <stdlib.h>
//不带头结点的链栈
typedef struct StackNode{
int data;
struct StackNode *next;
}StackNode,*LinkStack;
//初始化
bool InitStack(LinkStack &s){
s = NULL;
return true;
}
//入栈
bool push(LinkStack &s,int e){
StackNode *L = NULL;
L = (StackNode *)malloc(sizeof(StackNode));
if(L == NULL){
return false;
}
L->data = e;
L->next = s;
s = L;//栈顶指针指向栈顶元素
return true;
}
//出栈
bool pop(LinkStack &s,int &e){
if(s == NULL){
return false;
}
StackNode *p = NULL;
p = s;
e = p->data;
s = p->next;
free(p);
return true;
}
//打印栈中所有元素
int StackPrint(LinkStack s){
if(s == NULL){
return 0;
}
StackNode *p = NULL;
p = s;
while(p != NULL){
printf("%d\t",p->data);
p = p->next;
}
}
int main(){
LinkStack s;
int e;
if(InitStack(s)){
printf("初始化成功\n");
printf("请输入要入栈的元素:\n");
scanf("%d",&e);
if(push(s,e)){
printf("入栈成功\n");
}
if(pop(s,e)){
printf("出栈元素:%d\t",e);
}
if(StackPrint(s)){
StackPrint(s);
}
}
return 0;
}
总结
链栈和顺序栈:
时间复杂度:都为O(1)
空间复杂度:顺序栈需要提前分配空间,而链栈就比较灵活了通过指针可以有效利用内存中的空间
使用:当栈长度不固定使用链栈,当栈长度固定使用顺序栈