本题要求设计一个算法,判断用户输入的字符串是否是回文字符串,用户输入的字符串同时存储于链栈和链队列中。
个人学习答案:
int JudgePalindrome(LinkStack st, LinkQueue qu)
{
DataType a, b;
while (!LinkQueueEmpty(qu))// 循环直到栈和队列都为空
{
Pop(st, &a);// 从栈中弹出数据
DeLinkQueue(&qu, &b);//从队列中弹出数据
//注意queue中linkqueue定义的不是指针!传入需要&
if (a != b)// 比较弹出的数据
{
return -1;// 如果数据不一致,返回-1
}
}
return 2; // 如果所有数据都一致,返回2
}
1. 为何要使用链栈和链队列,而不使用顺序栈和顺序队列?后者在本题场景下针对输入有什么局限性?
链栈和链队列的优势在于它们的空间动态分配。对于顺序栈和顺序队列,它们通常需要预先定义一个固定大小的数组来存储元素。如果输入的字符串长度超过了这个预定义的大小,那么顺序栈和顺序队列就无法处理这么多的元素,除非重新分配更大的空间,这可能会导致性能问题和内存浪费。而链栈和链队列可以根据需要动态地分配空间,因此它们可以处理任意长度的字符串,而不会受到预先定义的大小的限制。
2. 循环条件可以改成判栈空不?
循环条件可以改成判断栈是否为空。在上述代码中,我们是通过判断链队列是否为空来控制循环的,这是因为队列是先进先出的数据结构,它反映了原始字符串的顺序。但是,由于栈和队列的长度应该是相同的(因为它们存储的是同一个字符串),所以理论上也可以通过判断栈是否为空来控制循环。但是,由于我们在比较之前已经将链栈中的所有元素转移到了辅助栈中,因此实际上我们应该判断辅助栈是否为空。
3. 还有没有时间和空间上更高效的算法?(在本算法基础上优化改进)
在本算法的基础上,可以做一些优化来提高效率。一种方法是避免使用辅助栈,直接使用链栈进行比较。由于链栈的后进先出的特性,链栈的中间元素不容易直接访问。但是,我们可以同时从链栈的顶部和底部进行比较,这样就可以在不使用额外空间的情况下判断字符串是否为回文。这需要两个指针,一个指向栈顶,另一个指向栈底,然后同时向中间移动,比较对应的元素。
如:
int JudgePalindrome(LinkStack st, LinkQueue qu) {
LinkStack slow = st->next, fast = st->next; // 慢指针和快指针初始化为栈顶
SNode *prev = st; // 用于记录慢指针的前一个节点
DataType stackTop, queueFront;
// 使用快慢指针找到链栈的中点
while (fast != NULL && fast->next != NULL) {
prev = slow; // 更新前一个节点
slow = slow->next; // 慢指针前进一步
fast = fast->next->next; // 快指针前进两步
}
// 如果快指针没有达到链栈的末尾,说明链栈长度为奇数,慢指针需要再前进一步
if (fast != NULL) {
prev = slow; // 更新前一个节点
slow = slow->next;
}
// 此时,慢指针指向链栈的中间位置,prev指向慢指针的前一个节点
// 从链栈的中间位置开始,同时从顶部和底部比较元素
while (slow != NULL) {
Pop(st, &stackTop);
DeLinkQueue(&qu, &queueFront);
if (stackTop != queueFront) {
return -1; // 发现不匹配的字符,返回-1
}
prev->next = NULL; // 断开链栈的上半部分
free(slow); // 释放下半部分的节点
slow = st->next; // 指向链栈的新底部
}
return 2; // 所有字符都匹配,是回文字符串
}
所涉及的链栈结点和链队列结点定义如下:
typedef char DataType;
/* 链栈的结点定义 */
typedef struct SNode
{
DataType data;
struct SNode *next;
}SNode,*LinkStack;
/* 链队列的结点定义 */
typedef struct QNode
{
DataType data;
struct QNode *next;
}LQNode,*PQNode ;
/* 链队列的定义 */
typedef struct
{
PQNode front, rear; // 链队列的队头和队尾指针
}LinkQueue;
函数接口定义:
int JudgePalindrome(LinkStack st,LinkQueue qu);
st
和 qu
都是用户传入的参数, 其中st
是链栈的头指针,qu
是链队列的头指针。如果是回文字符串,则函数返回2,反之返回-1。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef char DataType;
typedef struct SNode
{
DataType data;
struct SNode *next;
}SNode,*LinkStack;
int InitLinkStack( LinkStack *top )
{
*top = (LinkStack)malloc( sizeof(SNode) );
if( *top == NULL )
{
printf("初始化链栈出错");
return 0;
}
(*top)->next = NULL;
return 1;
}
int LinkStackEmpty( LinkStack top )
{
if( top->next == NULL )
return 1;
else
return 0;
}
int Push(LinkStack top, DataType e)
{
SNode *p;
p = (SNode*)malloc(sizeof(SNode));
if (!p)
{
printf("入栈操作出错!\n");
return 0;
}
p->data = e;
p->next = top->next;
top->next = p;
return 1;
}
int Pop(LinkStack top, DataType *e)
{
SNode *p;
if (!top->next)
{
printf("栈已空,无法完成出栈操作!\n");
return 0;
}
p = top->next;
top->next = p->next;
*e = p->data;
free(p);
return 1;
}
int Destroy(LinkStack top)
{
SNode *p;
while (top)
{
p = top;
top = top->next;
free(p);
}
return 1;
}
typedef struct QNode
{
DataType data;
struct QNode *next;
}LQNode,*PQNode ;
typedef struct
{
PQNode front, rear;
}LinkQueue;
int InitLinkQueue(LinkQueue* Q)
{
Q->front = Q->rear = (PQNode)malloc(sizeof(LQNode));
if (!Q->front)
{
printf("初始化队列失败!\n");
return 0;
}
Q->front->next = NULL;
return 1;
}
int LinkQueueEmpty(LinkQueue Q)
{
if (Q.front == Q.rear) return 1;
else return 0;
}
int EnLinkQueue(LinkQueue* Q, DataType e)
{
PQNode p;
p = (PQNode)malloc(sizeof(LQNode));
if (!p)
{
printf("内存分配失败,不能完成入队操作!\n");
return 0;
}
p->data = e;
p->next = NULL;//初始化入队结点
Q->rear->next = p;
Q->rear = p;
return 1;
}
int DeLinkQueue(LinkQueue* Q, DataType* e)
{
PQNode p;
if (Q->front == Q->rear)
{
printf("队列已空,不能完成出队操作!\n");
return 0;
}
p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
free(p);
if (Q->rear == p) //若删除的队列是最后一个结点,则移动队尾指针
{
Q->rear = Q->front;
}
return 1;
}
int DestroyLinkQueue(LinkQueue* Q)
{
while (Q->front)
{
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
return 1;
}
/* 本题要求函数 */
int JudgePalindrome(LinkStack st,LinkQueue qu);
int main()
{
LinkStack s;
LinkQueue q;
char ch;
int rst;
InitLinkStack(&s);
InitLinkQueue(&q);
while((ch=getchar())!='\n')
{
Push(s,ch);
EnLinkQueue(&q,ch);
}
rst = JudgePalindrome(s,q);
if ( rst == -1 )
{
printf("不是回文字符串\n");
}
else if ( rst == 2 )
{
printf("是回文字符串\n");
}
Destroy(s);
DestroyLinkQueue(&q);
return 0;
}
/* 请在这里填写答案 */
输入样例:
asdfghjklkjhgfdsa
输出样例:
是回文字符串