数据结构 栈
一、栈
1.栈是一种操作受限制的线性表,其仅能在表尾进行插入和删除操作。我们把这一端称为栈顶,相对地,把另一端称为栈底。因此栈是一种“后进先出”的数据形式。
二、链栈
1.带头结点的链栈:由于栈是一种“后进先出”的数据形式,所以第n个进入栈的元素a_n为第一个元素,a_(n-1)为第二个元素,以此类推,a_1为最后一个元素。
2.链栈的存储结构定义:
typedef int Item;
typedef struct node
{
Item item; //栈的数据域
struct node * next; //栈的指针域,指向栈中的下一个结点
}Node;
typedef Node * Stack;
该定义中通过typedef为某一类型自定义名称。用Item作为int的别名(这样做更加通用),如果以后需要其他数据形式的链栈,可以重新定义Item类型。用Node作为struct node的别名,链栈的结点类型名是Node。用Stack作为Node *的别名,Stack作为该类型(Node)的指针名,若有Stack S;则表示创建了一个链栈(S表示指向链栈的头指针,即表示链栈)。
3.链栈的初始化:将链栈初始化为空。
void InitStack(Stack * S) //形参:指向Stack类型的指针
{
*S=(Node *)malloc(sizeof(Node)); //建立头结点
(*S)->next=NULL; //头结点的指针域设置为NULL
}
void InitStack(Stack * S) //形参:指向Stack类型的指针
{
*S=NULL; //链栈头指针设置为NULL
}
带头结点的链栈初始化前/后:(初始化后链栈为空)
4.链栈的判空:
bool StackIsEmpty(const Stack * S) //形参:指向Stack类型的指针,由于该函数不修改栈中内容,使用const修饰符对指针所指向的内容进行保护
{
if((*S)->next==NULL) //判断链栈头结点的指针域是否为NULL
return true;
else
return false;
}
5.链栈的进栈操作:
bool Push(Stack * S,Item item) //形参:1.指向Stack类型的指针 2.Item类型的变量item,用于为新结点的数据域赋值
{
Node * temp; //指向Node类型的指针temp
temp=(Node *)malloc(sizeof(Node)); //申请一个结点的空间,并将其地址赋给结构指针temp
if(temp==NULL) //若申请结点不成功,则返回false
return false;
temp->item=item; //为新结点的数据域赋值
temp->next=(*S)->next; //将头结点的指针域赋给新结点的指针域
(*S)->next=temp; //头结点的指针域指向新结点
return true;
}
6.链栈的出栈操作:
bool Pop(Stack * S,Item * item) //形参:1.指向Stack类型的指针 2.指向Item类型的指针,带出出栈结点的数据域
{
Node * temp; //指向Node类型的指针temp
temp=(*S)->next; //指针temp指向链栈的首元结点
if(temp==NULL) //若链栈为空,则返回false
return false;
(*S)->next=temp->next; //将首元结点的指针域赋给头结点的指针域(即头结点的指针域指向第二结点)
*item=temp->item; //将出栈结点的数据域通过指针item带出
free(temp); //释放出栈结点所占用的空间
return true;
}
7.链栈取栈顶元素:
取链栈的顶部元素赋给item所指向的单元,也称读栈顶。与Pop不同之处在于GetTop不改变栈顶的位置(即不会将栈顶元素出栈)。
bool GetTop(Stack * S,Item * item) //形参:1.指向Stack类型的指针 2.指向Item类型的指针,取栈顶元素赋给item所指向的单元
{
Node * temp; //指向Node类型的指针temp
temp=(*S)->next; //指针temp指向链栈的首元结点
if(temp==NULL) //若链栈为空,则返回false
return false;
*item=temp->item; //取栈顶元素赋给item所指向的单元
return true;
}
8.统计栈中元素个数:
int StackItemCount(const Stack * S) //形参:指向Stack类型的指针,由于该函数不修改栈中内容,使用const修饰符对指针所指向的内容进行保护
{
int count=0; //定义一个计数器count
Node * temp; //指向Node类型的指针temp
temp=(*S)->next; //指针temp指向链栈的首元结点
while(temp!=NULL) //遍历栈,递增计数器
{
count++;
temp=temp->next;
}
return count;
}
9.链栈样例:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int Item;
typedef struct node
{
Item item;
struct node * next;
}Node;
typedef Node * Stack;
void InitStack(Stack * S);
void output(const Stack * S);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool StackIsEmpty(const Stack * S);
bool GetTop(Stack * S,Item * item);
int StackItemCount(const Stack * S);
int main()
{
Stack S;
int a,b,c;
InitStack(&S);
if(StackIsEmpty(&S)==true)
printf("栈为空!\n");
printf("请输入一个整数:");
while(scanf("%d",&a)==1)
{
if(Push(&S,a)==true)
printf("%d入栈!\n",a);
else
{
printf("栈已满!");
break;
}
printf("请输入一个整数:");
}
printf("栈中有 %d个元素。\n",StackItemCount(&S));
printf("栈中元素为:\n");
output(&S);
GetTop(&S,&b);
printf("\n栈顶元素为: %d\n\n",b);
printf("连续出栈三个元素。\n");
for(int i=1;i<=3;i++)
{
if(Pop(&S,&c)==true)
printf("出栈元素为: %d\n",c);
else
printf("栈为空!\n");
}
GetTop(&S,&b);
printf("\n现栈顶元素为: %d\n",b);
printf("现栈中有 %d个元素。\n",StackItemCount(&S));
printf("现栈中元素为:\n");
output(&S);
return 0;
}
void InitStack(Stack * S)
{
*S=(Node *)malloc(sizeof(Node));
(*S)->next=NULL;
}
bool StackIsEmpty(const Stack * S)
{
if((*S)->next==NULL)
return true;
else
return false;
}
bool Push(Stack * S,Item item)
{
Node * temp;
temp=(Node *)malloc(sizeof(Node));
if(temp==NULL)
return false;
temp->item=item;
temp->next=(*S)->next;
(*S)->next=temp;
return true;
}
bool Pop(Stack * S,Item * item)
{
Node * temp;
temp=(*S)->next;
if(temp==NULL)
return false;
(*S)->next=temp->next;
*item=temp->item;
free(temp);
return true;
}
bool GetTop(Stack * S,Item * item)
{
Node * temp;
temp=(*S)->next;
if(temp==NULL)
return false;
*item=temp->item;
return true;
}
int StackItemCount(const Stack * S)
{
int count=0;
Node * temp;
temp=(*S)->next;
while(temp!=NULL)
{
count++;
temp=temp->next;
}
return count;
}
void output(const Stack * S)
{
Node * temp;
temp=(*S)->next;
while(temp!=NULL)
{
printf("%d\t",temp->item);
temp=temp->next;
}
}
输出结果:
10.括号匹配算法:
在检验算法中可设置一个栈,读入表达式的当前字符:
①若是左括号,则直接入栈,等待相匹配的同类右括号;
②若是右括号,则将它与栈顶左括号相比较:
若栈已空,则说明表达式中括号不匹配;返回
若栈非空,且栈顶的左括号与刚读入的右括号同类型,则二者匹配,此时将栈顶的左括号出栈;
若栈非空,且栈顶的左括号与刚读入的右括号不同类型,说明表达式不合法。返回
③重复上述过程,直到表达式结束。若此时栈中仍有等待匹配的左括号,说明表达式不合法。返回。
④当输入序列和栈同时变为空时,说明所有括号完全匹配。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZE 100
typedef char Item;
typedef struct node
{
Item character;
struct node * next;
}Node;
typedef Node * Stack;
void InitStack(Stack * S);
bool StackIsEmpty(Stack * S);
bool Match(char ch1,char ch2);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool GetTop(Stack * S,Item * item);
void BracketMatch(Stack * S,char * str);
int main()
{
Stack S;
char str[SIZE];
InitStack(&S);
printf("请输入一个字符串:");
gets(str);
BracketMatch(&S,str);
return 0;
}
void InitStack(Stack * S)
{
*S=(Node *)malloc(sizeof(Node));
(*S)->next=NULL;
}
bool StackIsEmpty(Stack * S)
{
if((*S)->next==NULL)
return true;
else
return false;
}
bool Push(Stack * S,Item item)
{
Node * temp;
temp=(Node *)malloc(sizeof(Node));
if(temp==NULL)
return false;
temp->character=item;
temp->next=(*S)->next;
(*S)->next=temp;
return true;
}
bool Pop(Stack * S,Item * item)
{
Node * temp;
temp=(*S)->next;
if(temp==NULL)
return false;
(*S)->next=temp->next;
*item=temp->character;
free(temp);
return true;
}
bool GetTop(Stack * S,Item * item)
{
Node * temp;
temp=(*S)->next;
if(temp==NULL)
return false;
*item=temp->character;
return true;
}
bool Match(char ch1,char ch2)
{
if((ch1=='('&&ch2==')')||(ch1=='['&&ch2==']')||(ch1=='{'&&ch2=='}'))
return true;
else
return false;
}
void BracketMatch(Stack * S,char * str)
{
char ch;
for(int i=0;str[i]!='\0';i++)
{
switch(str[i])
{
case '(':Push(S,str[i]);break;
case '[':Push(S,str[i]);break;
case '{':Push(S,str[i]);break;
case ')':
case ']':
case '}':
if(StackIsEmpty(S)==true)
{
printf("右括号多余!\n");
return ;
}
else
{
GetTop(S,&ch);
if(Match(ch,str[i])==true)
Pop(S,&ch);
else
{
printf("对应的左右括号不同类!\n");
return ;
}
}
}//switch
}//for
if(StackIsEmpty(S)==true)
printf("括号匹配!\n");
else
printf("左括号多余!\n");
}
输出结果:
三、顺序栈
1.顺序存储结构的栈,即利用一组地址连续的存储单元依次存放栈的数据元素。栈顶指针top:动态地指示栈顶元素在顺序栈中的位置。通常以top=-1表示空栈。
2.顺序栈的存储结构定义:
#define SIZE 20
typedef char Item;
typedef struct{
Item elem[SIZE]; //存放栈元素
int top; //标记栈顶元素下标,top=-1时栈为空
}Stack;
该定义中通过typedef为某一类型自定义名称。用Item作为char的别名(这样做更加通用),如果以后需要其他数据形式的顺序栈,可以重新定义Item类型。使用top标记栈顶元素下标,top=-1时栈为空。通过define定义SIZE,作为栈的容量大小。
3.顺序栈的初始化:将top置为-1。
void InitStack(Stack * S) //形参:指向Stack类型的指针
{
S->top=-1; //top置为-1
}
4.顺序栈判空和判满:
①:顺序栈判空:
bool StackIsEmpty(const Stack * S) //形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护
{
if(S->top==-1) //若top=-1则栈为空,返回true,否则返回false
return true;
else
return false;
}
②:顺序栈判满:
bool StackIsFull(const Stack * S) //形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护
{
if(S->top==SIZE-1) //若栈容量大小-1与top相等,则返回true,否则返回false
return true;
else
return false;
}
5.顺序栈的入栈操作:
bool Push(Stack * S,Item item) //形参:1.指向Stack类型的指针 2.Item类型的变量item,用于为top所标记的空间赋值
{
if(S->top==SIZE-1) //若栈已满,则返回false
return false;
S->top++; //更新top,使top指向新的栈顶元素下标
S->elem[S->top]=item; //为top标记的数组空间赋值
return true;
}
6.顺序栈的出栈操作:
bool Pop(Stack * S,Item * item) //形参:1.指向Stack类型的指针 2.指向Item类型的指针,带出出栈空间的元素
{
if(S->top==-1) //若栈为空,则返回false
return false;
*item=S->elem[S->top]; //通过指针item将出栈元素带出
S->top--; //修改top,使top指向新的栈顶元素下标
return true;
}
7.顺序栈取栈顶元素:
bool GetTop(const Stack * S,Item * item) //1.形参:指向Stack类型的指针,由于该函数不修改栈中元素,使用const修饰符对指针所指向的内容进行保护 2.指向Item类型的指针,取栈顶元素赋给item所指向的单元
{
if(S->top==-1) //若栈为空,则返回false
return false;
*item=S->elem[S->top]; //取栈顶元素赋给item所指向的单元
return true;
}
8.顺序栈样例:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define SIZE 20
typedef char Item;
typedef struct{
Item elem[SIZE];
int top;
}Stack;
void InitStack(Stack * S);
void output(const Stack * S); //显示栈中元素
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
bool StackIsEmpty(const Stack * S);
int StackElemCount(const Stack * S); //统计栈中元素个数
bool GetTop(const Stack * S,Item * item);
int main()
{
Stack S;
char a,b,c;
InitStack(&S);
if(StackIsEmpty(&S)==true)
printf("顺序栈为空!\n");
printf("请输入一个字符,输入#结束:");
while(scanf("%c",&a)&&a!='#')
{
if(Push(&S,a)==true)
printf("%c入栈!\n",a);
else
{
printf("顺序栈已满!\n");
break;
}
getchar();
printf("请输入一个字符,输入#结束:");
}
printf("顺序栈中有 %d个元素。\n",StackElemCount(&S));
printf("顺序栈中元素为:\n");
output(&S);
GetTop(&S,&b);
printf("\n栈顶元素为: %c\n\n",b);
printf("连续出栈三个元素。\n");
for(int i=1;i<=3;i++)
{
if(Pop(&S,&c)==true)
printf("出栈元素为: %c\n",c);
else
printf("栈为空!\n");
}
GetTop(&S,&b);
printf("\n现栈顶元素为: %c\n",b);
printf("顺序栈中有 %d个元素。\n",StackElemCount(&S));
printf("现顺序栈中元素为:\n");
output(&S);
return 0;
}
void InitStack(Stack * S)
{
S->top=-1;
}
bool StackIsEmpty(const Stack * S)
{
if(S->top==-1)
return true;
else
return false;
}
bool Push(Stack * S,Item item)
{
if(S->top==SIZE-1)
return false;
S->top++;
S->elem[S->top]=item;
return true;
}
bool Pop(Stack * S,Item * item)
{
if(S->top==-1)
return false;
*item=S->elem[S->top];
S->top--;
return true;
}
bool GetTop(const Stack * S,Item * item)
{
if(S->top==-1)
return false;
*item=S->elem[S->top];
return true;
}
int StackElemCount(const Stack * S) //
{
int count;
count=S->top+1;
return count;
}
void output(const Stack * S)
{
int temp;
temp=S->top;
while(temp>=0)
{
printf("%c\t",S->elem[temp]);
temp=temp-1;
}
}
输出结果:
9.使用栈判别回文字符串。(回文字符串:正读反读均相同的字符序列,其结构呈中心对称)
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#define SIZE 100
typedef char Item;
typedef struct{
Item elem[SIZE];
int top;
}Stack;
void InitStack(Stack * S);
bool Push(Stack * S,Item item);
bool Pop(Stack * S,Item * item);
int main()
{
Stack S;
int len,mid,next;
char c,str[SIZE];
InitStack(&S);
printf("请输入一个字符串:");
scanf("%s",str);
len=strlen(str);
mid=len/2;
for(int i=0;i<mid;i++)
{
Push(&S,str[i]);
}
if(len%2==0)
next=mid;
else
next=mid+1;
for(int i=next;i<len;i++)
{
Pop(&S,&c);
if(str[i]!=c)
break;
}
if(S.top==-1)
printf("\n该字符串 (%s) 是回文字符串!",str);
else
printf("\n该字符串 (%s) 不是回文字符串!",str);
return 0;
}
void InitStack(Stack * S)
{
S->top=-1;
}
bool Push(Stack * S,Item item)
{
if(S->top==SIZE-1)
return false;
S->top++;
S->elem[S->top]=item;
return true;
}
bool Pop(Stack * S,Item * item)
{
if(S->top==-1)
return false;
*item=S->elem[S->top];
S->top--;
return true;
}
输出结果: