目录
前言
我们之前已经学习过线性表,栈(stack)和队列(queue)也属于线性表,只不过他们两个都是特殊的线性表;
栈和队列是特殊的线性表,除它两的特殊点之外,其余操作和特性都与普通线性表相似,在学习栈和队列之前,我们可以先复习线性表
1.栈
栈(stack)是仅限在表尾进行插入和删除操作的线性表,可分为顺序栈和链栈
(1)顺序栈
顾名思义,顺序栈就是线性表的顺序储存结构,只不过他的插入和删除只能在表尾进行;
我们吧允许进行插入和删除的一端称为栈顶(top),另一端称为栈底(base)不含任何数据元素的栈称为空栈
1.栈的结构定义
#include<stdio.h>
#include<stdbool.h> //bool(布尔类型的头文件)
#define stacksize 200 //定义数组大小为20
typedef bool Status; //表示状态
typedef int Elemtype; //int类型别名
typedef struct {
Elemtype data[stacksize]; //数据域
Elemtype top; //栈顶指针
}My_Stack;
2.元素访问
void visit(Elemtype e) //访问栈中的元素
{
printf("%d ", e);
}
3.初始化栈
Status initstack(My_Stack *s) //初始化栈
{
//这里没有给data申请空间建应该是因为数组的大小已经定义完成
s -> top = -1;
return true;
}
4.判断栈是否为空
Status stackempty(My_Stack s) //判断栈是否为空
{
if(s.top == -1)
return true;
else
return false;
}
5.清空栈
Status ClearStack(My_Stack *s) //将栈清空
{
s -> top = -1;
return true;
}
6.计算栈中元素的个数
Elemtype length(My_Stack s) //计算栈中元素的个数
{
return s.top + 1;
}
7.获得栈顶元素
Status getTop(My_Stack s, Elemtype *e) //获得栈顶元素
{
if(s.top == -1)
return false;
else
*e = s.data[s.top];
return true;
}
8.进栈操作Push
Status push(My_Stack *s, Elemtype e) //元素e入栈
{
if(s -> top == stacksize - 1)
return false;
else
{
s -> top++; //栈顶指针加一
s -> data[s -> top] = e; //将新元素赋给栈顶元素,新插入的元素进栈 ,
return true;
}
}
没有涉及循环语句,时间复杂度为O(1)
9.出栈操作Pop
Status pop(My_Stack *s, Elemtype *e) //栈顶元素出栈
{
if(s -> top == -1)
return false;
else
{
*e = s -> data[s -> top];
s -> top--; //栈顶指针减一
return true;
}
}
}
没有涉及循环语句,时间复杂度为O(1)
10.遍历栈中元素并进行打印
Status traverse(My_Stack s) //遍历栈中元素并进行打印
{
int i = 0;
while(i <= s.top)
visit(s.data[i++]);
printf("\n");
}
11.顺序栈完整代码示例
#include<stdio.h>
#include<stdbool.h> //bool(布尔类型的头文件)
#define stacksize 200 //定义数组大小为20
typedef bool Status; //表示状态
typedef int Elemtype; //int类型别名
typedef struct
{
Elemtype data[stacksize]; //数据域
Elemtype top; //栈顶指针
}My_Stack;
void visit(Elemtype e) //访问栈中的元素
{
printf("%d ", e);
}
Status initstack(My_Stack *s) //初始化栈
{
//这里没有给data申请空间建应该是因为数组的大小已经定义完成
s -> top = -1;
return true;
}
Status stackempty(My_Stack s) //判断栈是否为空
{
if(s.top == -1)
return true;
else
return false;
}
Status ClearStack(My_Stack *s) //将栈清空
{
s -> top = -1;
return true;
}
Elemtype length(My_Stack s) //计算栈中元素的个数
{
return s.top + 1;
}
Status getTop(My_Stack s, Elemtype *e) //获得栈顶元素
{
if(s.top == -1)
return false;
else
*e = s.data[s.top];
return true;
}
Status push(My_Stack *s, Elemtype e) //元素e入栈
{
if(s -> top == stacksize - 1)
return false;
else
{
s -> top++; //栈顶指针加一
s -> data[s -> top] = e; //将新元素赋给栈顶元素,新插入的元素进栈 ,
return true;
}
}
Status traverse(My_Stack s) //遍历栈中元素并进行打印
{
int i = 0;
while(i <= s.top)
visit(s.data[i++]);
printf("\n");
return true;
}
Status pop(My_Stack *s, Elemtype *e) //栈顶元素出栈
{
if(s -> top == -1)
return false;
else
{
*e = s -> data[s -> top];
s -> top--; //栈顶指针减一
return true;
}
}
int main()
{
My_Stack s;
int j, e;
initstack(&s);
for(j = 1;j <= 150;j+=10)
push(&s, j);
puts("进栈之后的元素依次为: ");
traverse(s);
pop(&s, &e);
printf("\n");
printf("弹出的栈顶元素为 %d \n\n", e);
if(stackempty(s))
{
printf("弹出栈顶元素之后的栈变为空\n\n");
}
else
{
printf("弹出栈顶元素之后的栈不为空\n\n");
}
getTop(s, &e);//获取栈顶元素
printf("栈顶元素 TopElem = %d 栈的长度为 %d \n\n", e, length(s));
printf("进行清空栈操作");
ClearStack(&s);//清空栈
if(stackempty(s))
{
printf("清空栈后,栈空\n\n");
}
else
{
printf("清空栈后,栈不空\n\n");
}
return 0;
}
顺序栈测试结果
(2)链栈
顾名思义,链栈就是线性表的链式储存结构
与链表的操作相似
1.//链栈的抽象数据类型定义
#define OK 1
#define ERROR 0
using namespace std;
typedef int Status;
typedef int ElemType;
//链栈的抽象数据类型定义
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStack;
2.//初始化链栈
Status InitStack(LinkStack &S)
{
//构造一个空栈,栈顶指针置为空
S = NULL;
return OK;
}
3.//入栈操作 Push
Status Push(LinkStack &S,ElemType e)
{
LinkStack p;//定义p
//这里使用的是C++语法new出的地址,也可使用C语言的语法malloc
p=(LinkStack)malloc(sizeof(StackNode)); //需要包含malloc头文件
// p=new StackNode;//生成新结点
p->data=e;//e赋给新结点的数据域
p->next=S; //新结点插入栈顶
S=p;//修改栈顶指针为p
return OK;
}
4.//出栈操作 Pop
Status Pop(LinkStack &S,ElemType &e)
{
LinkStack p;//定义p
if(S==NULL) return ERROR;//栈空
e=S->data;//将栈顶元素赋给e
p=S;//p临时保存栈顶元素以备释放
S=S->next;//修改栈顶指针
free(p);//释放空间
return OK;
}
5.//得到栈顶
ElemType GetTop(LinkStack S)
{
if(S!=NULL) //栈非空
return S->data;
}
6.//遍历打印栈中元素
ElemType GetElem(LinkStack S)
{
LinkStack p=S;//定义一个指针p;
while(p)//p不断向栈尾移动
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
7.//返回栈的长度
int StackLen(LinkStack S)
{
int len=0;
LinkStack p=S;
while(p)
{
len++;
p=p->next;
}
return len;
}
8.//清空链栈中的元素
Status StackClear(LinkStack &S)
{
LinkStack p=S;//定义一个指针p;
while(p)//p不断向栈尾移动,S=p,释放S
{
p=p->next;
free(S);
S=p;
}
return OK;
}
9.链栈完整代码示例
#include<iostream>
#include<malloc.h>
#define OK 1
#define ERROR 0
using namespace std;
typedef int Status;
typedef int ElemType;
//链栈的抽象数据类型定义
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStack;
//初始化链栈
Status InitStack(LinkStack &S)
{
//构造一个空栈,栈顶指针置为空
S = NULL;
return OK;
}
//入栈操作
Status Push(LinkStack &S,ElemType e)
{
LinkStack p;//定义p
//这里使用的是C++语法new出的地址,也可使用C语言的语法malloc
p=(LinkStack)malloc(sizeof(StackNode)); //需要包含malloc头文件
// p=new StackNode;//生成新结点
p->data=e;//e赋给新结点的数据域
p->next=S; //新结点插入栈顶
S=p;//修改栈顶指针为p
return OK;
}
//出栈操作
Status Pop(LinkStack &S,ElemType &e)
{
LinkStack p;//定义p
if(S==NULL) return ERROR;//栈空
e=S->data;//将栈顶元素赋给e
p=S;//p临时保存栈顶元素以备释放
S=S->next;//修改栈顶指针
delete p;//释放空间
return OK;
}
//得到栈顶
ElemType GetTop(LinkStack S)
{
if(S!=NULL) //栈非空
return S->data;
return 0;
}
//遍历栈中元素
ElemType GetElem(LinkStack S)
{
LinkStack p=S;//定义一个指针p;
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
return OK;
}
//返回栈的长度
int StackLen(LinkStack S)
{
int len=0;
LinkStack p=S;
while(p)
{
len++;
p=p->next;
}
return len;
}
//清空链栈中的元素
Status StackClear(LinkStack &S)
{
LinkStack p=S;//定义一个指针p;
while(p)//p不断向栈尾移动,S=p,释放S
{
p=p->next;
free(S);
S=p;
}
return OK;
}
int main()
{
LinkStack S;
ElemType e;
InitStack(S);
cout<<"进行入栈操作"<<endl;
cout<<endl;
for(int i=1;i<150;i+=10)
{
Push(S,i);//入栈
}
cout<<"此时的栈顶为: "<<GetTop(S)<<endl;
cout<<endl;
cout<<"由栈顶到栈底遍历栈中元素"<<endl ;
GetElem(S);
cout<<endl;
cout<<"此时栈的长度为"<<StackLen(S)<<endl ;
cout<<endl;
Pop(S,e);
cout<<"Pop后的栈顶为: "<<GetTop(S)<<endl;
cout<<endl;
cout<<"Pop后由栈顶到栈底遍历栈中元素"<<endl ;
GetElem(S);
cout<<endl;
cout<<"此时栈的长度为"<<StackLen(S)<<endl<<endl;
cout<<"清空栈操作"<<endl;
StackClear(S);
cout<<"此时栈的长度为"<<StackLen(S)<<endl ;
return 0;
}