当前位置:   article > 正文

数据结构之栈和队列

数据结构之栈和队列

基础知识:

栈是一种逻辑结构,是特殊的线性表,特殊在只能在固定一端操作,具有"后进先出"的基本特征(泡腾片的取和放一样)

  1. 栈顶 : 可以进行插入删除的一端

  2. 栈底:栈顶的对端

  3. 入栈: 将节点插入栈顶之上,也称为压栈,函数名通常为push()

  4. 出栈:将节点从栈顶剔除,也称为弹栈,函数名通常额外pop()

  5. 取栈顶: 取得栈顶元素,但不出栈,函数名通常为top()

存储方式

栈只是一种数据逻辑,可以采用顺序存储形成顺序栈或者采用链式存储形成链式栈。

顺序栈

  1. // 顺序栈管理结构体
  2. typedef struct
  3. {
  4. datatype *data; // 顺序栈入口
  5. int size; // 顺序栈总容量
  6. int top; // 顺序栈栈顶元素下标
  7. }seqStack;
  8. // 初始化空栈
  9. seqStack *initStack(int size)
  10. {
  11. seqStack *s = (seqStack *)malloc(sizeof(seqStack))
  12. if(s != NULL)
  13. {
  14. s->data = (datatype *)malloc(sizeof(datatype) * size));
  15. if(s->data == NULL)
  16. {
  17. free(s);
  18. return NULL;
  19. }
  20. s->size = size;
  21. s->top = -1;
  22. }
  23. return s;
  24. }
  25. // 判断栈是否已满
  26. bool isFull(seqStack *s)
  27. {
  28. return s->top == s->size-1;
  29. }
  30. // 判断栈是否为空
  31. bool isEmpty(seqStack *s)
  32. {
  33. return s->top == -1;
  34. }
  35. // 入栈
  36. bool push(seqStack *s, datatype data)
  37. {
  38. if(isFull(s))
  39. return false;
  40. s->data[++s->top] = data;
  41. return true;
  42. }
  43. // 出栈
  44. bool pop(seqStack *s, datatype *pm)
  45. {
  46. if(top(s, pm) == false)
  47. return false;
  48. s->top--;
  49. return true;
  50. }
  51. // 取栈顶元素
  52. bool top(seqStack *s, datatype *pm)
  53. {
  54. if(isEmpty(s))
  55. return false;
  56. *pm = s->data[s->top];
  57. return true;
  58. }

链式栈

  1. // 链式栈节点
  2. typedef struct node
  3. {
  4. datatype data;
  5. struct node *next;
  6. }node;
  7. // 链式栈管理结构体
  8. typedef struct linkStack
  9. {
  10. node *top; // 链式栈栈顶指针
  11. int size; // 链式栈当前元素个数
  12. }linkStack;
  13. // 初始化空栈
  14. linkStack * initStack(void)
  15. {
  16. linkStack * s = (linkStack *)malloc(sizeof(linkStack));
  17. if(s != NULL)
  18. {
  19. s->top = NULL;
  20. s->size = 0;
  21. }
  22. return s;
  23. }
  24. // 判断栈是否为空
  25. bool isEmpty(linkStack *s)
  26. {
  27. return (top->size == 0);
  28. }
  29. // 入栈
  30. bool push(linkStack *s, datatype data)
  31. {
  32. // 创建链表节点
  33. node *new = (node *)malloc(sizeof(node));
  34. if(new == NULL)
  35. return false;
  36. new->data = data;
  37. // 将节点置入栈顶
  38. new->next = s->top;
  39. s->top = new;
  40. // 更新栈元素个数
  41. s->size++;
  42. return true;
  43. }
  44. // 出栈
  45. bool pop(linkStack *s, datatype *pm)
  46. {
  47. if(isEmpty(s))
  48. return false;
  49. linkStack *tmp = s->top;
  50. // 将原栈顶元素剔除出栈
  51. s->top = tmp->next;
  52. tmp->next = NULL;
  53. // 返回栈顶元素,并释放节点
  54. *pm = tmp->data;
  55. free(tmp);
  56. return true;
  57. }
  58. // 取栈顶元素
  59. bool top(linkStack *s, datatype *pm)
  60. {
  61. if(isEmpty(s))
  62. return false;
  63. // 返回栈顶元素,并释放节点
  64. *pm = s->top->data;
  65. return true;
  66. }

队列

只能在固定的两端操作线性表,呈现一种“先进先出”的逻辑。

基础知识:

  • 队头:可以删除节点的一端

  • 队尾:可以插入节点的一端

  • 入队:将节点插入到队尾之后,函数名通常为enQueue()

  • 出队:将队头节点从队列中剔除,函数名通常为outQueue()

  • 取队头:取得队头元素,但不出队,函数名通常为front()

 存储方式

与其他的逻辑结构类似,队列可以采用顺序存储形成循环队列,也可以采用链式存储形成链式队列。

循环队列

如图,头指针+1= 尾指针则队列为满,尾指针=头指针则队列为空。

  1. struct seqQueue
  2. {
  3. datatype *data; // 循环队列入口
  4. int capacity; // 循环队列总容量
  5. int front; // 循环队列队头元素下标
  6. int rear; // 循环队列队头元素下标
  7. };
  8. // 初始化空队列
  9. seqQueue * initQueue(int cap)
  10. {
  11. *pq = (sequeue *)malloc(sizeof(sequeue));
  12. (*pq)->front = (*pq)->rear = MAXSIZE - 1;
  13. }
  14. // 判断队列是否为空
  15. bool isEmpty(seqQueue *q)
  16. {
  17. return q->front == q->rear;
  18. }
  19. // 判断队列是否已满
  20. bool isFull(seqQueue *q)
  21. {
  22. return (q->rear+1)%q->capacity == q->front;
  23. }
  24. // 出队
  25. bool outQueue(seqQueue *q, datatype *pm)
  26. {
  27. if(isEmpty(q))
  28. return false;
  29. *pm = q->data[q->front];
  30. q->front = (q->front + 1) % q->capacity;
  31. return true;
  32. }
  33. // 入队
  34. bool enQueue(seqQueue *q, datatype data)
  35. {
  36. if(isFull(q))
  37. return false;
  38. q->data[q->rear] = data;
  39. q->rear = (q->rear + 1) % q->capacity;
  40. return true;
  41. }

链式队列

链式队列的组织形式与链表无异,只不过插入删除被约束在固定的两端。

  1. // 链式队列节点
  2. typedef struct node
  3. {
  4. datatype data;
  5. struct node *next;
  6. }node;
  7. // 链式队列管理结构体
  8. typedef struct
  9. {
  10. node *front; // 队头指针
  11. node *rear; // 队尾指针
  12. int size; // 队列当前元素个数
  13. }linkQueue;
  14. // 初始化空队列
  15. linkQueue *initQueue()
  16. {
  17. linkQueue *q = (linkQueue *)malloc(sizeof(linkQueue))
  18. if(q != NULL)
  19. {
  20. q->front = NULL;
  21. q->rear = NULL;
  22. q->size = 0;
  23. }
  24. return q;
  25. }
  26. // 判断队列是否为空
  27. bool isEmpty(linkQueue *q)
  28. {
  29. return q->size == 0;
  30. }
  31. // 入队
  32. bool enQueue(linkQueue *q, datatype data)
  33. {
  34. // 创建新节点
  35. node *new = malloc(sizeof(node));
  36. if(new == NULL)
  37. return false;
  38. new->data = data;
  39. new->next = NULL;
  40. // 入队分两种情况:
  41. // 1. 当前队列为空,则新节点是队列的唯一节点
  42. if(isEmpty(q))
  43. q->front = q->rear = new;
  44. // 2. 否则队列不为空,将新节点拼接到队尾之后
  45. else
  46. {
  47. q->rear->next = new;
  48. q->rear = new;
  49. }
  50. q->size++;
  51. return true;
  52. }
  53. // 出队
  54. bool outQueue(linkQueue *q, datatype *pm)
  55. {
  56. if(isEmpty(q))
  57. return false;
  58. // 返回用户数据
  59. *pm = q->front->data;
  60. // 更新队头队尾指针,分两种情况:
  61. // 1. 当前队列只有一个元素,出队后队列为空,此时队头队尾指针都必须更新
  62. if(q->size == 1)
  63. {
  64. free(q->front);
  65. q->front = NULL;
  66. q->rear = NULL;
  67. }
  68. // 2. 否则,只需更新队头指针即可
  69. else
  70. {
  71. node *tmp = q->front;
  72. q->front = q->front->next;
  73. tmp->next = NULL;
  74. free(tmp);
  75. }
  76. q->size--;
  77. return true;
  78. }
  79. // 取队头元素
  80. bool front(linkQueue *q, datatype *pm)
  81. {
  82. if(isEmpty(q))
  83. return false;
  84. *pm = q->front->data;
  85. return true;
  86. }

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

闽ICP备14008679号