链栈的基本操作及应用

第1关:链栈的基本操作

任务描述

本关任务是实现链栈的基本操作函数,以实现判断栈是否为空、求栈的长度、进栈、出栈以及获取栈顶元素等功能。

测试说明

平台会对你编写的代码进行测试:

测试输入:
12 47 5 8 6 92 45 63 75 38 4 29

预期输出:
栈中元素依次为:12 47 5 8 6 92 45 63 75 38 4 29
弹出的栈顶元素 e=29
栈空否:0(1:空 0:否)
栈顶元素 e=4 栈的长度为11
清空栈后,栈空否:1(1:空 0:否)

输入说明
第一行输入顺序栈的数据元素的个数n;
第二行输入顺序栈的n个整数。

输出说明
第一行输出顺序栈的所有数据元素;
第二行输出出栈的数据元素;
第三行判断栈是否为空;
第四行输出当前的栈顶元素及栈的长度;
第五行销毁栈后,判断栈是否为空;

代码如下

#include <stdio.h>
#include<stdlib.h>
#include <iostream>
using namespace std;

 // 函数结果状态代码
 #define TRUE 1
 #define FALSE 0
 #define OK 1
 #define ERROR 0
typedef  int  SElemType;
void input(SElemType &s);
void output(SElemType s);

typedef  SElemType  ElemType;   // 栈结点类型和链表结点类型一致

struct  LNode
 {
   ElemType data;
   LNode *next;
 };
 typedef  LNode * LinkList; // 另一种定义LinkList的方法

// 不带头结点的单链表的部分基本操作(9个)
 #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
 void InitList(LinkList &L); 
 void ClearList(LinkList &L);
 int ListEmpty(LinkList L);
 int ListLength(LinkList L);
 int GetElem(LinkList L,int i,ElemType &e);
 int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType));
 int ListInsert(LinkList &L,int i,ElemType e);
 int ListDelete(LinkList &L,int i,ElemType &e);
 void ListTraverse(LinkList L,void(*vi)(ElemType));

 /*****链栈的基本操作*****/
typedef  LinkList LinkStack;     // LinkStack是指向栈结点的指针类型
#define  InitStack  InitList     // InitStack()与InitList()作用相同,下同
#define DestroyStack  DestroyList
#define ClearStack  ClearList
#define StackEmpty  ListEmpty
#define StackLength ListLength

int GetTop(LinkStack S,SElemType &e); // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
int Push(LinkStack &S,SElemType e);  // 插入元素e为新的栈顶元素
int Pop(LinkStack &S,SElemType &e); // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
void StackTraverse(LinkStack S,void(*visit)(SElemType)); // 从栈底到栈顶依次对栈中每个元素调用函数visit()


int main()
 {
   int j,n;
   LinkStack s;
   SElemType e;
   InitStack(s);
   cin>>n;
   for(j=1;j<=n;j++)
   {
	   input(e);
	   Push(s,e);
   }
   printf("栈中元素依次为:");
   StackTraverse(s,output);
   Pop(s,e);
   printf("\n弹出的栈顶元素 e=%d\n",e);
   printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
   GetTop(s,e);
   printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
   ClearStack(s);
   printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
   DestroyStack(s);  
 }
 
/*****SElemType类型元素的基本操作*****/
void input(SElemType &s)
{
	cin>>s;
}
void output(SElemType s)
{
	cout<<s<<" ";
}

// 不带头结点的单链表的部分基本操作(9个)
#define DestroyList ClearList    // DestroyList()和ClearList()的操作是一样的
void InitList(LinkList &L)
{ // 操作结果:构造一个空的线性表L
  //  L=NULL; // 指针为空
  L = (LinkStack)malloc(sizeof(LinkStack));
  L->next = NULL;
}

void ClearList(LinkList &L)
{ // 初始条件:线性表L已存在。操作结果:将L重置为空表
   LinkList p;
   while(L) // L不空
   {
     p=L; // p指向首元结点
     L=L->next; // L指向第2个结点(新首元结点)
     free(p); // 释放首元结点
   }
}

int ListEmpty(LinkList L)
{ // 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
   if(L)
     return FALSE;
   else
     return TRUE;
}

int ListLength(LinkList L)
{ // 初始条件:线性表L已存在。操作结果:返回L中数据元素个数
   int i=0;
   LinkList p=L->next;
   while(p) // p指向结点(没到表尾)
   {
     p=p->next; // p指向下一个结点
     i++;
   }
   return i;
}

int GetElem(LinkList L,int i,ElemType &e)
{ // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
   int j=1;
   LinkList p=L;
   if(i<1) // i值不合法
     return ERROR;
   while(j<i&&p) // 没到第i个元素,也没到表尾
   {
     j++;
     p=p->next;
   }
   if(j==i) // 存在第i个元素
   {
     e=p->data;
     return OK;
   }
   else
     return ERROR;
}

int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
{ // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
   // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
   //           若这样的数据元素不存在,则返回值为0
   int i=0;
   LinkList p=L;
   while(p)
   {
     i++;
     if(compare(p->data,e)) // 找到这样的数据元素
       return i;
     p=p->next;
   }
   return 0;
}

int ListInsert(LinkList &L,int i,ElemType e)
{ // 在不带头结点的单链线性表L中第i个位置之前插入元素e
   int j=1;
   LinkList p=L,s;
   if(i<1) // i值不合法
     return ERROR;
   s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
   s->data=e; // 给s的data域赋值
   if(i==1) // 插在表头
   {
     s->next=L;
     L=s; // 改变L
   }
   else
   { // 插在表的其余处
     while(p&&j<i-1) // 寻找第i-1个结点
     {
       p=p->next;
       j++;
     }
     if(!p) // i大于表长+1
       return ERROR;
     s->next=p->next;
     p->next=s;
   }
   return OK;
}

int ListDelete(LinkList &L,int i,ElemType &e)
{ // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值
   int j=1;
   LinkList p=L,q;
   if(i==1) // 删除第1个结点
   {
     L=p->next; // L由第2个结点开始
     e=p->data;
     free(p); // 删除并释放第1个结点
   }
   else
   {
     while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
     {
       p=p->next;
       j++;
     }
     if(!p->next||j>i-1) // 删除位置不合理
       return ERROR;
     q=p->next; // 删除并释放结点
     p->next=q->next;
     e=q->data;
     free(q);
   }
   return OK;
}
 
void ListTraverse(LinkList L,void(*vi)(ElemType))
{ // 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi()
   LinkList p=L;
   while(p)
   {
     vi(p->data);
     p=p->next;
   }
   printf("\n");
}


int GetTop(LinkStack S,SElemType &e)
 { // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
    /********** Begin **********/ 
    while(S->next!=NULL){
      S = S->next;
    }
    e = S->data;
    return e;
    /********** End **********/	
}

int Push(LinkStack &S,SElemType e)
{ // 插入元素e为新的栈顶元素
    /********** Begin **********/ 
    LinkStack ss = S;
    LinkStack node = (LinkStack)malloc(sizeof(LinkStack));
    while(ss->next){
      ss = ss->next;
    }
    node->data = e;
    node->next = ss->next;
    ss->next = node;
    return e;
    /********** End **********/	
 }

int Pop(LinkStack &S,SElemType &e)
{ // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
    /********** Begin **********/ 
    LinkStack ss = S,node;
    while(ss->next->next!=NULL){
      ss = ss->next;
    }
    e = ss->next->data;
    node = ss->next;
    ss->next = node->next;
    free(node);
    return e;
    /********** End **********/	
 }

void StackTraverse(LinkStack S,void(*visit)(SElemType))
{ // 从栈底到栈顶依次对栈中每个元素调用函数visit()
    /********** Begin **********/ 
   LinkStack p = S->next;
   while(p){
     visit(p->data);
     p = p->next;
   }
   
	/********** End **********/	
}

第2关:链栈的应用——括号匹配

任务描述

本关任务:设计一个算法,判断一个可能含有花括号、中括号、和圆括号的表达式中各类括号是否匹配,若匹配,则返回1;否则返回0。其中表达式只包含三种括号,花括号{}、中括号[]、圆括号(),即它仅由 (、)、[、]、{、}六个字符组成

测试说明

平台会对你编写的代码进行测试,只有所有数据全部计算正确才能通过测试:

测试输入:{ [ ] ( ) }
预期输出:{ [ ] ( ) }是匹配的表达式

测试输入:[ ( { } ] [ ) ]
预期输出:[ ( { } ] [ ) ]不是匹配的表达式

代码如下

 
#include<stdio.h>
#include<string.h>
#include "slink.h"	//包含前面的链栈基本运算函数


int Match(char exp[],int n)	//exp存放表达式,n是表达式长度
{ 
	LinkStack st;			//定义一个链栈st
   InitStack(st);		//栈初始化
   int flag=1,i=0;
   char ch;
	int a=0,b=0;
   /********** Begin **********/ 
	for(int i =0 ;i<n;i++){
		if(exp[i]=='('||exp[i]=='{'||exp[i]=='['){
			Push(st,exp[i]);
			a++;
		}else{
			b++;
			GetTop(st,ch);
			if((ch =='('&&exp[i]==')')||(ch == '{'&&exp[i]=='}')||(ch=='['&&exp[i]==']'))
			Pop(st,ch);
		}
	}
	if(ListEmpty(st)&&a==b){
		return 1;
	}else{
		return 0;
	}

 
   /********** End **********/
}

void display(char exp[])
{
	int n=strlen(exp);
	if (Match(exp,n))
		printf("%s是匹配的表达式\n",exp);
	else
		printf("%s不是匹配的表达式\n",exp);
}

int main()
{
	char str[80];
	scanf("%s",str);
	display(str);
	return 0;
}

辅助文件

slink.h

// 函数结果状态代码
 #define TRUE 1
 #define FALSE 0
 #define OK 1
 #define ERROR 0

typedef  char  ElemType;

struct  LNode
 {
   ElemType data;
   LNode *next;
 };
 typedef  LNode * LinkList; // 另一种定义LinkList的方法

// 不带头结点的单链表的部分基本操作(9个)
 #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
 void InitList(LinkList &L); 
 void ClearList(LinkList &L);
 int ListEmpty(LinkList L);
 int ListLength(LinkList L);
 int GetElem(LinkList L,int i,ElemType &e);
 int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType));
 int ListInsert(LinkList &L,int i,ElemType e);
 int ListDelete(LinkList &L,int i,ElemType &e);
 void ListTraverse(LinkList L,void(*vi)(ElemType));

/*****链栈的基本操作*****/
typedef    ElemType  SElemType;   // 栈结点类型和链表结点类型一致

typedef  LinkList LinkStack;     // LinkStack是指向栈结点的指针类型
#define  InitStack  InitList     // InitStack()与InitList()作用相同,下同
#define DestroyStack  DestroyList
#define ClearStack  ClearList
#define StackEmpty  ListEmpty
#define StackLength ListLength

int GetTop(LinkStack S,SElemType &e); // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
int Push(LinkStack &S,SElemType e);  // 插入元素e为新的栈顶元素
int Pop(LinkStack &S,SElemType &e); // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
void StackTraverse(LinkStack S,void(*visit)(SElemType)); // 从栈底到栈顶依次对栈中每个元素调用函数visit()

slink.cpp

#include<stdio.h>
#include<stdlib.h>
#include"slink.h"
 // 不带头结点的单链表的部分基本操作(9个)
void InitList(LinkList &L)
{ // 操作结果:构造一个空的线性表L
   L=NULL; // 指针为空
 }

#define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的

void ClearList(LinkList &L)
{ // 初始条件:线性表L已存在。操作结果:将L重置为空表
   LinkList p;
   while(L) // L不空
   {
     p=L; // p指向首元结点
     L=L->next; // L指向第2个结点(新首元结点)
     free(p); // 释放首元结点
   }
}

int ListEmpty(LinkList L)
{ // 初始条件:单链表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
   if(L)
     return FALSE;
   else
     return TRUE;
}

int ListLength(LinkList L)
{ // 初始条件:线性表L已存在。操作结果:返回L中数据元素个数
   int i=0;
   LinkList p=L;
   while(p) // p指向结点(没到表尾)
   {
     p=p->next; // p指向下一个结点
     i++;
   }
   return i;
}

int GetElem(LinkList L,int i,ElemType &e)
{ // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
   int j=1;
   LinkList p=L;
   if(i<1) // i值不合法
     return ERROR;
   while(j<i&&p) // 没到第i个元素,也没到表尾
   {
     j++;
     p=p->next;
   }
   if(j==i) // 存在第i个元素
   {
     e=p->data;
     return OK;
   }
   else
     return ERROR;
}

int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
{ // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
   // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
   //           若这样的数据元素不存在,则返回值为0
   int i=0;
   LinkList p=L;
   while(p)
   {
     i++;
     if(compare(p->data,e)) // 找到这样的数据元素
       return i;
     p=p->next;
   }
   return 0;
}

int ListInsert(LinkList &L,int i,ElemType e)
{ // 在不带头结点的单链线性表L中第i个位置之前插入元素e
   int j=1;
   LinkList p=L,s;
   if(i<1)                // i值不合法
     return ERROR;
   s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
   s->data=e; // 给s的data域赋值
   if(i==1) // 插在表头
   {
     s->next=L;
     L=s; // 改变L
   }
   else
   { // 插在表的其余处
     while(p&&j<i-1) // 寻找第i-1个结点
     {
       p=p->next;
       j++;
     }
     if(!p) // i大于表长+1
       return ERROR;
     s->next=p->next;
     p->next=s;
   }
   return OK;
}

int ListDelete(LinkList &L,int i,ElemType &e)
 { // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值
   int j=1;
   LinkList p=L,q;
   if(i==1)    // 删除第1个结点
   {
     L=p->next; // L由第2个结点开始
     e=p->data;
     free(p);  // 删除并释放第1个结点
   }
   else
   {
     while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
     {
       p=p->next;
       j++;
     }
     if(!p->next||j>i-1) // 删除位置不合理
       return ERROR;
     q=p->next;         // 删除并释放结点
     p->next=q->next;
     e=q->data;
     free(q);
   }
   return OK;
}
 
 void ListTraverse(LinkList L,void(*vi)(ElemType))
 { // 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi()
   LinkList p=L;
   while(p)
   {
     vi(p->data);
     p=p->next;
   }
   printf("\n");
 } 

//链栈的部分基本操作(4个)
 int GetTop(LinkStack S,SElemType &e)
{ // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
  
  return GetElem(S,1,e);
    
}

int Push(LinkStack &S,SElemType e)
{ // 插入元素e为新的栈顶元素
  
  return ListInsert(S,1,e);
    
}
int Pop(LinkStack &S,SElemType &e)
{ // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
  
  return ListDelete(S,1,e);
     
}
void StackTraverse(LinkStack S,void(*visit)(SElemType))
{ // 从栈底到栈顶依次对栈中每个元素调用函数visit()
   
   LinkStack temp,p=S; // p指向栈顶元素
   InitStack(temp); // 初始化临时栈temp
   while(p)
   {
     Push(temp,p->data); // 由S栈顶到栈底,依次将栈元素入栈到temp栈
     p=p->next;
   }
   ListTraverse(temp,visit); // 遍历temp线性表   
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杼蛘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值