假设正读和反读都相同的字符序列为“回文字符串”,例如,"abba"和"abcba"是回文字符串,“abcde” 和"ababab"则不是回文字符串。试写一个程序判断输入的字符串是否为回文字符串。
方法一:
1.将字符串按照用户输入的顺序分别入栈和队列
2.分别从队列和栈中取出首个字符
3.比较取出的字符,若相等,继续分别从队列和栈中取首个字符;
否则跳出循环,并设置标志 flag=0;
4.若队列和栈中的字符取完,则结束,设置标志flag=1;
5.flag=1,表示字符从前往后和从后往前的序列完全匹配,该字符串属于回文
6.flag=0,表示字符从前往后和从后往前的序列不完全匹配,该字符串不属于回文
#include <stdio.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef char ElemType;
typedef struct strStack
{
ElemType *base;
ElemType *top;
int StackSize;
} sqStack;//定义一个栈
struct strQueue
{
ElemType e;
struct strQueue *next;
};
typedef struct Queue
{
struct strQueue *front;
struct strQueue *rear;
} Queue;//定义一个队列
void InitStack(sqStack *S);//初始化栈
void Push_Stack(sqStack *S, ElemType e);//入栈
void Pop(sqStack *S, ElemType *e);//出栈
void InitQueue(Queue *Q);//初始化队列
void InserQueue(Queue *Q, ElemType e);//入队列
void DeleteQueue(Queue *Q, ElemType *e);//出队列
int StackLen(sqStack S);//求栈的长度
int main()
{
sqStack S;
Queue Q;
InitStack(&S);
InitQueue(&Q);//初始化栈和队列
char ch;
int len;//栈的长度
int flag = 1;
/*将所有元素入栈、入队列*/
while((ch = getchar()) != '\n')
{
Push_Stack(&S, ch);
InserQueue(&Q, ch);
}
len = StackLen(S);//栈的长度
for(int i = 0; i < len; i++)
{
char elem_stack, elem_Queue;
Pop(&S, &elem_stack);
DeleteQueue(&Q, &elem_Queue);
/*依次出栈、出队列*/
/*当取出的元素不一样时,则已经不是回文串,跳出循环*/
if(elem_stack != elem_Queue)
{
flag = 0;
break;
}
}
if(flag == 0)
{
printf("不是回文串\n");
}
else
{
printf("是回文串\n");
}
return 0;
}
void InitStack(sqStack *S)//初始化栈
{
S->base = (ElemType*)malloc(STACK_INIT_SIZE * sizeof(ElemType));
if(S->base == NULL)
{
exit(-1);
}
S->top = S->base;
S->StackSize = STACKINCREMENT;
}
void Push_Stack(sqStack *S, ElemType e)//入栈
{
if(S->top - S->base == S->StackSize)
{
S->base = (ElemType*)realloc(S->base, (STACKINCREMENT + S->StackSize) * sizeof(ElemType));
if(S->base == NULL)
{
exit(-1);
}
}
*(S->top) = e;
S->top ++;
}
void Pop(sqStack *S, ElemType *e)//出栈
{
if(S -> top == S->base)
{
return ;
}
*e = *--(S->top);
}
void InitQueue(Queue *Q)//初始化队列
{
Q->front = Q->rear = (struct strQueue*)malloc(sizeof(struct strQueue));
if(!Q->front)
{
exit(0);
}
else
{
Q->front->next = NULL;
}
}
void InserQueue(Queue *Q, ElemType e)//入队列
{
struct strQueue *q = (struct strQueue*)malloc(sizeof(struct strQueue));
if(!q)
{
exit(-1);
}
else
{
q->e = e;
q->next = NULL;
Q->rear->next = q;
Q->rear = q;
}
}
void DeleteQueue(Queue *Q, ElemType *e)//出队列
{
if(Q->front == Q->rear)
{
return ;
}
else
{
struct strQueue *q = Q->front->next;
*e = q->e;
Q->front->next = q->next;
if(Q->rear == q)
{
Q->rear = Q->front;
}
free(q);
}
}
int StackLen(sqStack S)//求栈的长度
{
return (S.top - S.base);
}
方法二:
1、将字符存入一个双向循环链表
2、从表头往后和表尾往前分别取一个元素,若不相等,则设置flag = 0,并跳出循环;
3、若元素全部取完,则设置flag = 1;
4、flag=1,表示字符从前往后和从后往前的序列完全匹配,该字符串属于回文
5、flag=0,表示字符从前往后和从后往前的序列不完全匹配,该字符串不属于回文
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
//定义一个双向循环链表
typedef struct DualNode
{
ElemType data;
struct DualNode *prior;
struct DualNode *next;
} DualNode, *DuLinkList;
void Init_DuLinkList(DuLinkList *L);//初始化双向循环链表
void InsertDulinkList(DuLinkList *L, ElemType e);//插入元素
int main()
{
DuLinkList L;
Init_DuLinkList(&L);
char ch;
int flag = 1;
while((ch = getchar()) != '\n')
{
InsertDulinkList(&L, ch);
}//依次插入
DuLinkList head, tail;
head = L->next;//head指向第一个有元素的节点
tail = L->prior;//tail指向最后一个有元素的节点
while(head != tail)
{/*tail与head相等时结束循环,当元素个数为奇数时则每个指针只需走一半即可
元素个数为偶数时,每个指针都需要移动一圈走到头结点*/
if(head->data != tail->data)
{
flag = 0;
break;
}
head = head->next;
tail = tail->prior;
}
if(flag == 1)
{
printf("是回文串\n");
}
else
{
printf("不是回文串\n");
}
return 0;
}
void Init_DuLinkList(DuLinkList *L)//初始化双向循环链表
{
*L = (DuLinkList)malloc(sizeof(DualNode));//分配一个空间
if(!(*L))
{
exit(0);
}
else
{
(*L)->next = (*L);
(*L)->prior = (*L);
}
/*头结点data域没有数据*/
}
void InsertDulinkList(DuLinkList *L, ElemType e)
{
DuLinkList new = (DuLinkList)malloc(sizeof(DualNode));
DuLinkList p = (*L)->prior;//p为头结点前的节点,相当于尾结点
new->data = e;
new->next = *L;//新节点的next指向头结点
new->prior = p;//新节点的prior域指向原“尾节点”
p->next = new;//原“尾结点”的next域指向新节点
(*L)->prior = new;//把头结点的prior域指向新节点
/*此部分代码画图理解更佳,此不赘述*/
}
方法三:
1、利用快慢指针把单链表前半部分逆转并把链表分成两个链表。
2、依次比较两个单链表节点的data域,出现不相同的地方,则必不为回文字符串,若两个链表走到了最后,退出循环,则为回文串
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LinkNode, *LinkList;
void InitList(LinkList *L, int n);
LinkList Div_ReverseList(LinkList *L);
void Compare(LinkList former,LinkList latter);
int main()
{
LinkList L = NULL;
int n;
printf("输入字符个数\n");
scanf("%d", &n);
fflush(stdin);
InitList(&L, n);
LinkList former = Div_ReverseList(&L);
LinkList latter = L;
Compare(former,latter);
return 0;
}
void InitList(LinkList *L, int n)
{
printf("请输入含%d个字符的字符串\n",n);
char c;
*L = (LinkList)malloc(sizeof(LinkNode));
(*L)->next = NULL;
scanf("%c", &c);
(*L)->data = c;
LinkList q = *L;
LinkList p;
for(int i = 0; i < n - 1; i++)
{
p = (LinkList)malloc(sizeof(LinkNode));
scanf("%c", &c);
p->data = c;
q->next = p;
q = p;
}
p->next = NULL;
}
LinkList Div_ReverseList(LinkList *L)//将链表逆转一半分成两个等长链表
{
LinkList lslow = *L;//慢指针
LinkList lfast = (*L)->next;//快指针
LinkList temp = NULL;
if(lslow->next == NULL)//只有一个节点,返回头结点
{
return lslow;
}
while(lslow->next != NULL&&lfast->next != NULL && lfast->next->next != NULL)
{
*L = lslow->next;
lslow->next = temp;
temp = lslow;
lslow = *L;
lfast = lfast->next->next;
}
if(lfast->next == NULL)
{
*L = lslow->next;
lslow->next = temp;
return lslow;
}//此时,链表分成了以lslow和*L为头结点的两个单链表
else //(lfast->next->next == NULL)
{
LinkList t = (*L)->next;
*L = lslow->next->next;
lslow->next = temp;
free(t);//把中间的节点释放掉
return lslow;
}//此时链表分成了以temp和*L为头结点的两个链表
}
void Compare(LinkList former,LinkList latter)
{
while(former != NULL)
{
if(former->data != latter->data)//出现一处不相等,就必不是回文串
{
printf("No\n");
break;
}
former = former->next;
latter = latter->next;
}
if(former == NULL)//走到最后
{
printf("YES\n");
}
}