当前位置:   article > 正文

数据结构【栈和队列】

数据结构【栈和队列】

目录

概念与结构

栈的实现

栈的数据

栈的初始化

入栈

出栈

取栈顶元素

获取有效个数

栈的销毁

队列

概念与结构

队列的实现

队列的数据

初始化队列

入队列

出队列

取队头数据

取队尾数据

获取有效个数

队列销毁

栈的代码

stack.h

stack.c

test.c

队列的代码

Queue.h

Queue.c

test.c


概念与结构

栈:⼀种特殊的线性表,其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作 的⼀端称为栈顶,另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插⼊操作叫做进栈/压栈/⼊栈,⼊数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

栈底层结构选型。

栈的实现⼀般可以使⽤数组或者链表实现,相对⽽⾔数组的结构实现更优⼀些。因为数组在尾上插⼊ 数据的代价⽐较⼩。

栈的实现

栈我们用顺序表来实现

栈的数据

arr就是数组,给arr申请空间后就是数组了。

空间就是有多少个空间。

栈顶是用来进栈和出栈的。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<stdbool.h>
  4. #include<assert.h>
  5. typedef int data;
  6. typedef struct stack
  7. {
  8. data* arr;//存放数值
  9. int koj; //空间
  10. int top; //栈顶
  11. }stack;

栈的初始化

  1. //初始化
  2. void stack_csh(stack* r);

把arr置为空。

把koj和栈顶置为0。 

  1. //初始化
  2. void stack_csh(stack* r)
  3. {
  4. assert(r);
  5. r->arr = NULL;
  6. r->koj = r->top = 0;
  7. }

入栈

  1. //入栈
  2. void stack_push(stack* r, data x);

思路:先判断空间够不够,不够就2倍增容。

够的话,在栈顶的位置插入数据x。

  1. //入栈
  2. void stack_push(stack* r, data x)
  3. {
  4. assert(r);
  5. //空间大小等于栈顶,就说明空间不够
  6. if (r->koj == r->top)
  7. {
  8. int koj1 = r->koj == 0 ? 4 : 2 * r->koj;
  9. stack* tab = (stack*)realloc(r->arr, sizeof(stack));
  10. if (tab == NULL)
  11. {
  12. perror("realloc");
  13. exit(1);
  14. }
  15. //把新申请的空间给r
  16. r->arr = tab;
  17. r->koj = koj1;
  18. }
  19. //空间够直接入栈
  20. r->arr[r->top] = x;
  21. r->top++;
  22. }

  1. void p()
  2. {
  3. stack add;
  4. //初始化栈
  5. stack_csh(&add);
  6. //入栈
  7. stack_push(&add,1);
  8. stack_push(&add,2);
  9. stack_push(&add,3);
  10. stack_push(&add,4);
  11. }
  12. int main()
  13. {
  14. p();
  15. return 0;
  16. }

出栈

  1. //布尔类型
  2. bool buer(stack* r);
  3. //出栈
  4. void stack_pop(stack* r);

布尔类型,栈顶为0返回真,不为0返回假

  1. //布尔类型
  2. bool buer(stack* r)
  3. {
  4. assert(r);
  5. return r->top == 0;
  6. }

这里布尔类型接收真,假,这个逻辑非!把真变假,把假变真。

栈的删除操作叫做出栈。

我们只需要让,栈顶减减就行了

  1. //出栈
  2. void stack_pop(stack* r)
  3. {
  4. assert(r);
  5. //布尔类型
  6. assert(!buer(r));
  7. r->top--;
  8. }

出栈我们可以用循环来出栈,也可以用4条来出栈。


取栈顶元素

  1. //取栈顶
  2. data stack_top(stack* r);


arr数组的栈顶减1这个位置就可以拿到4。

  1. //取出栈顶
  2. data stack_top(stack* r)
  3. {
  4. assert(r);
  5. assert(!buer(r));
  6. return r->arr[r->top - 1];
  7. }

取出栈顶的数据赋值给tab,然后打印出来。然后出栈

  1. while (!buer(&add))
  2. {
  3. //取出栈顶数据
  4. data tab = stack_top(&add);
  5. printf("%d ", tab);
  6. //出栈
  7. stack_pop(&add);
  8. }

获取有效个数

  1. //获取有效个数
  2. data stack_size(stack* r);

我们直接返回top就行了。

  1. //有效个数
  2. data stack_size(stack* r)
  3. {
  4. assert(r);
  5. return r->top;
  6. }

当前有效个数是4,循环出栈后,有效个数是0


栈的销毁

  1. //销毁
  2. void xiaoh(stack* r);

判断arr这个空间是不是空,不是空释放arr空间,

koj和top赋值为0。

  1. //销毁
  2. void xiaoh(stack* r)
  3. {
  4. assert(r);
  5. if (r->arr != NULL)
  6. {
  7. free(r->arr);
  8. }
  9. r->arr = NULL;
  10. r->koj = r->top = 0;
  11. }

队列

概念与结构

概念:只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先 出FIFO(First In First Out)

⼊队列:进⾏插⼊操作的⼀端称为队尾

出队列:进⾏删除操作的⼀端称为队头

队列底层结构选型

队列也可以数组和链表的结构实现,使⽤链表的结构实现更优⼀些,因为如果使⽤数组的结构,出队 列在数组头上出数据,效率会⽐较低。


队列的实现

创建3个文件,test.c测试文件,Queue.h头文件,Queue.c函数文件


队列的数据

  1. typedef int data;
  2. typedef struct queuedata//单链表
  3. {
  4. data arr;//存放的数据
  5. struct queuedata* p;//指向下一个节点
  6. }queuedata;
  7. typedef struct Queue
  8. {
  9. queuedata* to; //队头——单链表的 头节点
  10. queuedata* wei;//队尾——单链表的 尾节点
  11. int size; //有效个数
  12. }Queue;

初始化队列

  1. //初始化
  2. void csh(Queue* r);

我们只需要把队头和队尾置为NULL,有效个数给0。

  1. //初始化
  2. void csh(Queue* r)
  3. {
  4. assert(r);
  5. r->to = r->wei = NULL;
  6. r->size = 0;
  7. }


入队列

入队列要从队尾进入

  1. //入队,队尾
  2. void dui_wei(Queue* r,data x);

思路:

1.申请一个单链表的空间,把x给新申请的空间,

2.判断队尾是不是空,是空当前链表里没有数据,所以让队头和队尾指向新申请的空间,

3.不是空,这个和单链表的尾插差不多,队尾的p指向新申请的空间,

有效个数加1

  1. //入队尾
  2. void dui_wei(Queue* r,data x)
  3. {
  4. assert(r);
  5. //申请单链表空间
  6. queuedata* tab = (queuedata*)malloc(sizeof(queuedata));
  7. if (tab == NULL)
  8. {
  9. perror("malloc");
  10. exit(1);
  11. }
  12. //把x赋值给新申请空间的arr
  13. tab->arr = x;
  14. tab->p = NULL;
  15. //入队
  16. //判断队尾是不是空
  17. if (r->wei == NULL)
  18. {
  19. //是空,队头队尾指向新申请的空间
  20. r->to = r->wei = tab;
  21. }
  22. else//不是空
  23. {
  24. //队尾p指向新申请的空间
  25. r->wei->p = tab;
  26. //队尾走到新申请的空间
  27. r->wei = r->wei->p;
  28. }
  29. //有效个数加1
  30. r->size++;
  31. }

我们可以看到插入了4个数据1,2,3,4,有效个数是4

  1. void p()
  2. {
  3. Queue add;
  4. //初始化
  5. csh(&add);
  6. //入队,尾
  7. dui_wei(&add, 1);
  8. dui_wei(&add, 2);
  9. dui_wei(&add, 3);
  10. dui_wei(&add, 4);
  11. }
  12. int main()
  13. {
  14. p();
  15. return 0;
  16. }

出队列

出队列:进⾏删除操作的⼀端称为队头

出队列要从队头出,


出队列,我们要用布尔类型,判断链表是不是空,是空不能出队列,报错。

  1. //布尔类型
  2. bool buer(Queue* r);
  3. //出队列
  4. void dui_to(Queue* r);

布尔判断队头是不是等于空,是返回真,不是返回假。

  1. //布尔类型
  2. bool buer(Queue* r)
  3. {
  4. assert(r);
  5. return r->to == NULL;
  6. }

思路:判断队头等于队尾,说明只有一个节点。直接释放就行了,

不等于说明有链表里有空间,把头节点的下一个节点给tab,释放头节点,再把tab给头节点。

有效个数减1

  1. //出队,头
  2. void dui_to(Queue* r)
  3. {
  4. assert(r);
  5. //布尔类型,!把真变假,把假变真
  6. assert(!buer(r));
  7. //判断队头等于队尾,就说明只有一个节点
  8. if (r->to == r->wei)
  9. {
  10. //直接释放空间
  11. free(r->to);
  12. //把队头和队尾置为空
  13. r->to = r->wei = NULL;
  14. }
  15. else
  16. {
  17. //把队头的下一个节点给tab
  18. queuedata* tab = r->to->p;
  19. //释放当前队头节点
  20. free(r->to);
  21. //把tab节点给队头
  22. r->to = tab;
  23. }
  24. //有效个数减1
  25. --r->size;
  26. }

取队头数据

  1. //取队头数据
  2. data qto(Queue* r);

直接返回头节点的数据就行了

  1. //取队头数据
  2. data qto(Queue* r)
  3. {
  4. assert(r);
  5. assert(!buer(r));
  6. return r->to->arr;
  7. }

printf("头:%d\n", qto(&add));

取队尾数据

  1. //取队尾数据
  2. data qwei(Queue* r);

直接返回队尾的数据就行了。

  1. //取尾
  2. data qwei(Queue* r)
  3. {
  4. assert(r);
  5. assert(!buer(r));
  6. return r->wei->arr;
  7. }

printf("尾:%d\n", qwei(&add));

获取有效个数

  1. //有效个数
  2. data size(Queue* r);

  1. //有效个数
  2. data size(Queue* r)
  3. {
  4. assert(r);
  5. return r->size;
  6. }

printf("size:%d\n", size(&add));

队列销毁

  1. //销毁
  2. void xiaoh(Queue* r);

把队头给tab,让tab循环销毁单链表,add保存头节点的下一个节点,释放头节点,把add给tab,

把队头和队尾置为NULL,有效个数给0。

  1. //销毁
  2. void xiaoh(Queue* r)
  3. {
  4. assert(r);
  5. assert(!buer(r));
  6. //把队头给tab
  7. queuedata* tab = r->to;
  8. //循环销毁单链表
  9. while (tab != NULL)
  10. {
  11. //add保存头节点的下一个节点
  12. queuedata* add = tab->p;
  13. //释放头节点
  14. free(tab);
  15. //把add给tab
  16. tab = add;
  17. }
  18. //把队头和队尾置为空
  19. r->to = r->wei = NULL;
  20. //有效个数赋值为0
  21. r->size = 0;
  22. }

栈的代码

stack.h
  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<assert.h>
  6. typedef int data;
  7. typedef struct stack
  8. {
  9. data* arr;//存放数值
  10. int koj; //空间
  11. int top; //栈顶
  12. }stack;
  13. //初始化
  14. void stack_csh(stack* r);
  15. //入栈
  16. void stack_push(stack* r, data x);
  17. //布尔类型
  18. bool buer(stack* r);
  19. //出栈
  20. void stack_pop(stack* r);
  21. //取栈顶
  22. data stack_top(stack* r);
  23. //获取有效个数
  24. data stack_size(stack* r);
  25. //销毁
  26. void xiaoh(stack* r);
stack.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"stack.h"
  3. //初始化
  4. void stack_csh(stack* r)
  5. {
  6. assert(r);
  7. r->arr = NULL;
  8. r->koj = r->top = 0;
  9. }
  10. //入栈
  11. void stack_push(stack* r, data x)
  12. {
  13. assert(r);
  14. //空间大小等于栈顶,就说明空间不够
  15. if (r->koj == r->top)
  16. {
  17. int koj1 = r->koj == 0 ? 4 : 2 * r->koj;
  18. stack* tab = (stack*)realloc(r->arr, sizeof(stack));
  19. if (tab == NULL)
  20. {
  21. perror("realloc");
  22. exit(1);
  23. }
  24. //把新申请的空间给r
  25. r->arr = tab;
  26. r->koj = koj1;
  27. }
  28. //空间够直接入栈
  29. r->arr[r->top] = x;
  30. r->top++;
  31. }
  32. //布尔类型
  33. bool buer(stack* r)
  34. {
  35. assert(r);
  36. return r->top == 0;
  37. }
  38. //出栈
  39. void stack_pop(stack* r)
  40. {
  41. assert(r);
  42. //布尔类型
  43. assert(!buer(r));
  44. r->top--;
  45. }
  46. //取出栈顶
  47. data stack_top(stack* r)
  48. {
  49. assert(r);
  50. assert(!buer(r));
  51. return r->arr[r->top - 1];
  52. }
  53. //有效个数
  54. data stack_size(stack* r)
  55. {
  56. assert(r);
  57. return r->top;
  58. }
  59. //销毁
  60. void xiaoh(stack* r)
  61. {
  62. assert(r);
  63. if (r->arr != NULL)
  64. {
  65. free(r->arr);
  66. }
  67. r->arr = NULL;
  68. r->koj = r->top = 0;
  69. }
test.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"stack.h"
  3. void p()
  4. {
  5. stack add;
  6. //初始化栈
  7. stack_csh(&add);
  8. //入栈
  9. stack_push(&add,1);
  10. stack_push(&add,2);
  11. stack_push(&add,3);
  12. stack_push(&add,4);
  13. //出栈
  14. /*stack_pop(&add);
  15. stack_pop(&add);
  16. stack_pop(&add);
  17. stack_pop(&add);*/
  18. printf("size:%d\n", stack_size(&add));
  19. while (!buer(&add))
  20. {
  21. //取出栈顶数据
  22. data tab = stack_top(&add);
  23. printf("%d ", tab);
  24. //出栈
  25. stack_pop(&add);
  26. }
  27. printf("size:%d\n", stack_size(&add));
  28. //销毁
  29. xiaoh(&add);
  30. }
  31. int main()
  32. {
  33. p();
  34. return 0;
  35. }

队列的代码

Queue.h
  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. #include<stdbool.h>
  6. typedef int data;
  7. typedef struct queuedata//单链表
  8. {
  9. data arr;//存放的数据
  10. struct queuedata* p;//指向下一个节点
  11. }queuedata;
  12. typedef struct Queue
  13. {
  14. queuedata* to; //队头——单链表的 头节点
  15. queuedata* wei;//队尾——单链表的 尾节点
  16. int size; //有效个数
  17. }Queue;
  18. //初始化
  19. void csh(Queue* r);
  20. //入队,队尾
  21. void dui_wei(Queue* r,data x);
  22. //布尔类型
  23. bool buer(Queue* r);
  24. //出队列
  25. void dui_to(Queue* r);
  26. //取队头数据
  27. data qto(Queue* r);
  28. //取队尾数据
  29. data qwei(Queue* r);
  30. //有效个数
  31. data size(Queue* r);
  32. //销毁
  33. void xiaoh(Queue* r);
Queue.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"Queue.h"
  3. //初始化
  4. void csh(Queue* r)
  5. {
  6. assert(r);
  7. r->to = r->wei = NULL;
  8. r->size = 0;
  9. }
  10. //入队尾
  11. void dui_wei(Queue* r,data x)
  12. {
  13. assert(r);
  14. //申请单链表空间
  15. queuedata* tab = (queuedata*)malloc(sizeof(queuedata));
  16. if (tab == NULL)
  17. {
  18. perror("malloc");
  19. exit(1);
  20. }
  21. //把x赋值给新申请空间的arr
  22. tab->arr = x;
  23. tab->p = NULL;
  24. //入队
  25. //判断队尾是不是空
  26. if (r->wei == NULL)
  27. {
  28. //是空,队头队尾指向新申请的空间
  29. r->to = r->wei = tab;
  30. }
  31. else//不是空
  32. {
  33. //队尾p指向新申请的空间
  34. r->wei->p = tab;
  35. //队尾走到新申请的空间
  36. r->wei = r->wei->p;
  37. }
  38. //有效个数加1
  39. r->size++;
  40. }
  41. //布尔类型
  42. bool buer(Queue* r)
  43. {
  44. assert(r);
  45. return r->to == NULL;
  46. }
  47. //出队,头
  48. void dui_to(Queue* r)
  49. {
  50. assert(r);
  51. //布尔类型,!把真变假,把假变真
  52. assert(!buer(r));
  53. //判断队头等于队尾,就说明只有一个节点
  54. if (r->to == r->wei)
  55. {
  56. //直接释放空间
  57. free(r->to);
  58. //把队头和队尾置为空
  59. r->to = r->wei = NULL;
  60. }
  61. else
  62. {
  63. //把队头的下一个节点给tab
  64. queuedata* tab = r->to->p;
  65. //释放当前队头节点
  66. free(r->to);
  67. //把tab节点给队头
  68. r->to = tab;
  69. }
  70. //有效个数减1
  71. --r->size;
  72. }
  73. //取队头数据
  74. data qto(Queue* r)
  75. {
  76. assert(r);
  77. assert(!buer(r));
  78. return r->to->arr;
  79. }
  80. //取尾
  81. data qwei(Queue* r)
  82. {
  83. assert(r);
  84. assert(!buer(r));
  85. return r->wei->arr;
  86. }
  87. //有效个数
  88. data size(Queue* r)
  89. {
  90. assert(r);
  91. return r->size;
  92. }
  93. //销毁
  94. void xiaoh(Queue* r)
  95. {
  96. assert(r);
  97. assert(!buer(r));
  98. //把队头给tab
  99. queuedata* tab = r->to;
  100. //循环销毁单链表
  101. while (tab != NULL)
  102. {
  103. //add保存头节点的下一个节点
  104. queuedata* add = tab->p;
  105. //释放头节点
  106. free(tab);
  107. //把add给tab
  108. tab = add;
  109. }
  110. //把队头和队尾置为空
  111. r->to = r->wei = NULL;
  112. //有效个数赋值为0
  113. r->size = 0;
  114. }
test.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"Queue.h"
  3. void p()
  4. {
  5. Queue add;
  6. //初始化
  7. csh(&add);
  8. //入队,尾
  9. dui_wei(&add, 1);
  10. dui_wei(&add, 2);
  11. dui_wei(&add, 3);
  12. dui_wei(&add, 4);
  13. printf("头:%d\n", qto(&add));
  14. printf("尾:%d\n", qwei(&add));
  15. printf("size:%d\n", size(&add));
  16. //销毁
  17. xiaoh(&add);
  18. }
  19. int main()
  20. {
  21. p();
  22. return 0;
  23. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号