当前位置:   article > 正文

C语言实现栈与队列_堆栈和队列c语言

堆栈和队列c语言

一.栈的定义

  1.栈:是只允许在一边进行插入或删除的顺序表。■特别之处在于只能在一端进行删除、插入。

  2.栈顶:进行删除或插入操作的一端。

  3.栈底:不能进行删除或插入的一端。

二.栈的算法

 
栈的实现可以用数组(顺序表),也可以使用链表,这里使用顺序表来实现。栈的常见操作有栈的初始化、销毁、增删等等,以下是栈创建过程中使用的函数。

  1.宏定义(初始准备)

  不直接定义一个数组,而采用realloc、malloc来动态管理顺序表大小,使栈的大小不再受限。再定义一个top栈顶指针来方便后续的增删操作。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<assert.h>
  4. #include<stdbool.h>
  5. typedef int MyDataType;//将int类型重定义叫做MyDataType
  6. typedef struct Stack
  7. {
  8. MyDataType* a;//一个MyDataType类型的指针,可以进行动态内存开辟
  9. int capacity;//栈的最大容量
  10. int top;//用于栈顶指针
  11. }ST;

2.栈的初始化

  在初始化中,将top栈顶指针指向0,但此时栈中没有元素(此时栈为空)。当然也可以将top初始化为-1,此时当top为0时栈中含有一个元素。

  1. ST st;//在测试代码中预先定义一个ST类型的变量
  2. void InitStack(ST* ps)
  3. {
  4. assert(ps);
  5. ps->a = NULL;
  6. ps->capacity = 0;
  7. ps->top = 0;//将栈顶指针指向0
  8. }

3.向栈顶插入元素

   在插入数据前,需要判断ps指针是否为空,还要判断栈是否已经达到最大容量,如果size=capacity(栈已达到最大容量)就需要使用realloc扩容(注意:使用realloc函数时,若第一个参数为空,则函数返回一个开辟了指定大小的地址)。当top初始化为0时,先赋值,在++top;而当top初始化为-1时,先++top,再赋值。

  1. void PushStack(ST* ps, MyDataType x)
  2. {
  3. assert(ps);
  4. if (ps->top == ps->capacity)
  5. {
  6. int NewSize = ps->top == 0 ? 4 : ps->capacity * 2;//用三目运算符可以避免对top是否为零的两种情况进行讨论
  7. MyDataType* temp = (MyDataType*)realloc(ps->a, sizeof(MyDataType) * NewSize);
  8. if (temp == NULL)
  9. {
  10. perror("realloc");
  11. exit(-1);
  12. }
  13. ps->a = temp;
  14. ps->capacity = NewSize;
  15. }
  16. ps->a[ps->top] = x;
  17. ps->top++;//先赋值再将top加一
  18. }

4.判断栈是否为空

  1. bool StackEmpty(ST* ps)
  2. {
  3. assert(ps);
  4. return ps->top == 0;//ps->top为0,表达式为真返回true
  5. }

 5.删除栈顶元素

  删除栈顶元素之前首先需要判断栈是否为空,如果为空则不能删除元素。顺序表删除尾部元素十分简单,只需要将栈顶指针指向的位置减一即可。

  1. void PopStack(ST* ps)
  2. {
  3. assert(ps);
  4. assert(ps->top > 0);
  5. --ps->top;
  6. }

6.计算栈中元素个数

  由于对top初始化时的值不同,计数的条件不同,所以读取个数的操作也由我们来书写,而不由使用者自己来判断。

  1. int StackSize(ST* ps)
  2. {
  3. assert(ps);
  4. assert(ps->top >= 0);
  5. return ps->top ;
  6. }

7.读取栈顶元素

  1. MyDataType StackTop(ST* ps)
  2. {
  3. assert(ps);
  4. assert(ps->top > 0);//需要判断栈是否为空,为空则不能读取栈顶元素
  5. return ps->a[ps->top-1];
  6. }

8.销毁栈

  销毁需要把动态开辟的空间全部释放,并将指针置为空。

  1. void DestroyStack(ST* ps)
  2. {
  3. assert(ps);
  4. free(ps->a);
  5. ps->a = NULL;
  6. ps->capacity = ps->top = 0;
  7. }

三.栈的例题

题目链接:

有效的括号

题目解答:

栈的特点是后入先出,与括号之间匹配判断一致

  1. typedef char MyDataType;
  2. typedef struct Stack
  3. {
  4. MyDataType* a;
  5. int capacity;
  6. int top;
  7. }ST;
  8. void InitStack(ST*ps);
  9. void PushStack(ST* ps,MyDataType x);
  10. void PopStack(ST* ps);
  11. void DestroyStack(ST* ps);
  12. bool StackEmpty(ST* ps);
  13. MyDataType StackTop(ST* ps);
  14. int StackSize(ST* ps);
  15. void InitStack(ST* ps)
  16. {
  17. assert(ps);
  18. ps->a = NULL;
  19. ps->capacity = 0;
  20. ps->top = 0;
  21. }
  22. void PushStack(ST* ps, MyDataType x)
  23. {
  24. assert(ps);
  25. if (ps->top == ps->capacity)
  26. {
  27. int NewSize = ps->top == 0 ? 4 : ps->capacity * 2;
  28. MyDataType* temp = (MyDataType*)realloc(ps->a, sizeof(MyDataType) * NewSize);
  29. if (temp == NULL)
  30. {
  31. perror("realloc");
  32. exit(-1);
  33. }
  34. ps->a = temp;
  35. ps->capacity = NewSize;
  36. }
  37. ps->a[ps->top] = x;
  38. ps->top++;
  39. }
  40. void PopStack(ST* ps)
  41. {
  42. assert(ps);
  43. assert(ps->top > 0);
  44. --ps->top;
  45. }
  46. void DestroyStack(ST* ps)
  47. {
  48. assert(ps);
  49. free(ps->a);
  50. ps->a = NULL;
  51. ps->capacity = ps->top = 0;
  52. }
  53. bool StackEmpty(ST* ps)
  54. {
  55. assert(ps);
  56. return ps->top == 0;
  57. }
  58. MyDataType StackTop(ST* ps)
  59. {
  60. assert(ps);
  61. assert(ps->top > 0);
  62. return ps->a[ps->top-1];
  63. }
  64. int StackSize(ST* ps)
  65. {
  66. assert(ps);
  67. assert(ps->top >= 0);
  68. return ps->top ;
  69. }//手动搭建一个栈
  70. bool isValid(char* s)
  71. {
  72. ST st;
  73. InitStack(&st);
  74. while(*s)
  75. {
  76. if(*s=='('||*s=='['||*s=='{')//当为左括号时入栈
  77. {
  78. PushStack(&st,*s);
  79. }
  80. else//当为右括号的时候
  81. {
  82. if(StackEmpty(&st))
  83. {
  84. DestroyStack(&st);
  85. return false;
  86. }//如果栈为空时就读取到右括号,
  87. //即说明还未有左括号就有右括号,显然不符合规律
  88. int stacktop=StackTop(&st);
  89. PopStack(&st);
  90. if(*s==')'&&stacktop!='('||
  91. *s==']'&&stacktop!='['||
  92. *s=='}'&&stacktop!='{' )//出栈并一一判断
  93. {
  94. DestroyStack(&st);
  95. return false;
  96. }
  97. }
  98. s++;
  99. }
  100. bool ret=StackEmpty(&st);
  101. return ret;
  102. }

队列

一.队列的定义

  队列是只允许在一端插入元素,另一端删除元素的线性表,特点是先进先出。

二.队列的算法

      队列是从队尾进,队头出,所以采用链表的结构来实现,如果采用数组结构,则会使队头操作繁琐。与栈类似,我们仍然是实现以下函数代码。

 1.宏定义(初始准备)

  Queue这个结构体中还包含两个QNode结点结构体。包含队列头尾结点,能够帮助从队尾插入和从队头删除。

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<assert.h>
  4. #include<stdbool.h>
  5. typedef int MyDataType;//将int类型重命名为MyDataType
  6. typedef struct QueueNode
  7. {
  8. MyDataType val;
  9. struct QueueNode* next;
  10. }QNode;//单链表的结点结构
  11. typedef struct Queue//队列中包含队头、队尾、队列大小
  12. {
  13. QNode* front;
  14. QNode* back;
  15. int size;
  16. }QL;

2.队列的初始化

  1. void QueueInit(QL* pq)
  2. {
  3. assert(pq);//判断pq是否为空指针
  4. pq->size = 0;
  5. pq->front = pq->back = NULL;
  6. }

3.向队尾插入元素

  1. void QueuePush(QL* pq, MyDataType x)
  2. {
  3. assert(pq);
  4. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  5. if (newnode == NULL)
  6. {
  7. perror("malloc fail");
  8. exit(-1);
  9. }
  10. newnode->val = x;
  11. newnode->next = NULL;
  12. if (pq->back == NULL)
  13. pq->front = pq->back = newnode;//链表为空,则让front和back都指向newnode
  14. else
  15. {
  16. pq->back->next = newnode;
  17. pq->back = newnode;
  18. }
  19. pq->size++;
  20. }//与单链表搭建类似,由于不含头结点,
  21. //所以需要分链表是否为空的两种情况讨论。

4.删除队头元素

  1. void QueuePop(QL* pq)//与单链表不同,这里不需要传二级指针,
  2. //因为这里只是修改结构体中的内容,而不是改变结构体地址
  3. {
  4. assert(pq);
  5. assert(!QueueEmpty(pq));//断言链表不为空,为空则不能删除数据
  6. if (pq->front->next == NULL)//链表只含有一个数据
  7. {
  8. free(pq->front);
  9. pq->back = pq->front = NULL;
  10. }
  11. else
  12. {
  13. QNode* cur = pq->front->next;
  14. free(pq->front);
  15. pq->front = cur;
  16. }
  17. pq->size--;
  18. }

5.读取队尾和队头元素

  1. MyDataType QueueFront(QL* pq)//队头元素
  2. {
  3. assert(pq);
  4. assert(!QueueEmpty(pq));//不能为空链表
  5. return pq->front->val;
  6. }
  7. MyDataType QueueBack(QL* pq)//队尾元素
  8. {
  9. assert(pq);
  10. assert(!QueueEmpty(pq));//不能为空链表
  11. return pq->back->val;
  12. }

6.判断队列是否为空,读取队列大小

    即使是读取队列元素个数这样的操作也靠函数实现,能有效避免使用者不明变量含义而造成读取元素个数错误。

  1. bool QueueEmpty(QL* pq)//判断队列是否为空
  2. {
  3. assert (pq);
  4. return pq->front==NULL;//若头结点为空,则队列不含任何元素,队列为空
  5. }
  6. int QueueSize(QL* pq)//读取队列大小
  7. {
  8. return pq->size;
  9. }

7.队列的销毁

  1. void QueueDestroy(QL* pq)
  2. {
  3. assert(pq);
  4. QNode* cur = pq->front;
  5. while (cur)
  6. {
  7. QNode* next = cur->next;
  8. free(cur);
  9. cur = next;
  10. }//每个结点一一释放空间
  11. pq->back = pq->front = NULL;
  12. pq->size = 0;
  13. }

三.队列的例题

题目链接:

设计循环队列

题目解答:

  可以使用单链表和数组,但显然使用数组更方便。问题的关键在于数组尾元素的处理,这时要灵活使用取模操作。

  1. typedef struct {
  2. int *a;
  3. int front;
  4. int rear;
  5. int k;
  6. } MyCircularQueue;
  7. MyCircularQueue* myCircularQueueCreate(int k) {
  8. MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  9. obj->k=k;
  10. obj->a=(int *)malloc(sizeof(int)*(k+1));
  11. obj->front=obj->rear=0;
  12. return obj;
  13. }
  14. bool myCircularQueueIsEmpty(MyCircularQueue* obj)
  15. {
  16. return obj->front==obj->rear;
  17. }
  18. bool myCircularQueueIsFull(MyCircularQueue* obj)
  19. {
  20. return (obj->rear+1)% (obj->k+1)==obj->front;
  21. }
  22. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
  23. {
  24. if(myCircularQueueIsFull(obj))
  25. return false;
  26. obj->a[obj->rear]=value;
  27. obj->rear=(obj->rear+1)%(obj->k+1);
  28. return true;
  29. }
  30. bool myCircularQueueDeQueue(MyCircularQueue* obj)
  31. {
  32. if(myCircularQueueIsEmpty(obj))
  33. return false;
  34. obj->front=(obj->front+1)%(obj->k+1);
  35. return true;
  36. }
  37. int myCircularQueueFront(MyCircularQueue* obj)
  38. {
  39. if(myCircularQueueIsEmpty(obj))
  40. return -1;
  41. else
  42. return obj->a[obj->front];
  43. }
  44. int myCircularQueueRear(MyCircularQueue* obj) {
  45. if(myCircularQueueIsEmpty(obj))
  46. return -1;
  47. else
  48. return obj->a[(obj->rear+obj->k)%(obj->k+1)];
  49. }
  50. void myCircularQueueFree(MyCircularQueue* obj) {
  51. free(obj->a);
  52. free(obj);
  53. }

栈与队列的互相实现

题目链接:

题目一:用栈实现队列

题目二:用队列实现栈

题目解答:

 题目一:由于C语言没有库函数来搭建栈,所以我们必须手动搭建一个栈。思路很简单:用一个栈专门来进数据;另一个栈专门来出数据。

  1. typedef int MyDataType;
  2. typedef struct Stack
  3. {
  4. MyDataType* a;
  5. int capacity;
  6. int top;
  7. }ST;
  8. void InitStack(ST*ps);
  9. void PushStack(ST* ps,MyDataType x);
  10. void PopStack(ST* ps);
  11. void DestroyStack(ST* ps);
  12. bool StackEmpty(ST* ps);
  13. MyDataType StackTop(ST* ps);
  14. int StackSize(ST* ps);
  15. void InitStack(ST* ps)
  16. {
  17. assert(ps);
  18. ps->a = NULL;
  19. ps->capacity = 0;
  20. ps->top = 0;
  21. }
  22. void PushStack(ST* ps, MyDataType x)
  23. {
  24. assert(ps);
  25. if (ps->top == ps->capacity)
  26. {
  27. int NewSize = ps->top == 0 ? 4 : ps->capacity * 2;
  28. MyDataType* temp = (MyDataType*)realloc(ps->a, sizeof(MyDataType) * NewSize);
  29. if (temp == NULL)
  30. {
  31. perror("realloc");
  32. exit(-1);
  33. }
  34. ps->a = temp;
  35. ps->capacity = NewSize;
  36. }
  37. ps->a[ps->top] = x;
  38. ps->top++;
  39. }
  40. void PopStack(ST* ps)
  41. {
  42. assert(ps);
  43. assert(ps->top > 0);
  44. --ps->top;
  45. }
  46. void DestroyStack(ST* ps)
  47. {
  48. assert(ps);
  49. free(ps->a);
  50. ps->a = NULL;
  51. ps->capacity = ps->top = 0;
  52. }
  53. bool StackEmpty(ST* ps)
  54. {
  55. assert(ps);
  56. return ps->top == 0;
  57. }
  58. MyDataType StackTop(ST* ps)
  59. {
  60. assert(ps);
  61. assert(ps->top > 0);
  62. return ps->a[ps->top-1];
  63. }
  64. int StackSize(ST* ps)
  65. {
  66. assert(ps);
  67. assert(ps->top >= 0);
  68. return ps->top ;
  69. }
  70. typedef struct {
  71. ST pushstack;
  72. ST popstack;
  73. int size;
  74. } MyQueue;
  75. MyQueue* myQueueCreate()
  76. {
  77. MyQueue*queue=(MyQueue*)malloc(sizeof(MyQueue));
  78. InitStack(&queue->pushstack);
  79. InitStack(&queue->popstack);
  80. queue->size=0;
  81. return queue;
  82. }
  83. void myQueuePush(MyQueue* obj, int x)
  84. {
  85. assert(obj);
  86. PushStack(&obj->pushstack,x);
  87. }
  88. int myQueuePop(MyQueue* obj)
  89. {
  90. if(StackEmpty(&obj->popstack))
  91. {
  92. while(!StackEmpty(&obj->pushstack))
  93. {
  94. int push=StackTop(&obj->pushstack);
  95. PopStack(&obj->pushstack);
  96. PushStack(&obj->popstack,push);
  97. }
  98. }
  99. int pop=StackTop(&obj->popstack);
  100. PopStack(&obj->popstack);
  101. return pop;
  102. }
  103. int myQueuePeek(MyQueue* obj)
  104. {
  105. if(StackEmpty(&obj->popstack))
  106. {
  107. while(!StackEmpty(&obj->pushstack))
  108. {
  109. int push=StackTop(&obj->pushstack);
  110. PopStack(&obj->pushstack);
  111. PushStack(&obj->popstack,push);
  112. }
  113. }
  114. int pop=StackTop(&obj->popstack);
  115. return pop;
  116. }
  117. bool myQueueEmpty(MyQueue* obj)
  118. {
  119. return StackEmpty(&obj->pushstack)&&StackEmpty(&obj->popstack);
  120. }
  121. void myQueueFree(MyQueue* obj)
  122. {
  123. DestroyStack(&obj->pushstack);
  124. DestroyStack(&obj->popstack);
  125. free(obj);
  126. }

题目二:C语言仍然需要手动搭建队列。思路也不难:出数据时,现将数据导入另一个队列,只剩一个元素时,再弹出数据,如此反复。

  1. typedef int MyDataType;
  2. typedef struct QueueNode
  3. {
  4. MyDataType val;
  5. struct QueueNode* next;
  6. }QNode;
  7. typedef struct Queue
  8. {
  9. QNode* front;
  10. QNode* back;
  11. int size;
  12. }QL;
  13. void QueueInit(QL* pq);
  14. void QueueDestroy(QL* pq);
  15. void QueuePush(QL* pq, MyDataType x);
  16. void QueuePop(QL* pq);
  17. MyDataType QueueFront(QL* pq);
  18. MyDataType QueueBack(QL* pq);
  19. bool QueueEmpty(QL* pq);
  20. int QueueSize(QL* pq);
  21. void QueueInit(QL* pq)
  22. {
  23. assert(pq);
  24. pq->size = 0;
  25. pq->front = pq->back = NULL;
  26. }
  27. void QueueDestroy(QL* pq)
  28. {
  29. assert(pq);
  30. QNode* cur = pq->front;
  31. while (cur)
  32. {
  33. QNode* next = cur->next;
  34. free(cur);
  35. cur = next;
  36. }
  37. pq->back = pq->front = NULL;
  38. pq->size = 0;
  39. }
  40. void QueuePush(QL* pq, MyDataType x)
  41. {
  42. assert(pq);
  43. QNode* newnode = (QNode*)malloc(sizeof(QNode));
  44. if (newnode == NULL)
  45. {
  46. perror("malloc fail");
  47. exit(-1);
  48. }
  49. newnode->val = x;
  50. newnode->next = NULL;
  51. if (pq->back == NULL)
  52. pq->front = pq->back = newnode;
  53. else
  54. {
  55. pq->back->next = newnode;
  56. pq->back = newnode;
  57. }
  58. pq->size++;
  59. }
  60. void QueuePop(QL* pq)
  61. {
  62. assert(pq);
  63. assert(!QueueEmpty(pq));
  64. if (pq->front->next == NULL)
  65. {
  66. free(pq->front);
  67. pq->back = pq->front = NULL;
  68. }
  69. else
  70. {
  71. QNode* cur = pq->front->next;
  72. free(pq->front);
  73. pq->front = cur;
  74. }
  75. pq->size--;
  76. }
  77. MyDataType QueueFront(QL* pq)
  78. {
  79. assert(pq);
  80. assert(!QueueEmpty(pq));
  81. return pq->front->val;
  82. }
  83. MyDataType QueueBack(QL* pq)
  84. {
  85. assert(pq);
  86. assert(!QueueEmpty(pq));
  87. return pq->back->val;
  88. }
  89. bool QueueEmpty(QL* pq)
  90. {
  91. assert (pq);
  92. return pq->back==NULL;
  93. }
  94. int QueueSize(QL* pq)
  95. {
  96. return pq->size;
  97. }
  98. typedef struct {
  99. QL queue1;
  100. QL queue2;
  101. } MyStack;
  102. MyStack* myStackCreate() {
  103. MyStack*mystack=(MyStack*)malloc(sizeof(MyStack));
  104. QueueInit(&mystack->queue1);
  105. QueueInit(&mystack->queue2);
  106. return mystack;
  107. }
  108. void myStackPush(MyStack* obj, int x)
  109. {
  110. if(QueueEmpty(&obj->queue1))
  111. {
  112. QueuePush(&obj->queue2,x);
  113. }
  114. else{
  115. QueuePush(&obj->queue1,x);
  116. }
  117. }
  118. int myStackPop(MyStack* obj)
  119. {
  120. QL* empque=&obj->queue1;
  121. QL *noempque=&obj->queue2;
  122. if(QueueEmpty(&obj->queue2))
  123. {
  124. empque=&obj->queue2;
  125. noempque=&obj->queue1;
  126. }
  127. while(QueueSize(noempque)!=1)
  128. {
  129. int push=QueueFront(noempque);
  130. QueuePop(noempque);
  131. QueuePush(empque,push);
  132. }
  133. int pop=QueueFront(noempque);
  134. QueuePop(noempque);
  135. return pop;
  136. }
  137. int myStackTop(MyStack* obj) {
  138. if(!QueueEmpty(&obj->queue1))
  139. return QueueBack(&obj->queue1);
  140. else
  141. return QueueBack(&obj->queue2);
  142. }
  143. bool myStackEmpty(MyStack* obj) {
  144. return QueueEmpty(&obj->queue1)&&QueueEmpty(&obj->queue2);
  145. }
  146. void myStackFree(MyStack* obj) {
  147. free(obj);
  148. }

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

闽ICP备14008679号