正读与反读都相同的字符序列为“回文”序列。
栈与队列都是操作位置受限的线性表。栈中的元素具有“后进先出”的特点,而队列中的元素则是按顺序出队列。所以,可以用一个栈以及一个队列相互配合(即一个从字符串的最后往前判断,另一个从字符串的最前面往后判断),来判断输入的一个字符串是否是回文。
本篇中栈与队列的存储结构均为顺序存储。
顺序栈的存储结构。栈中的元素为char型
typedef struct SqStack{ char *top; //定义栈顶指针 char *base; //定义栈底指针 int stacksize; //栈可用的最大容量 }SqStack;
顺序队列的存储结构。
typedef struct SqQueue{ char *base; //存储空间的基地址 int front; //头指针 int rear; //尾指针 }SqQueue;
将同一个字符串分别压入栈中以及存入队列中。
比较判断时,同时从栈中弹出一个元素以及从队列中出来一个元素,比较这两个元素是否相同。
用来判断回文的函数
int compare(char s[]) { int i=0; char x,y; SqStack S; SqQueue Q; Creat_Stack(&S); //创建栈 Creat_Q(&Q); //创建队列 while(s[i] != '\0') { if(s[i] == '\n') continue; //跳过字符串开头的回车字符 Push(&S,s[i]); //入栈 In_Queue(&Q,s[i]); //入队 i++; } while(IsEmpty_Q(&Q) != 1) { Pop(&S,&x); Out_Queue(&Q,&y); if(x!=y) //若有一个字符不同 { destory_S(&S); //销毁栈 destory_Q(&Q); //销毁队列 return 0; } } destory_S(&S); //销毁栈 destory_Q(&Q); //销毁队列 return 1; }
详细代码
#include<stdio.h> #include<stdlib.h> //exit() 函数 #include<math.h> //OVERFLOW #define MAXSIZE 100 //能存储的字符串最大达到100 #define OK 0 #define ERROR -1 typedef int Status; //定义顺序栈的存储结构。栈中的元素为char型 typedef struct SqStack{ char *top; //定义栈顶指针 char *base; //定义栈底指针 int stacksize; //栈可用的最大容量 }SqStack; //定义顺序队列的存储结构 typedef struct SqQueue{ char *base; //存储空间的基地址 int front; //头指针 int rear; //尾指针 }SqQueue; /*顺序栈的初始化。构造一个空栈 1.因为对于栈的操作都是从栈顶进行的,栈尾指针是不动的,栈顶指针是来回上下移动的 2.若构建不成功,退出该函数并给出信息 3.若构建成功,则让栈顶指针指向栈底指针所指向的位置(栈为空的条件:栈顶指针等于栈底指针) 4.给栈可用的最大容量赋值 */ Status Creat_Stack(SqStack *S) { S->base = (char *)malloc(sizeof(char)*MAXSIZE); //给栈动态分配内存,所分配的内存为100 if(!S->base) { printf("创建失败!\n"); exit(OVERFLOW); //若内存分配失败,则返回 } S->top = S->base; //让栈顶指针指向栈底指针的位置 S->stacksize = MAXSIZE; //给栈可用的最大容量赋值 return OK; } /*判断栈是否为空 当栈顶指针等于栈底指针时,栈为空 */ int IsEmpty_S(SqStack *S) { if(S->top == S->base) return 1; //若为空,则返回1 return 0; } /*入栈 1.首先判断栈是否为满,若为满则退出去 2.接下来执行*S->top++ = e */ Status Push(SqStack *S,char a) { if(S->top - S->base == S->stacksize) //若栈满 { printf("栈已满,无法插入!\n"); return ERROR; } *S->top++ = a; //将a压入栈中 return OK; } /*出栈 1.首先判断栈是否为空,若为空,则退出 2.先令栈顶元素的指针回退 3.将栈顶元素弹出栈 */ Status Pop(SqStack *S,char *a) //a为弹出的元素 { int x=IsEmpty_S(S); if(x) //判断栈是否为空 { printf("栈为空,无法删除!\n"); return ERROR; } *a=*--S->top; //注意!!!! return OK; } /*顺序栈的销毁 malloc时,是一整块的S->base地址,因此只需直接释放S->base即可,同时让两个指针为空 */ Status destory_S(SqStack *S) { free(S->base); S->base = NULL; S->top = NULL; S->stacksize = 0; return OK; } //队列还是创建循环队列为好,因为普通队列容易存在假溢出的现象 /* 队列的初始化 1.首先给队列的基地址动态分配存储空间 2.若分配失败,则返回 3.若分配成功,则初始化头指针与尾指针皆为0 */ Status Creat_Q(SqQueue *Q) { Q->base = (char *)malloc(sizeof(char)*MAXSIZE); if(!Q->base) { printf("创建失败!\n"); exit(OVERFLOW); //若内存分配失败,则返回 } Q->front = 0; Q->rear = 0; return OK; } /*入队 1.首先判断队列是否为满 2.若队列未满,则让元素入队 3.队尾指针自增一 */ Status In_Queue(SqQueue *Q,char a) { if((Q->rear+1)%MAXSIZE == Q->front) //尾指针在循环意义上加一后等于头指针,队满 { printf("队列已满,无法入队!\n"); return ERROR; } Q->base[Q->rear] = a; Q->rear = (Q->rear+1)%MAXSIZE; //尾指针加一 return OK; } /* 判断队是否为空 若头指针=尾指针,则队列为空 */ int IsEmpty_Q(SqQueue *Q) { if(Q->front == Q->rear) return 1; //为空则返回1 return 0; } /*出队 1.首先判断队列是否为空 2.若队列不为空,则让队头元素出队 3.头指针自增一 */ Status Out_Queue(SqQueue *Q,char *a) //用a记录出队的元素值 { if(IsEmpty_Q(Q) == 1) { printf("队列为空,无法出队!\n"); return ERROR; } *a = Q->base[Q->front]; Q->front = (Q->front+1) %MAXSIZE; return OK; } //顺序队列的销毁 Status destory_Q(SqQueue *Q) { free(Q->base); Q->base = NULL; Q->front = 0; Q->rear = 0; return OK; } //进行回文比较的函数 int compare(char s[]) { int i=0; char x,y; SqStack S; SqQueue Q; Creat_Stack(&S); //创建栈 Creat_Q(&Q); //创建队列 while(s[i] != '\0') { if(s[i] == '\n') continue; //跳过字符串开头的回车字符 Push(&S,s[i]); //入栈 In_Queue(&Q,s[i]); //入队 i++; } while(IsEmpty_Q(&Q) != 1) { Pop(&S,&x); Out_Queue(&Q,&y); if(x!=y) //若有一个字符不同 { destory_S(&S); //销毁栈 destory_Q(&Q); //销毁队列 return 0; } } destory_S(&S); //销毁栈 destory_Q(&Q); //销毁队列 return 1; } //主函数 int main() { char s[MAXSIZE]={'0'}; int a=0,i; printf("请输入需要回文判断的字符:"); scanf("%s",s); a=compare(s); if(a==1) printf("是回文数\n"); else printf("不是回文数\n"); return 0; }
运行效果图