链表回文判断

问题

判断一条单向链表是不是“回文” ?回文,英文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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值