3 判断单链表的对称性
作者: 冯向阳时间限制: 1S章节: 课程设计
问题描述 :
设带头结点的单链表的头指针为head,结点结构由data和next两个域构成,其中data域为字符型。在使用单链表ADT的基础上,设计一算法判断该链表的前n个字符是否中心对称。例如 x, xyx, xyyx都是中心对称。
参考函数原型:
//判断单链表的前n个结点是否中心对称
template<class ElemType>
bool Judge_Symmetry( LinkList<ElemType> &L, int num );
输入说明 :
第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string)
第二行:待判断对称性的链表长度n
第三行:单链表A的数据元素(数据元素之间以空格分隔)
注意:单链表A中的元素个数可能小于n,也可能大于n。如果元素个数小于n,则判断整个单链表是否对称。
输出说明 :
如第一行输入值为0、1、2、3之外的值,直接输出“err”
否则:
第一行:单链表A的遍历结果(数据元素之间以"->"分隔)
空行
第三行:true(对称)
false(不对称)
![](https://img-blog.csdnimg.cn/933874b582094615b6401d826c938c72.png)
反思:
1.首先稍微复习了一下链表的知识,找到了链表的模板,进行了一些回顾理解
2.分析问题,int函数
* 输入m判断数据类型,输入链表长度n
*构造单链表
*中心对称函数处理
3.判断数据类型还是分成四种情况
int m,n,i=0;
cin>>m>>n;
if(m==0)
{
LinkList <int> B;
int input1[100];
int num;
while(cin>>input1[i])i++;
B.CreateList_Tail(i, input1);//回顾链表构造方式
B.ListTraverse();
Judge_Symmetry(B,n);
}
其他略
4.Judge_Symmetry函数构造
//判断单链表的前n个结点是否中心对称
* 一个个看是不是对称,i++到中间为止
* 一个i一个n-1看是不是一样
* 如果不一样false,结束循环输出true
template<class ElemType>
bool Judge_Symmetry( LinkList<ElemType> &L, int n )
{
typename LinkList<ElemType>::Position pa,pb,head;
//这里使用了LinkList<ElemType>::Link,在前面要加“typename”,否则不能编译
ElemType a,b;
head=pa=pb=L.GetHead();
pa=L.NextPos(pa);
pb=L.NextPos(pb);
int i,j;
for(i=1;i<=n/2;i++)
//需要注意的细节就是范围,不过大概想一想就知道了,从1开始不容易出错;n/2和n/2+1是一样的
{
pb=L.NextPos(head);
//这个算法很关键的就是每一次pb都得回到一开始再走,这也是链表的缺点所在;当然,可以提前使用一个priorpos函数,不过都一样
for(j=1;j<=n-i;j++)pb=L.NextPos(pb);
L.GetElem(pa,a);
L.GetElem(pb,b);
if(a!=b)
{
cout<<"false";
return true;//这里不需要break,直接return就行了
}
pa=L.NextPos(pa);//别忘了pa在这移动
}
cout<<"true";
return true;
}
5.把用到的函数从模板库中拿出来
遇到的问题
1.无法运行
没办法运行和调试,这时候虽然字很多但也得沉下心来理解是哪里除了问题。聚焦到问题——Gercurelem函数,undefined,
原来是这个函数没有具体申明,所以不能运行。且这个问题没有报错,只是不能运行,所以这是需要积累的无法运行原因。
而没有申明的原因是当时看到它和Getelem函数是一样的,所以就不用它了,没想到没删干净,留了个函数头在模板中
![](https://img-blog.csdnimg.cn/52dbceb50f424cddbfbbcc1aeff3d1d7.png)
2.选择模板库中模板的时候,发现一次性大量删除就会报错,如果一点点删除则则不会,这个感觉有点奇怪。
完整代码
#include<iostream>//数据流输入/输出:cin>>,cout<<的头文件
#include <algorithm>//算法类函数:sort().....的头文件
#include<string>//字符串操作的头文件
using namespace std;
/* 单链表的结点定义 */
template<class ElemType>
struct Node
{
ElemType data;
Node<ElemType> *next;
Node(Node<ElemType> *ptr = NULL)
{
next = ptr; //构造函数1,用于构Node造头结点
}
Node(const ElemType &item, Node<ElemType> *ptr = NULL) //构造函数2,用于构造其他结点
//函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
{
next = ptr;
data = item;
}
};
//带头结点的单链表
template<class ElemType>
class LinkList
{
private:
Node<ElemType> *head; // 头指针
Node<ElemType> *tail; // 尾指针
public:
//以下定义两个类型,可以看出,Link和Position类型完全相同,
//只是Link类型被认为指向一个链表,Position类型被认为指向某个位置的结点
typedef struct Node<ElemType> *Link;
typedef struct Node<ElemType> *Position;
//create
//无参数的构造函数
LinkList()
{
head = new Node<ElemType>;
tail=head;
}
//表尾插入法动态生成链表
void CreateList_Tail(int n, ElemType A[]);
//基本操作
//遍历链表
bool ListTraverse() const;
//Get与Set
//获取链表头结点指针
Link GetHead()
{
return head;
}
//用e返回链表的第i个元素数据
bool GetElem(int i, ElemType &e);
//用e返回链表pos位置的元素数据
bool GetElem(Position pos, ElemType &e);
//返回pos位置的后继结点的指针
Position NextPos(Position pos);
};
//CreateList//
//2.表尾插入动态生成链表
template<class ElemType>
void LinkList<ElemType>::CreateList_Tail(int n, ElemType A[])
{
Node<ElemType> *r; //r为指向尾结点的指针
r = head;
Node<ElemType> *p; //p为指向待插入结点的指针
for(int i = 0; i < n; i++)
{
p = new Node<ElemType>;
p->data = A[i];
r->next = p;
r = p;
}
r->next = NULL;
tail = r;
}
//基本操作//
//ListTraverse,遍历链表
template<class ElemType>
bool LinkList<ElemType>::ListTraverse() const
{
//遍历链表
Node<ElemType> *p;
p = head->next;
while( p->next)
{
cout<<p->data<<"->";
p = p->next;
} // while
cout<<p->data<<'\n'<<endl;
return true;
}
//GetElem and SetElem//
//用e返回第i个元素
template<class ElemType>
bool LinkList<ElemType>::GetElem(int i, ElemType &e)
{
//由于本函数隐含了一个循环,因此会使得程序的时间复杂度增大n倍,因此不建议实现本方法
Node<ElemType> *p;
p = head->next;
int j = 1; //初始化,p指向第一个结点,j为计数器
while (j < i && p) { //顺链域向后扫描,直到p指向第i个元素或p为空
p = p->next; //p指向下一个结点
++j; //计数器j相应加1
}
if (!p || j > i)
return false; //i值不合法i>n或i<=0
e = p->data; //取第i个结点的数据域
return true;
}
//用e返回指针pos所指向结点的值
template<class ElemType>
bool LinkList<ElemType>::GetElem(Position pos, ElemType &e)
{
Node<ElemType> *p;
p = head->next;
while (p && p!=pos) { //顺链域向后扫描,直到p为空或者扫描到q的位置
p = p->next; //p指向下一个结点
}
if (!p)
return false; //pos不合法
e = p->data; //取结点的数据域
return true;
}
//返回pos位置的后继结点的指针
template<class ElemType>
Node<ElemType>* LinkList<ElemType>::NextPos(Position pos)
{
Node<ElemType> *p;
p = head;
while (p && p!=pos) { //顺链域向后扫描,直到p为空或者扫描到q的位置
p = p->next; //p指向下一个结点
}
if (!p)
return NULL; //pos不合法
return pos->next;
}
//******************************************//以上是模板自带函数
//判断单链表的前n个结点是否中心对称
/*
* 一个个看是不是对称,i++到中间为止
* 一个i一个n-1看是不是一样
* 如果不一样break false
* 结束循环输出true
*/
template<class ElemType>
bool Judge_Symmetry( LinkList<ElemType> &L, int n )
{
typename LinkList<ElemType>::Position pa,pb,head;
ElemType a,b;
head=pa=pb=L.GetHead();
pa=L.NextPos(pa);
pb=L.NextPos(pb);
int i,j;
for(i=1;i<=n/2;i++)
{
pb=L.NextPos(head);
for(j=1;j<=n-i;j++)pb=L.NextPos(pb);
L.GetElem(pa,a);
L.GetElem(pb,b);
if(a!=b)
{
cout<<"false";
return true;
}
pa=L.NextPos(pa);
}
cout<<"true";
return true;
}
/*
* 输入m判断数据类型,输入链表长度n
*构造单链表
*中心对称函数处理
* 试一下能不能把四个合成一个
*/
int main()
{
int m,n,i=0;
cin>>m>>n;
if(m==0)
{
LinkList <int> B;
int input1[100];
int num;
while(cin>>input1[i])i++;
B.CreateList_Tail(i, input1);
B.ListTraverse();
Judge_Symmetry(B,n);
}
else if(m==1)
{
LinkList <double> B;
double input1[100];
double num;
while(cin>>input1[i])i++;
B.CreateList_Tail(i, input1);
B.ListTraverse();
Judge_Symmetry(B,n);
}
else if(m==2)
{
LinkList <char> B;
char input1[100];
char num;
while(cin>>input1[i])i++;
B.CreateList_Tail(i, input1);
B.ListTraverse();
Judge_Symmetry(B,n);
}
else if(m==3)
{
LinkList <string> B;
string input1[100];
string num;
while(cin>>input1[i])i++;
B.CreateList_Tail(i, input1);
B.ListTraverse();
Judge_Symmetry(B,n);
}
else cout<<"err";
return 0;
}