问题
判断一条单向链表是不是“回文” ?回文,英文palindrome,指顺着读和反过来读都一样。
思路1
判断回文单向链表跟判断回文字符串很大的区别就是遍历。字符串可以自由向前遍历,而单向字符串不行,因此最简单直观的思路就是将链表翻转,然后再进行比较。但是这种方法就比较笨,因为还需要创建另外一个单链表来存储原有的单链表,然后翻转单链表,然后再进行比较。所以不推荐使用这种方法。
思路2
既然回文单链表有如此特性,那么我们可以考虑部分翻转单链表,然后再利用快慢指针去进行比较,这样没有额外的空间开销,时间复杂度也降低了很多。此时需要注意的问题就是翻转哪一部分的链表?
因此我们首先需要判断的就是该链表的长度是奇数还是偶数。如链表1所示:
a -> b -> c -> d
此时若要判断链表是否为回文链表,我们需要从c处开始翻转,翻转的位置为(length/2 + 1),即将c与d的位置翻转,然后通过快慢指针p和q,p指向起始位置,q指向(length/2 + 1),然后依次比较对应数据是否相同,若全部相同,则是回文指针,否则不是。
当链表2为奇数时,
a -> b -> c -> d -> e
此时需要翻转的位置则是翻转的位置为(length/2 + 2),即将d与e的位置翻转,然后通过快慢指针p和q,p指向起始位置,q指向(length/2 + 2),然后依次比较对应数据是否相同,若全部相同,则是回文指针,否则不是。
具体代码如下:
#include<iostream>
using namespace std;
typedef char ElemType;
typedef struct List{
ElemType data;
struct List *next;
};
typedef List *LinkList;
bool InitLink(LinkList *list){
*list = (LinkList)malloc(sizeof(List));
if(!(*list))
return false;
(*list)->next = NULL;
return true;
}
bool InsertList(LinkList *list, ElemType elem){
if(NULL == list)
return false;
LinkList s = (LinkList)malloc(sizeof(List));
if(!s)
return false;
s->data = elem;
s->next = NULL;
LinkList p = *list;
while(p->next != NULL){
p = p->next;
}
p->next = s;
return true;
}
int LengthList(LinkList *list){
if(NULL == (*list)->next)
return 0;
int count = 0;
LinkList p = (*list)->next;
while(p != NULL){
count++;
p = p->next;
}
return count;
}
void ReverseList(LinkList *list){
if((*list)->next == NULL || (*list)->next->next == NULL)
return ;
int length = LengthList(list);
int count = 0;
LinkList p, q, r, first, subHead;
if(length % 2)
p = (*list);
else
p = (*list)->next;
while(count <= length/2){
p = p->next;
count++;
}
subHead = p;
first = p->next; //the first reverse node
p = p->next;
q = p->next;
while(q != NULL){
r = q->next;
q->next = p;
p = q;
q = r;
}
first->next = NULL;
subHead->next = p;
}
bool IsPalindrom(LinkList *list){
ReverseList(list);
LinkList p, q;
int length = LengthList(list);
int count = 0;
q = (*list)->next;
if(length % 2)
p = (*list);
else
p = (*list)->next;
while(count <= length/2){
p = p->next;
count++;
}
p = p->next;
cout << "p->data: " << p->data << endl;
while(p->next != NULL){
if(q->data != p->data)
return false;
q = q->next;
p = p->next;
}
return true;
}
void printList(LinkList list){
LinkList p = list->next;
while(p != NULL){
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int main(){
List l;
LinkList list = &l;
InitLink(&list);
InsertList(&list, 'm');
InsertList(&list, 'a');
InsertList(&list, 'd');
InsertList(&list, 'a');
InsertList(&list, 'm');
printList(list);
cout << IsPalindrom(&list) << endl;
return 0;
}