C语言:队列

本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

一、基本概念

队列和堆栈的顺序不同: 队列是一种先进先出(First-In First-Out, FIFO)的结构。

二、实现原理

在队列的尾部插入以及在头部删除,因为它准确的描述了人们在排队时的实际体验。

三、过程分析

队列的实现比堆栈稍微复杂一点。它需要两个指针------- 一个指向头,一个指向队尾。同时,数组并不像适合堆栈那样适合队列的实现,这是由队列使用内存的方式决定的。

1. 考虑一个用5个元素的数组实现的队列。下图是10、20、30、40、50这几个值插入队列以后队列的样子:

2. 经过三次删除之后,队列的样子如下:


这种情况,数组并没有填满,但它的尾部已经没有空间,无法再插入新的元素了。这个问题的一种解决方法是当一个元素被删除之后,队列中的其余元素朝数组起始位置方向移动一个位置。由于复制元素所需的开销,这种方法几乎不可行,尤其是那些较大的队列。

一个好一点的方案就是让队列的尾部“环绕”到数组的头部,这样新元素就可以存储到以前删除元素所留出来的空间中。这个方法常常称为循环数组,示意图如下:

1. 假设初始阶段结构如下:


2. 插入另一个元素之后的结果:



这里有两点需要说明:

1. 循环数组的插入操作只会改变rear的值,而front的值保持不变

2. 当尾部下标移出数组尾部时,把它设置为0。用下面的代码就可以实现:

rear += 1;
if (rear >= QUEUE_SIZE) {
    rear = 0;
}
等效的写法如下:

rear = (rear + 1) % QUEUE_SIZE

3. 我们继续往循环数组中插入几个元素,直到数组 "满" 为止,结构如下:


4. 我们尝试将循环数组中的元素全部删除,最终结构图如下:


注:循环数组的删除操作只会改变front的值,而rear的值保持不变

可以看出,循环数组 "满" 的时候 和 循环数组 ”空“ 的时候,front和rear的值都是一致的,这样就会导致我们无法判断循环数组是"空"还是"满"。

解决思路:重新定义"满"的含义。如果使数组中的一个元素始终保留不用,这样队列"满"时,front和rear的值便不相同,可以和队列为空的情况区分开来。通过不允许数组完全填满,问题便得以避免。示意图如下:


为"空"满足的条件为:

(rear + 1) % QUEUE_SIZE == front
为"满"满足的条件为:
(rear + 2) % QUEUE_SIZE == front
四、代码清单

#define QUEUE_SIZE 100
#define ARRAY_SIZE (QUEUE_SIZE + 1) // 数组中的一个元素始终保留不用,为了区分队列是满还是空
static QUEUE_TYPE queue[ARRAY_SIZE];
static size_t front = 1;
static size_t rear = 0;

void insert(QUEUE_TYPE value) {
    assert(!is_full());
    rear = (rear + 1) % ARRAY_SIZE;
    queue[rear] = value;
}

void delete(void) {
    assert(!is_empty());
    front = (front + 1) % ARRAY_SIZE;
}

QUEUE_TYPE first(void) {
    assert(!is_empty());
    return queue[front];
}

int is_empty(void) {
    return (rear + 1) % ARRAY_SIZE == front;
}

int is_full(void) {
    return (rear + 2) % ARRAY_SIZE == front;
}


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
中缀表达式转后缀表达式可以通过使用栈来实现。具体步骤如下: 1. 创建一个空栈和一个空的输队列; 2. 从左到右遍历中缀表达式的每个元素; 3. 如果当前元素是操作数,将其加入输队列中; 4. 如果当前元素是左括号,将其压入栈中; 5. 如果当前元素是右括号,则将栈中的元素弹并加入输队列中,直到遇到左括号,左括号弹但不加入输队列; 6. 如果当前元素是运算符: 1. 如果栈为空,则将当前运算符压入栈中; 2. 如果栈不为空,则比较当前运算符与栈顶运算符的优先级,如果当前运算符优先级低于等于栈顶运算符,则将栈顶运算符弹并加入输队列中,重复此步骤直到当前运算符优先级高于栈顶运算符,然后将当前运算符压入栈中; 7. 遍历完中缀表达式后,如果栈中还有运算符,将它们依次弹并加入输队列中; 8. 输队列中的元素即为转换后的后缀表达式。 下面是一个 C 语言实现的中缀转后缀的函数,其中假定中缀表达式已经存储在一个字符串数组 infix 中,后缀表达式存储在另一个字符串数组 postfix 中: ```c #include <stdio.h> #include <string.h> #include <ctype.h> #define MAXLEN 100 int is_operator(char c) { return (c == '+' || c == '-' || c == '*' || c == '/'); } int get_priority(char c) { if (c == '*' || c == '/') { return 2; } else if (c == '+' || c == '-') { return 1; } else { return 0; } } void infix_to_postfix(char *infix, char *postfix) { int i, j, len; char c, stack[MAXLEN]; int top = -1; len = strlen(infix); j = 0; for (i = 0; i < len; i++) { c = infix[i]; if (isdigit(c)) { postfix[j++] = c; } else if (is_operator(c)) { while (top >= 0 && get_priority(stack[top]) >= get_priority(c)) { postfix[j++] = stack[top--]; } stack[++top] = c; } else if (c == '(') { stack[++top] = c; } else if (c == ')') { while (top >= 0 && stack[top] != '(') { postfix[j++] = stack[top--]; } if (top >= 0 && stack[top] == '(') { top--; } } } while (top >= 0) { postfix[j++] = stack[top--]; } postfix[j] = '\0'; } int main() { char infix[MAXLEN], postfix[MAXLEN]; printf("Enter an infix expression: "); fgets(infix, MAXLEN, stdin); infix_to_postfix(infix, postfix); printf("Postfix expression: %s\n", postfix); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋恨雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值