数据结构实验
- 能实现队列的顺序存储和链式存储下的基本操作
实验内容
- 有一类字符串,将其所有字符倒过来后和原来一样,这种字符串被称为“回文”。如121、abcba都是回文,abA、abad都不是回文。请你使用队列的基本操作设计程序,运行后可以接受用户输入一个不超过10个字符的字符串,并通过你的程序判断该是否是回文,是则输出yes,否则输出no。
实验过程
设计思路
- 因为要实现队列的顺序存储和链式存储两个基本操作,用队列解决“比较回文”,直接使用两种方式将输入字符串进行存储,由于队列的是一边进一边出,所以判断回文时,使两队列在同一个循环中,顺序存储队列顺序输出和链式存储队列顺序输出(这里的链式存储在将字符串存储后经过逆序处理),两队列值相比是否相等,返回相应判断的bool值,根据判断输出结果。
代码实现解释
- 定义队列链式存储的节点结构,即存储内容和下一个节点的地址;定义一个类似于head作用的指针节点,这个节点存放front指针和rear指针,其中front、rear指针就是指向链式存储队列地址的指针;定义一个head的指针PLinkQueue,定义队列顺序存储的节点结构。
- 创建一个空link队列。生成head管理节点,并初始化front和rear,一开始队列为空,front和rear指向同一处。
- 判断link队列是否为空。即判断front指针是否为空,若为空,返回0;若不为空,返回1。
- 将数据元素X插入队尾。生成一个队列节点,将数据元素X存入节点,再将节点入队,这里注意先判断队列是否为空,即front=NULL,如果是,则插入元素的地址即为队列的首地址front;如果不为空,就将节点插入队尾,尾插法,插入后,队尾指针往后移,返回一个bool值,用于测试时判断是否插入成功。
- 队列逆置。这里采用的是带头结点的链表逆置方法,由于我们的队列没有头节点,所以用一个temp暂时代替,然后将pu->front指向temp,使用两个s,p移动指针,一个用于处理当前节点的移动,另一个存放队列未逆置的元素,其移动过程有点像一个固定高度的环节点,中间穿过一根左右两端打结的绳子,本来绳的左端在环节点处(原队头),现在从绳的左端拉下去,右端就上来(原来的队尾,现在的队头),从而实现链式队列的逆置。
- 出队。取出队列的首节点,front后移,并释放该节点,返回该节点元素。
- 函数isEmpty(),用于判断顺序队列是否为空,即判断front==rear,返回判断的bool值。
- 顺序队列的初始化。初始化顺序队列的head指针sq,给队头队尾赋值,返回sq。
- 队列入队。这里的字符串长度有限,所以不需要判断顺换队列是否满队,直接入队就好。
- 出队。判断队列是否为空,非空,在对头出队,front后移,返回出队元素。
- 回文判断。使两队列在同一个循环中,顺序存储队列顺序输出和链式存储队列顺序输出(这里的链式存储在将字符串存储后经过逆序处理),两队列值相比是否相等,返回相应判断的bool值。
主函数实现字符串输入,回文函数isPalindrome(str)的调用,根据返回的bool值输出结果。
代码实现
//能实现队列的顺序存储和链式存储 判断回文
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 20
typedef char DataType; //定义数据变量
//链式存储 队列、栈的 数据元素结构
typedef struct node
{
DataType info;
struct node *next;
}QueueData;
//队的指针,相当于head
typedef struct queueRecord // 对头、队尾指针 连两个指向同一队列的不同指针
{
QueueData *front, *rear;
}LinkQueue;
//顺序存储
typedef struct queue
{
int front;
int rear;
DataType *element;
}SeqQueue;
typedef struct queueRecord *PLinkQueue;
typedef struct queue *Queue;
//创建一个空队列,生成一个LinkQueue类型的节点。并初始化成员front和rear
PLinkQueue createEmptyQueue_link()
{
PLinkQueue list = (PLinkQueue )malloc(sizeof(struct queueRecord));
if(list!=NULL)
{
list->front=NULL;
list->rear=NULL;
return list;
}
return NULL;
}
//判定队列是否为空,看队列的front指针是否为空,若为空,则队列为空,返回0,若不为空,返回1
int isEmptyQueue_link(PLinkQueue qu)
{
if(qu->front!=NULL) return 1;
return 0;
}
//将数据元素X插入队尾,生成一个struct node类型的节点,并给相应的成员赋值后插入队尾
int inQueue_link(DataType x, PLinkQueue qu)
{
QueueData *data=(QueueData *)malloc(sizeof(struct node)); // 给插入元素初始化节点
if(data==NULL) return 0;
data->info=x;
data->next=NULL;
if(qu->front==NULL)
{
qu->front=data; //当开始没有元素时,插入元素的首地址即为队头p
qu->rear=data;
}
else
{
qu->rear->next=data; //尾插法,插入后,队尾指针往后移,即插入元素的地址
qu->rear=data;
}
return 1;
}
//队列逆置,不用考虑队尾指针
void queueRevers(PLinkQueue pu)
{
QueueData *p, *s;
QueueData *temp=(QueueData *)malloc(sizeof(struct node));
temp->info=1;
temp->next=pu->front;
pu->front=temp;
p=pu->front->next;
pu->front->next=NULL;
while(p)
{
s=p;
p=p->next;
s->next=pu->front->next;
pu->front->next=s;
}
pu->front=pu->front->next;
free(temp);
}
//出队,取出qu队列的首节点,并释放该节点 ,返回该节点的元素
DataType delQueue_link(PLinkQueue pu)
{
QueueData *p;
int temp=pu->front->info;
p=pu->front; //取出元素后释放该节点
pu->front=pu->front->next;
free(p);
return temp;
}
//下面放之前写过的栈的代码
int isEmpty(Queue sq) // 这里先判断,有点奇怪,如果先创建结构体,节点内容是默认的
{
if(sq->rear==sq->front) return 1;
return 0;
}
//顺序队列初始化
Queue createSeqQueue()
{
Queue sq=(Queue )malloc(sizeof(struct queue));
if(sq==NULL) return NULL;
sq->element=(DataType *)malloc(sizeof(struct queue)*MAXNUM);
if(sq->element==NULL) return NULL;
sq->front=sq->rear=0;
return sq;
}
//有限的队列入队可以这样
int pushSeqQueue(DataType x, Queue sq)
{
sq->element[sq->rear]=x;
sq->rear=(sq->rear+1)%MAXNUM;
return 1;
}
//出队列
DataType popQueue(Queue sq)
{
DataType temp;
if(!isEmpty(sq)) //队列非空
{
temp=sq->element[sq->front];
sq->front=(sq->front+1)%MAXNUM;
}
return temp;
}
//回文判断
int isPalindrome(char str[])
{
int flag;
int j=0;
PLinkQueue pu=createEmptyQueue_link();
// printf("%d", pu); initialize successful
char t1, t2;
Queue sq=createSeqQueue();
// printf("%d", s);
for(int i=0; i<strlen(str); i++)
{
flag=inQueue_link(str[i], pu);
// printf("qu %d\n", flag);
flag=pushSeqQueue(str[i], sq);
// printf("sta %d\n", flag);
}
j=strlen(str)-1;
queueRevers(pu);
for(int i=0; i<strlen(str); i++, j--)
{
// printf("%c\n", popQueue(s));
t1=delQueue_link(pu);
// printf("\n%c ", t1);
t2=popQueue(sq);
// printf("%c\n", t2);
if(t1!=t2) return 0;
}
return 1;
}
int main(void)
{
char str[20]; // 输入一个不超过10个字符的字符串
int flag=0;
scanf("%s", str);
flag = isPalindrome(str);
if(flag) printf("yes!");
else printf("no!");
return 0;
}