• C++11 数据结构6 栈的链式存储,实现,测试


    栈顶放在链表的头部

    栈顶放在链表的头部还是尾部呢?

    需要栈 是特殊的线性表,那么我们回忆一下 线性表的链式存储的插入和删除的写法,就应该能理清线性表的头部做为栈顶 合适  还是 线性表的尾部 作为栈顶合适

    插入算法 核心代码

    1. //正式插入数据,
    2. int i = 0;
    3. LinkListNode *curSeqListNode = &(tempseqlist->head);//让curSeqListNode 指向 链表的头部
    4. for (int i = 0; i < pos; ++i) {
    5. curSeqListNode = curSeqListNode->next;
    6. }
    7. node->next = curSeqListNode->next;
    8. curSeqListNode->next = node;
    9. tempseqlist->length++;
    10. return ret;

    删除算法 核心代码

    1. //辅助指针变量curSeqListNode,指向的位置是链表的头部
    2. LinkListNode *curSeqListNode = &(tempseqlist->head);//让curSeqListNode 指向 链表的头部
    3. int i = 0;
    4. for (i = 0; i < pos; ++i) {
    5. curSeqListNode = curSeqListNode->next;
    6. }
    7. retSeqListNode = curSeqListNode->next; //先将要删除的节点缓存出来
    8. curSeqListNode->next = retSeqListNode->next;// 删除的节点的next中保存着 “要删除元素的下一个元素”,让curseqlistnode->next 指向
    9. tempseqlist->length--;
    10. return retSeqListNode;

    从这两个算法都能看出,如果要在pos 位置插入元素 或者 删除元素,那么先要遍历到pos 位置,因此我们在 线性表的头部 做为 栈顶 比较合理。因此不管是插入元素,或者是删除元素,都是对线性表的头部的第一个元素进行处理。

    相关代码:

    1. #ifndef __006LINKSTACK_H__
    2. #define __006LINKSTACK_H__
    3. typedef void LinkStack; //链表的返回值,需要使用void *
    4. typedef struct LinkStackNode { //链表节点
    5. struct LinkStackNode *next;
    6. }LinkStackNode;
    7. // 初始化,建立一个空的链表
    8. //返回值不为NULL,表示创建成功。
    9. //返回值为NULL,表示创建失败。
    10. LinkStack* LinkStack_Create();
    11. //销毁该线性表
    12. //返回值为1,表示成功。
    13. //返回值为-1,表示失败。
    14. int LinkStack_Destory(LinkStack *list);
    15. //清空seqlist
    16. //返回值为1,表示成功。
    17. //返回值为-1,表示失败。
    18. int LinkStack_Clear(LinkStack *list);
    19. // 返回线性表List存在的元素个数
    20. //返回值 >=0 表示:该list存在的元素个数
    21. //<0 表示error
    22. int LinkStack_Length(LinkStack *list);
    23. //从LinkStack 中获取栈顶位置的数据,实际上是 栈的第一个链表的数据
    24. //返回值:为存储在该位置的元素
    25. //返回NULL 表示有问题
    26. LinkStackNode* LinkStack_Get(LinkStack *list);
    27. //给LinkStack中指定位置插入数据,
    28. //参数LinkStackNode为要插入的数据
    29. //参数 pos 为要插入的位置
    30. //成功返回1
    31. //失败 返回<0
    32. int LinkStack_Insert(LinkStack *list, LinkStackNode *node);
    33. //从LinkStack 中删除栈顶位置的元素,实际上删除的链表的除了头结点的第一个元素
    34. //参数 pos
    35. //返回值为 删除的元素
    36. //返回NULL 表示出现了error
    37. LinkStackNode* LinkStack_Delete(LinkStack *list);
    38. //判断当前linkstack 是否为null,如果为null,则返回1
    39. //如果不为NULL,则返回-1
    40. int isEmptyLinkStack(LinkStack *list);
    41. #endif

    1. #include "006linkstack.h"
    2. #include "stdlib.h"
    3. #include "stdio.h"
    4. #include "string.h"
    5. typedef struct LinkStack {
    6. LinkStackNode head;
    7. int length;// 该链表的大小
    8. }TLinkStack;
    9. // 初始化,建立一个空的链表
    10. //返回值不为NULL,表示创建成功。
    11. //返回值为NULL,表示创建失败。
    12. LinkStack* LinkStack_Create() {
    13. TLinkStack * ts = (TLinkStack *)malloc(sizeof(TLinkStack));
    14. if (ts == NULL) {
    15. printf("LinkStack_Create error list==NULL\n");
    16. return NULL;
    17. }
    18. memset(ts, 0, sizeof(TLinkStack));
    19. ts->head.next = NULL;
    20. ts->length = 0;
    21. return ts;
    22. }
    23. //销毁该线性表
    24. //返回值为1,表示成功。
    25. //返回值为-1,表示失败。
    26. int LinkStack_Destory(LinkStack *list) {
    27. int ret = 1;
    28. if (list ==NULL) {
    29. ret = -1;
    30. printf("func LinkStack_Destory error bacesue list = NULL return ret = -1\n");
    31. return ret;
    32. }
    33. TLinkStack * ts = list;
    34. free(ts);
    35. ts = NULL;
    36. list = NULL;
    37. return ret;
    38. }
    39. //清空seqlist
    40. //返回值为1,表示成功。
    41. //返回值为-1,表示失败。
    42. int LinkStack_Clear(LinkStack *list) {
    43. int ret = 1;
    44. if (list == NULL) {
    45. ret = -1;
    46. printf("func LinkStack_Clear error bacesue list = NULL return ret = -1\n");
    47. return ret;
    48. }
    49. TLinkStack * ts = list;
    50. ts->head.next = NULL;
    51. ts->length = 0;
    52. return ret;
    53. }
    54. // 返回线性表List存在的元素个数
    55. //返回值 >=0 表示:该list存在的元素个数
    56. //<0 表示error
    57. int LinkStack_Length(LinkStack *list) {
    58. int ret = 0;
    59. if (list == NULL) {
    60. ret = -1;
    61. printf("func LinkStack_Length error bacesue list = NULL return ret = -1\n");
    62. return ret;
    63. }
    64. TLinkStack * ts = list;
    65. return ts->length;
    66. }
    67. //从LinkStack 中获取指定位置的数据
    68. //参数pos:LinkStack中的位置
    69. //返回值:为存储在该位置的元素
    70. //返回NULL 表示有问题
    71. LinkStackNode* LinkStack_Get(LinkStack *list) {
    72. LinkStackNode* ret = NULL;
    73. if (list == NULL) {
    74. ret = NULL;
    75. printf("func LinkStack_Get error bacesue list = NULL return ret = NULL\n");
    76. return ret;
    77. }
    78. TLinkStack * ts = list;
    79. if (ts->length==0) {
    80. ret = NULL;
    81. printf("func LinkStack_Get error bacesue ts->length = 0 return ret = NULL\n");
    82. return ret;
    83. }
    84. return ts->head.next;
    85. }
    86. //给LinkStack中指定位置插入数据,
    87. //参数LinkStackNode为要插入的数据
    88. //参数 pos 为要插入的位置
    89. //成功返回1
    90. //失败 返回<0
    91. int LinkStack_Insert(LinkStack *list, LinkStackNode *node) {
    92. int ret = 1;
    93. if (list == NULL) {
    94. ret = -1;
    95. printf("func LinkStack_Insert error bacesue list = NULL return ret = -1\n");
    96. return ret;
    97. }
    98. TLinkStack * ts = list;
    99. node->next = ts->head.next;
    100. ts->head.next = node;
    101. ts->length++;
    102. return ret;
    103. }
    104. //从LinkList 中删除指定位置的元素
    105. //参数 pos
    106. //返回值为 删除的元素
    107. //返回NULL 表示出现了error
    108. LinkStackNode* LinkStack_Delete(LinkStack *list) {
    109. LinkStackNode* ret = NULL;
    110. if (list == NULL) {
    111. ret = NULL;
    112. printf("func LinkStack_Delete error bacesue list = NULL return ret = NULL\n");
    113. return ret;
    114. }
    115. TLinkStack * ts = list;
    116. if (ts->length == 0) {
    117. ret = NULL;
    118. printf("func LinkStack_Delete error bacesue ts->length = 0 return ret = NULL\n");
    119. return ret;
    120. }
    121. LinkStackNode * delnode = ts->head.next;
    122. ts->head.next = delnode->next;
    123. ts->length--;
    124. return delnode;
    125. }
    126. //判断当前linkstack 是否为null,如果为null,则返回1
    127. //如果不为NULL,则返回0
    128. //error 则返回-1
    129. int isEmptyLinkStack(LinkStack *list) {
    130. int ret = 0;
    131. if (list == NULL) {
    132. ret = -1;
    133. printf("func isEmptyLinkStack error bacesue list = NULL return ret = -1\n");
    134. return ret;
    135. }
    136. TLinkStack * ts = list;
    137. int length = ts->length;
    138. if (length>0) {
    139. ret = 0;
    140. }
    141. else {
    142. ret = 1;
    143. }
    144. return ret;
    145. }

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #define _CRTDBG_MAP_ALLOC
    3. #include "iostream"
    4. #include <stdio.h>
    5. #include <stdlib.h>
    6. extern "C" {
    7. #include "006linkstack.h"
    8. }
    9. typedef struct Teacher {
    10. LinkStackNode linkstacknode;
    11. int age;
    12. char name[128];
    13. char *othername;
    14. char **stuname; //一个老师下面有5个学生
    15. }Teacher;
    16. int main() {
    17. _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口
    18. int ret = 0;
    19. //初始化队列,要动态的创建SeqStack,根据user设定的大小创建
    20. //int stacksize ,表示user 要创建栈的大小
    21. //创建失败返回NULL
    22. LinkStack* linkstack = LinkStack_Create();
    23. if (linkstack == NULL) {
    24. ret = -1;
    25. printf("func LinkStack_Create error because linkstack = NULL return ret =-1\n");
    26. return ret;
    27. }
    28. ret = isEmptyLinkStack(linkstack);
    29. printf("isEmptyLinkStack = ret %d\n", ret);
    30. ret = LinkStack_Length(linkstack);
    31. printf("LinkStack_Length = ret %d\n", ret);
    32. Teacher tea1;
    33. tea1.age = 20;
    34. strcpy(tea1.name, (const char*)"tea1");
    35. tea1.othername = (char *)malloc(sizeof(char) * 128);
    36. memset(tea1.othername, 0, sizeof(char) * 128);
    37. strcpy(tea1.othername, (const char*)"tea1othername");
    38. tea1.stuname = (char **)malloc(sizeof(char *) * 5);
    39. memset(tea1.stuname, 0, sizeof(char *) * 5);
    40. for (size_t i = 0; i < 5; i++)
    41. {
    42. tea1.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
    43. memset(tea1.stuname[i], 0, sizeof(char) * 128);
    44. sprintf(tea1.stuname[i], "tea1stuname%d", i + 1);
    45. }
    46. Teacher tea2;
    47. tea2.age = 22;
    48. strcpy(tea2.name, (const char*)"tea2");
    49. tea2.othername = (char *)malloc(sizeof(char) * 128);
    50. memset(tea2.othername, 0, sizeof(char) * 128);
    51. strcpy(tea2.othername, (const char*)"tea2othername");
    52. tea2.stuname = (char **)malloc(sizeof(char *) * 5);
    53. memset(tea2.stuname, 0, sizeof(char *) * 5);
    54. for (size_t i = 0; i < 5; i++)
    55. {
    56. tea2.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
    57. memset(tea2.stuname[i], 0, sizeof(char) * 128);
    58. sprintf(tea2.stuname[i], "tea2stuname%d", i + 1);
    59. }
    60. Teacher tea3;
    61. tea3.age = 33;
    62. strcpy(tea3.name, (const char*)"tea3");
    63. tea3.othername = (char *)malloc(sizeof(char) * 128);
    64. memset(tea3.othername, 0, sizeof(char) * 128);
    65. strcpy(tea3.othername, (const char*)"tea3othername");
    66. tea3.stuname = (char **)malloc(sizeof(char *) * 5);
    67. memset(tea3.stuname, 0, sizeof(char *) * 5);
    68. for (size_t i = 0; i < 5; i++)
    69. {
    70. tea3.stuname[i] = (char *)malloc(sizeof(char) * 128);//每个学生名字也有128个字符
    71. memset(tea3.stuname[i], 0, sizeof(char) * 128);
    72. sprintf(tea3.stuname[i], "tea3stuname%d", i + 1);
    73. }
    74. ret = LinkStack_Insert(linkstack, (LinkStackNode * )&tea1);
    75. if (ret < 0) {
    76. printf("LinkStack_Insert(linkstack, (LinkStackNode * )&tea1) func error ret =%d \n", ret);
    77. return ret;
    78. }
    79. ret = LinkStack_Insert(linkstack, (LinkStackNode *)&tea2);
    80. if (ret < 0) {
    81. printf("LinkStack_Insert(linkstack, (LinkStackNode * )&tea2) func error ret =%d \n", ret);
    82. return ret;
    83. }
    84. ret = LinkStack_Insert(linkstack, (LinkStackNode *)&tea3);
    85. if (ret < 0) {
    86. printf("LinkStack_Insert(linkstack, (LinkStackNode * )&tea3) func error ret =%d \n", ret);
    87. return ret;
    88. }
    89. printf("-after-\n");
    90. ret = isEmptyLinkStack(linkstack);
    91. printf("isEmptyLinkStack = ret %d\n", ret);
    92. ret = LinkStack_Length(linkstack);
    93. printf("LinkStack_Length = ret %d\n", ret);
    94. while (LinkStack_Length(linkstack) > 0) {
    95. Teacher * temptea = (Teacher *)LinkStack_Get(linkstack);
    96. if (temptea == NULL) {
    97. printf("can not get find teacher\n");
    98. }
    99. printf("temptea->age = %d,temptea->name = %s,temptea->othername=%s\n",
    100. temptea->age,
    101. temptea->name,
    102. temptea->othername);
    103. for (size_t j = 0; j < 5; j++)
    104. {
    105. printf("temptea->stuname[%d] = %s, ",
    106. j, temptea->stuname[j]);
    107. }
    108. Teacher * deltea = (Teacher *)LinkStack_Delete(linkstack);
    109. if (deltea == NULL) {
    110. printf("LinkStack_Delete seqstack error\n");
    111. }
    112. if (deltea->othername != NULL) {
    113. free(deltea->othername);
    114. }
    115. if (deltea->stuname != NULL) {
    116. for (size_t i = 0; i < 5; i++)
    117. {
    118. if (deltea->stuname[i] != NULL) {
    119. free(deltea->stuname[i]);
    120. }
    121. }
    122. free(deltea->stuname);
    123. deltea->stuname = NULL;
    124. }
    125. printf("\n");
    126. }
    127. printf("sss\n");
    128. //销毁栈
    129. //成功 返回1 表示成功销毁栈
    130. //失败 返回-1 表示该函数执行的时候有问题
    131. ret = LinkStack_Destory(linkstack);
    132. return 0;
    133. }

    相关应用:实现编译器中的符号成对检测

    //几乎所有的编译器都具有检测括号是否匹配的能力,
    //那么如何实现编译器中的符号成对检测?如下字符串:
    //5 + 5 * (6) + 9 / 3 * 1) - (1 + 3(
    //算法思路
    //
    //从第一个字符开始扫描
    //当遇见普通字符时忽略,
    //当遇见左括号时压入栈中
    //当遇见右括号时从栈中弹出栈顶符号,并进行匹配
    //匹配成功:继续读入下一个字符
    //匹配失败:立即停止,并报错
    //结束:
    //成功 : 所有字符扫描完毕,且栈为空
    //    失败:匹配失败或所有字符扫描完毕但栈非空

    //总结:
    //当需要检测成对出现但又互不相邻的事物时可以使用栈“后进先出”的特性

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #define _CRTDBG_MAP_ALLOC
    3. #include "iostream"
    4. #include <stdio.h>
    5. #include <stdlib.h>
    6. //几乎所有的编译器都具有检测括号是否匹配的能力,
    7. //那么如何实现编译器中的符号成对检测?如下字符串:
    8. //5 + 5 * (6) + 9 / 3 * 1) - (1 + 3(
    9. //算法思路
    10. //
    11. //从第一个字符开始扫描
    12. //当遇见普通字符时忽略,
    13. //当遇见左括号时压入栈中
    14. //当遇见右括号时从栈中弹出栈顶符号,并进行匹配
    15. //匹配成功:继续读入下一个字符
    16. //匹配失败:立即停止,并报错
    17. //结束:
    18. //成功 : 所有字符扫描完毕,且栈为空
    19. // 失败:匹配失败或所有字符扫描完毕但栈非空
    20. //总结:
    21. //当需要检测成对出现但又互不相邻的事物时可以使用栈“后进先出”的特性
    22. char *err1 = (char *)"无法找到对应的右括号的 左括号";
    23. char *err2 = (char *)"该 左括号 没有对应的有括号";
    24. extern "C" {
    25. #include "004seqstack.h"
    26. }
    27. int isLeft( char ch) {
    28. if ('(' == ch) {
    29. return 1;
    30. }
    31. return 0;
    32. }
    33. int isRight(char ch) {
    34. if (')' == ch) {
    35. return 1;
    36. }
    37. return 0;
    38. }
    39. void printerror(char* err,char *str, char *ptemp) {
    40. printf("err start");
    41. printf(err);
    42. printf("原始字符串如下\n");
    43. printf(str);
    44. printf("\n");
    45. printf("error位置如下\n");
    46. int num = ptemp - str;
    47. while (num > 0 ) {
    48. printf(" ");
    49. --num;
    50. }
    51. printf("|\n");
    52. printf("err end");
    53. }
    54. void testchar(char *str) {
    55. SeqStack * seqstack = createSeqStack(1024);
    56. if (seqstack ==NULL) {
    57. printf("func testchar error because seqstack==NULL\n");
    58. return;
    59. }
    60. if (str == NULL) {
    61. printf("testchar func error because str==NULL\n");
    62. return;
    63. }
    64. char *ptemp = str;//让辅助指针变量指向传递过来的str
    65. while (*(ptemp) != '\0') {
    66. if (isLeft(*ptemp)) { 当遇见左括号时压入栈中.判断是否是符号,如果是 左括号 符号,则要进栈,
    67. push_SeqStack(seqstack,ptemp);
    68. }
    69. if (isRight(*ptemp)) {//当遇见右括号时从栈中弹出栈顶符号,并进行匹配
    70. //如果这时候栈中啥也没有,就有问题,直接break;
    71. if (size_SeqStack(seqstack) == 0) {
    72. printerror(err1,str,ptemp);
    73. break;
    74. }
    75. pop_SeqStack(seqstack);
    76. }
    77. ptemp++;
    78. }
    79. //当将整个字符串都弄完成后,检查栈中是否有元素,如果栈中有元素,说明有左括号没有匹配
    80. while (size_SeqStack(seqstack) > 0 ) {
    81. printerror(err2, str, (char *)top_SeqStack(seqstack));
    82. pop_SeqStack(seqstack);
    83. }
    84. }
    85. int main() {
    86. int ret = 0;
    87. _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口
    88. //char* sourcestr = (char *)"5 + 5 * (6) + 9 / 3 * 1) - (1 + 3(";
    89. char* sourcestr = (char *)"5 + 5 * (6) + 9 / 3 * 1 - (1 + 3(";
    90. testchar(sourcestr);
    91. return ret;
    92. }

  • 相关阅读:
    利用Kali进行DDOS泛洪演练
    Kubernetes 控制平面组件:etcd
    Windows10不常用操作(录屏、开启超级管理员、关闭自动IP配置、Edge崩溃等)
    当资本对于区块链的关注开始减退,一场降温开始在区块链行业上演
    LeCun和Bengio“吵”起来了,人工智能是“潘多拉魔盒”吗?
    如何确认串口波特率
    SpringBoot集成MyBatis
    django DRF增删改查查
    如何才能在人力RPO蓝海项目中实现盈利呢?
    MySQL单表查询进阶
  • 原文地址:https://blog.csdn.net/hunandede/article/details/138039026