👋 欢迎来到“数据结构(C语言)学习与实践”篇!
本篇中,我们将一起学习队列的基本操作,并使用一个将所学应用与实际问题——用队列实现字符串中心对称的检验,以此来巩固我们的知识!
📚 介绍
队列(Queue)是一种先进先出(FIFO)的数据结构,它的基本操作是:
- 入队(Enqueue):将元素添加到队列的尾部。
- 出队(Dequeue):从队列的头部移除元素。
在本篇博客中,我们将探讨如何利用队列来判断一个字符串是否中心对称。所谓“中心对称”,是指一个字符串的前半部分与后半部分对称,如字符串 "abcba" 即为中心对称。
通过这篇文章,你不仅可以了解队列的基本操作,还能学习如何将队列与实际问题结合来解决实际问题。
🔧 队列的基本操作
1. 队列定义
队列是一种只允许在队尾插入元素、在队头删除元素的线性结构。我们可以通过循环队列来解决这个问题,使得队尾和队头之间的关系可以通过模运算来实现。
#define Maxsize 50
#define N 50
typedef struct {
char* base;
int front;
int rear;
int length; // 队列当前长度
} SqQueue;
2. 队列的基本操作实现
接下来,我们实现队列的几个常见操作:
- 初始化队列(InitQueue)
- 检查队列是否为空(QEmpty)
- 获取队列长度(QLength)
- 检查队列是否已满(QFull)
- 入队操作(EnQueue)
- 出队操作(DeQueue)
- 获取队头元素(GetHead)
- 从队尾获取元素(ReQueuerear)
// 初始化队列
bool InitQueue(SqQueue* Q) {
Q->base = (char*)malloc(Maxsize * sizeof(char));
if (!Q->base) return false; // 如果内存分配失败
Q->front = 0;
Q->rear = 0;
Q->length = 0;
return true;
}
// 返回队列长度
bool QLength(SqQueue* Q) {
return Q->length;
}
// 判断队列是否为空
bool QEmpty(SqQueue* Q) {
return Q->length == 0;
}
// 判断队列是否已满
bool QFull(SqQueue* Q) {
return Q->length == Maxsize;
}
// 入队操作
bool EnQueue(SqQueue* Q, char e) {
if (Q->length == Maxsize) return false; // 队列已满
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % Maxsize; // 循环队列
++Q->length;
return true;
}
// 出队操作
bool DeQueue(SqQueue* Q, char* e) {
if (Q->length == 0) return false; // 队列为空
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % Maxsize; // 循环队列
--Q->length;
return true;
}
// 从队尾取元素
bool ReQueuerear(SqQueue* Q, char* e) {
if (Q->length == 0) return false;
Q->rear = (Q->rear - 1 + Maxsize) % Maxsize; // 处理负数的情况
*e = Q->base[Q->rear];
return true;
}
// 获取队头元素
bool GetHead(SqQueue* Q, char* e) {
if (Q->length == 0) return false;
*e = Q->base[Q->front];
return true;
}
📏 算法思路:检验字符串是否中心对称
1. 问题分析
我们可以利用队列的基本操作来判断一个字符串是否中心对称。思路如下:
- 入队:将字符串的字符一个一个压入队列。
- 出队与队尾取元素:在队列非空的情况下,从队尾取一个元素,并从队头取一个元素进行比较。若两者不相等,则表示字符串不对称;若始终相等,则字符串是中心对称的。
2. 算法实现
// 从队尾往前取元素
bool ReQueuerear(SqQueue* Q, char* e) {
if (Q->length == 0) return false;
Q->rear = (Q->rear - 1 + Maxsize) % Maxsize; // 处理负数的情况
*e = Q->base[Q->rear];
return true;
}
// 检验字符串是否中心对称
bool SymmetryExam(char str[]) {
SqQueue Q;
InitQueue(&Q);
char c1, c2;
int i = 0;
// 将字符串入队,直到遇到结束标志'#'为止
while (str[i] != '#') {
EnQueue(&Q, str[i]);
++i;
}
// 检查队列中的元素是否对称
while (Q.length) {
if (!ReQueuerear(&Q, &c2)) // 从队尾取元素
return false;
if (!DeQueue(&Q, &c1)) // 从队头取元素
return false;
if (c1 != c2)
return false; // 不相等则不对称
}
return true; // 如果所有元素都对称,返回true
}
3. 完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Maxsize 50
#define N 50
typedef struct {
char* base;
int front;
int rear;
int length; // 队列当前长度
} SqQueue;
bool InitQueue(SqQueue* Q) {
Q->base = (char*)malloc(Maxsize * sizeof(char));
if (!Q->base) return false;
Q->front = 0;
Q->rear = 0;
Q->length = 0;
return true;
}
bool EnQueue(SqQueue* Q, char e) {
if (Q->length == Maxsize) return false;
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % Maxsize;
++Q->length;
return true;
}
bool DeQueue(SqQueue* Q, char* e) {
if (Q->length == 0) return false;
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % Maxsize;
--Q->length;
return true;
}
bool ReQueuerear(SqQueue* Q, char* e) {
if (Q->length == 0) return false;
Q->rear = (Q->rear - 1 + Maxsize) % Maxsize;
*e = Q->base[Q->rear];
return true;
}
bool SymmetryExam(char str[]) {
SqQueue Q;
InitQueue(&Q);
char c1, c2;
int i = 0;
while (str[i] != '#') {
EnQueue(&Q, str[i]);
++i;
}
while (Q.length) {
if (!ReQueuerear(&Q, &c2)) return false;
if (!DeQueue(&Q, &c1)) return false;
if (c1 != c2)
return false;
}
return true;
}
int main() {
char str[N];
gets_s(str);
puts(str);
if (SymmetryExam(str))
printf("字符串中心对称!\n");
else
printf("字符串不中心对称!\n");
return 0;
}
🚀 算法分析与优化建议
1. 时间复杂度
- 时间复杂度:该算法的时间复杂度为 O(n),其中 n 是字符串的长度。我们只需要遍历一遍字符串并进行队列操作(每个队列操作的时间复杂度为 O(1))。
2. 空间复杂度
- 空间复杂度:由于我们使用了队列来存储字符串字符,因此空间复杂度为 O(n)。
3. 常见问题与优化建议
-
队列满的情况:在本实现中,我们使用了固定大小的队列。如果字符串长度超过
Maxsize
,程序会出现错误。可以考虑使用动态数组或者链表来实现队列,避免队列满的情况。 -
输入问题:
gets_s
被认为不安全,建议使用fgets
来读取字符串。 -
边界处理:我们
在 ReQueuerear
中考虑了队列的循环操作,通过模运算确保队尾指针不会越界。
🧑💻 编程技巧与建议
-
使用循环队列:通过模运算来实现循环队列,可以避免队列满后的处理问题,提升队列操作的效率。
-
使用动态内存管理:为队列分配内存时,可以考虑使用
realloc
来动态调整队列的大小,避免内存溢出。 -
安全的字符串输入:避免使用
gets_s
,使用fgets
或scanf
来确保输入的安全性。
🏁 总结
通过队列,我们可以轻松地实现对字符串的中心对称性检验。了解队列的基本操作和灵活运用它们,在处理类似问题时可以极大地简化代码并提高效率。希望这篇博客能够帮助你更好地理解队列的使用和一些常见的编程技巧!
如果你有任何问题或建议,欢迎在评论区留言,我们一起讨论!