当前位置:   article > 正文

链栈的基本操作及应用_链表的基本操作与栈的应用 数据结构实践

链表的基本操作与栈的应用 数据结构实践

第1关:链栈的基本操作

任务描述

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

相关知识

链式存储的栈

栈的链式存储结构是采用某种链表结构,栈的链式存储结构简称为链栈。 这里采用单链表作为链栈,该单链表是不带头结点的。

可以用不带头结点的单链表存储链栈,设计初始化栈、判断栈是否为空、进栈和出栈等相应算法。

不带头结点的单链表,在进行插入、删除、查值等操作运算时需要对表首进行特殊处理。

不带头结点的单链表基本操作

链栈就是不带头结点的单链表,不带头结点的单链表的基本操作如下:

 
  1. struct LNode
  2. {
  3. ElemType data;
  4. LNode *next;
  5. };
  6. typedef LNode * LinkList; // 另一种定义LinkList的方法
  7. // 不带头结点的单链表的部分基本操作(9个)
  8. void InitList(LinkList &L)
  9. { // 操作结果:构造一个空的线性表L
  10. L=NULL; // 指针为空
  11. }
  12. #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
  13. void ClearList(LinkList &L)
  14. { // 初始条件:线性表L已存在。操作结果:将L重置为空表
  15. LinkList p;
  16. while(L) // L不空
  17. {
  18. p=L; // p指向首元结点
  19. L=L->next; // L指向第2个结点(新首元结点)
  20. free(p); // 释放首元结点
  21. }
  22. }
  23. int ListEmpty(LinkList L)
  24. { // 初始条件:单链表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
  25. if(L)
  26. return FALSE;
  27. else
  28. return TRUE;
  29. }
  30. int ListLength(LinkList L)
  31. { // 初始条件:线性表L已存在。操作结果:返回L中数据元素个数
  32. int i=0;
  33. LinkList p=L;
  34. while(p) // p指向结点(没到表尾)
  35. {
  36. p=p->next; // p指向下一个结点
  37. i++;
  38. }
  39. return i;
  40. }
  41. int GetElem(LinkList L,int i,ElemType &e)
  42. { // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
  43. int j=1;
  44. LinkList p=L;
  45. if(i<1) // i值不合法
  46. return ERROR;
  47. while(j<i&&p) // 没到第i个元素,也没到表尾
  48. {
  49. j++;
  50. p=p->next;
  51. }
  52. if(j==i) // 存在第i个元素
  53. {
  54. e=p->data;
  55. return OK;
  56. }
  57. else
  58. return ERROR;
  59. }
  60. int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
  61. { // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
  62. // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
  63. // 若这样的数据元素不存在,则返回值为0
  64. int i=0;
  65. LinkList p=L;
  66. while(p)
  67. {
  68. i++;
  69. if(compare(p->data,e)) // 找到这样的数据元素
  70. return i;
  71. p=p->next;
  72. }
  73. return 0;
  74. }
  75. int ListInsert(LinkList &L,int i,ElemType e)
  76. { // 在不带头结点的单链线性表L中第i个位置之前插入元素e
  77. int j=1;
  78. LinkList p=L,s;
  79. if(i<1) // i值不合法
  80. return ERROR;
  81. s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
  82. s->data=e; // 给s的data域赋值
  83. if(i==1) // 插在表头
  84. {
  85. s->next=L;
  86. L=s; // 改变L
  87. }
  88. else
  89. { // 插在表的其余处
  90. while(p&&j<i-1) // 寻找第i-1个结点
  91. {
  92. p=p->next;
  93. j++;
  94. }
  95. if(!p) // i大于表长+1
  96. return ERROR;
  97. s->next=p->next;
  98. p->next=s;
  99. }
  100. return OK;
  101. }
  102. int ListDelete(LinkList &L,int i,ElemType &e)
  103. { // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值
  104. int j=1;
  105. LinkList p=L,q;
  106. if(i==1) // 删除第1个结点
  107. {
  108. L=p->next; // L由第2个结点开始
  109. e=p->data;
  110. free(p); // 删除并释放第1个结点
  111. }
  112. else
  113. {
  114. while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
  115. {
  116. p=p->next;
  117. j++;
  118. }
  119. if(!p->next||j>i-1) // 删除位置不合理
  120. return ERROR;
  121. q=p->next; // 删除并释放结点
  122. p->next=q->next;
  123. e=q->data;
  124. free(q);
  125. }
  126. return OK;
  127. }
  128. void ListTraverse(LinkList L,void(*vi)(ElemType))
  129. { // 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi()
  130. LinkList p=L;
  131. while(p)
  132. {
  133. vi(p->data);
  134. p=p->next;
  135. }
  136. printf("\n");
  137. }

链栈的基本操作

针对链栈我们定义如下操作:

 
  1. typedef SElemType ElemType; // 栈结点类型和链表结点类型一致
  2. typedef LinkList LinkStack; // LinkStack是指向栈结点的指针类型
  3. #define InitStack InitList // InitStack()与InitList()作用相同,下同
  4. #define DestroyStack DestroyList
  5. #define ClearStack ClearList
  6. #define StackEmpty ListEmpty
  7. #define StackLength ListLength

编程要求

根据提示,在右侧编辑器 Begin-End 区间补充代码,实现4个链栈的基本操作函数,具体要求如下:

  • 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()

测试说明

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

测试输入: 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个整数。

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

 

  1. #include <stdio.h>
  2. #include<stdlib.h>
  3. #include <iostream>
  4. using namespace std;
  5. // 函数结果状态代码
  6. #define TRUE 1
  7. #define FALSE 0
  8. #define OK 1
  9. #define ERROR 0
  10. typedef int SElemType;
  11. void input(SElemType &s);
  12. void output(SElemType s);
  13. typedef SElemType ElemType; // 栈结点类型和链表结点类型一致
  14. struct LNode
  15. {
  16. ElemType data;
  17. LNode *next;
  18. };
  19. typedef LNode * LinkList; // 另一种定义LinkList的方法
  20. // 不带头结点的单链表的部分基本操作(9个)
  21. #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
  22. void InitList(LinkList &L);
  23. void ClearList(LinkList &L);
  24. int ListEmpty(LinkList L);
  25. int ListLength(LinkList L);
  26. int GetElem(LinkList L,int i,ElemType &e);
  27. int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType));
  28. int ListInsert(LinkList &L,int i,ElemType e);
  29. int ListDelete(LinkList &L,int i,ElemType &e);
  30. void ListTraverse(LinkList L,void(*vi)(ElemType));
  31. /*****链栈的基本操作*****/
  32. typedef LinkList LinkStack; // LinkStack是指向栈结点的指针类型
  33. #define InitStack InitList // InitStack()与InitList()作用相同,下同
  34. #define DestroyStack DestroyList
  35. #define ClearStack ClearList
  36. #define StackEmpty ListEmpty
  37. #define StackLength ListLength
  38. int GetTop(LinkStack S,SElemType &e); // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
  39. int Push(LinkStack &S,SElemType e); // 插入元素e为新的栈顶元素
  40. int Pop(LinkStack &S,SElemType &e); // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
  41. void StackTraverse(LinkStack S,void(*visit)(SElemType)); // 从栈底到栈顶依次对栈中每个元素调用函数visit()
  42. int main()
  43. {
  44. int j,n;
  45. LinkStack s;
  46. SElemType e;
  47. InitStack(s);
  48. cin>>n;
  49. for(j=1;j<=n;j++)
  50. {
  51. input(e);
  52. Push(s,e);
  53. }
  54. printf("栈中元素依次为:");
  55. StackTraverse(s,output);
  56. Pop(s,e);
  57. printf("\n弹出的栈顶元素 e=%d\n",e);
  58. printf("栈空否:%d(1:空 0:否)\n",StackEmpty(s));
  59. GetTop(s,e);
  60. printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
  61. ClearStack(s);
  62. printf("清空栈后,栈空否:%d(1:空 0:否)\n",StackEmpty(s));
  63. DestroyStack(s);
  64. }
  65. /*****SElemType类型元素的基本操作*****/
  66. void input(SElemType &s)
  67. {
  68. cin>>s;
  69. }
  70. void output(SElemType s)
  71. {
  72. cout<<s<<" ";
  73. }
  74. // 不带头结点的单链表的部分基本操作(9个)
  75. #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的
  76. void InitList(LinkList &L)
  77. { // 操作结果:构造一个空的线性表L
  78. // L=NULL; // 指针为空
  79. L = (LinkStack)malloc(sizeof(LinkStack));
  80. L->next = NULL;
  81. }
  82. void ClearList(LinkList &L)
  83. { // 初始条件:线性表L已存在。操作结果:将L重置为空表
  84. LinkList p;
  85. while(L) // L不空
  86. {
  87. p=L; // p指向首元结点
  88. L=L->next; // L指向第2个结点(新首元结点)
  89. free(p); // 释放首元结点
  90. }
  91. }
  92. int ListEmpty(LinkList L)
  93. { // 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
  94. if(L)
  95. return FALSE;
  96. else
  97. return TRUE;
  98. }
  99. int ListLength(LinkList L)
  100. { // 初始条件:线性表L已存在。操作结果:返回L中数据元素个数
  101. int i=0;
  102. LinkList p=L->next;
  103. while(p) // p指向结点(没到表尾)
  104. {
  105. p=p->next; // p指向下一个结点
  106. i++;
  107. }
  108. return i;
  109. }
  110. int GetElem(LinkList L,int i,ElemType &e)
  111. { // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
  112. int j=1;
  113. LinkList p=L;
  114. if(i<1) // i值不合法
  115. return ERROR;
  116. while(j<i&&p) // 没到第i个元素,也没到表尾
  117. {
  118. j++;
  119. p=p->next;
  120. }
  121. if(j==i) // 存在第i个元素
  122. {
  123. e=p->data;
  124. return OK;
  125. }
  126. else
  127. return ERROR;
  128. }
  129. int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
  130. { // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
  131. // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
  132. // 若这样的数据元素不存在,则返回值为0
  133. int i=0;
  134. LinkList p=L;
  135. while(p)
  136. {
  137. i++;
  138. if(compare(p->data,e)) // 找到这样的数据元素
  139. return i;
  140. p=p->next;
  141. }
  142. return 0;
  143. }
  144. int ListInsert(LinkList &L,int i,ElemType e)
  145. { // 在不带头结点的单链线性表L中第i个位置之前插入元素e
  146. int j=1;
  147. LinkList p=L,s;
  148. if(i<1) // i值不合法
  149. return ERROR;
  150. s=(LinkList)malloc(sizeof(LNode)); // 生成新结点
  151. s->data=e; // 给s的data域赋值
  152. if(i==1) // 插在表头
  153. {
  154. s->next=L;
  155. L=s; // 改变L
  156. }
  157. else
  158. { // 插在表的其余处
  159. while(p&&j<i-1) // 寻找第i-1个结点
  160. {
  161. p=p->next;
  162. j++;
  163. }
  164. if(!p) // i大于表长+1
  165. return ERROR;
  166. s->next=p->next;
  167. p->next=s;
  168. }
  169. return OK;
  170. }
  171. int ListDelete(LinkList &L,int i,ElemType &e)
  172. { // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值
  173. int j=1;
  174. LinkList p=L,q;
  175. if(i==1) // 删除第1个结点
  176. {
  177. L=p->next; // L由第2个结点开始
  178. e=p->data;
  179. free(p); // 删除并释放第1个结点
  180. }
  181. else
  182. {
  183. while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
  184. {
  185. p=p->next;
  186. j++;
  187. }
  188. if(!p->next||j>i-1) // 删除位置不合理
  189. return ERROR;
  190. q=p->next; // 删除并释放结点
  191. p->next=q->next;
  192. e=q->data;
  193. free(q);
  194. }
  195. return OK;
  196. }
  197. void ListTraverse(LinkList L,void(*vi)(ElemType))
  198. { // 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi()
  199. LinkList p=L;
  200. while(p)
  201. {
  202. vi(p->data);
  203. p=p->next;
  204. }
  205. printf("\n");
  206. }
  207. int GetTop(LinkStack S,SElemType &e)
  208. { // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
  209. /********** Begin **********/
  210. while(S->next)
  211. {
  212. S=S->next;
  213. }
  214. e=S->data;
  215. return e;
  216. /********** End **********/
  217. }
  218. int Push(LinkStack &S,SElemType e)
  219. { // 插入元素e为新的栈顶元素
  220. /********** Begin **********/
  221. LinkStack p=S;
  222. LinkStack q=(LinkStack)malloc(sizeof(LinkStack));
  223. while(p->next)
  224. {
  225. p=p->next;
  226. }
  227. q->data=e;
  228. q->next=p->next;
  229. p->next=q;
  230. return e;
  231. /********** End **********/
  232. }
  233. int Pop(LinkStack &S,SElemType &e)
  234. { // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
  235. /********** Begin **********/
  236. LinkStack p=S,q;
  237. while(p->next->next)
  238. {
  239. p=p->next;
  240. }
  241. e=p->next->data;
  242. q=p->next;
  243. p->next=q->next;
  244. // free(q);
  245. return e;
  246. /********** End **********/
  247. }
  248. void StackTraverse(LinkStack S,void(*visit)(SElemType))
  249. { // 从栈底到栈顶依次对栈中每个元素调用函数visit()
  250. /********** Begin **********/
  251. LinkStack p=S->next;
  252. while(p)
  253. {
  254. visit(p->data);
  255. p=p->next;
  256. }
  257. /********** End **********/
  258. }

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

任务描述

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

相关知识

从左至右扫描一个表达式(或字符串),则每个右括号将与最近遇到的那个左括号相匹配。

在从左至右扫描表达式过程中把所遇到的左括号存放到栈中。

每当遇到一个右括号时,就将它与栈顶的左括号(如果存在)相匹配,同时从栈顶删除该左括号。

算法思想:

设置一个栈,当读到左括号时,左括号进栈。当读到右括号时,则从栈中弹出一个元素,与读到的左括号进行匹配,若匹配成功,继续读入;否则匹配失败。另外,在算法的开始和结束时,栈都应该是空的,所以匹配到最后还要判断栈是否为空,若空,则说明匹配成功,返回1。若非空,则说明匹配失败,返回0。

步骤如下:

  • 设置一个链栈st,定义一个整型flag变量(初始为1)。

  • 用i扫描表达式exp,当i<n并且flag=1时循环:

  • 当遇到左括号“(”、“[”、“{”时,将其进栈;

  • 遇到“}”、“]”、“)”时,出栈字符ch,若出栈失败(下溢出)或者ch不匹配,则置flag=0退出循环;

  • 否则直到exp扫描完毕为止。

  • 若栈空并且flag为1则返回1,否则返回0。

编程要求

根据提示,在右侧编辑器 Begin - End 之间补充代码,判断表达式(或字符串)中括号是否成对出现。

测试说明

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

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

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

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include "slink.h" //包含前面的链栈基本运算函数
  4. int Match(char exp[],int n) //exp存放表达式,n是表达式长度
  5. {
  6. LinkStack st; //定义一个链栈st
  7. InitStack(st); //栈初始化
  8. int flag=1,i=0;
  9. char ch;
  10. /********** Begin **********/
  11. int m=0,p=0;
  12. for(i=0;i<n;i++)
  13. {
  14. if(exp[i]=='('||exp[i]=='['||exp[i]=='{')
  15. {
  16. Push(st,exp[i]);
  17. m++;
  18. }
  19. else
  20. {
  21. p++;
  22. GetTop(st,ch);
  23. if((ch=='('&&exp[i]==')')||(ch=='['&&exp[i]==']')||(ch=='{'&&exp[i]=='}'))
  24. {
  25. Pop(st,ch);
  26. }
  27. }
  28. }
  29. if(ListEmpty(st)&&(m==p))
  30. {
  31. return 1;
  32. }
  33. else
  34. {
  35. return 0;
  36. }
  37. /********** End **********/
  38. }
  39. void display(char exp[])
  40. {
  41. int n=strlen(exp);
  42. if (Match(exp,n))
  43. printf("%s是匹配的表达式\n",exp);
  44. else
  45. printf("%s不是匹配的表达式\n",exp);
  46. }
  47. int main()
  48. {
  49. char str[80];
  50. scanf("%s",str);
  51. display(str);
  52. return 0;
  53. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/905923
推荐阅读
相关标签
  

闽ICP备14008679号