判断一个链表是否为回文结构
2016-07-02 20:31
375 查看
题目:判断一个链表是否为回文结构。
要求:时间复杂度为 O(n),空间时间复杂度为O(1)。
思路分析:回文链表的特点就是对称,那么要判断是否回文,就可以用两个指针指向对称的节点,看它们的数据是否一样。由于是单向链表,不能同时用两个指针,从头尾向内部遍历取值比较。且本题对空间复杂度也有要求,所以可用如下方法实现。
具体步骤如下:
(1)先得到链表的中间节点;
(2)从中间节点的下一个节点开始,反转链表。
(3)从中间节点处,断开原链表。
(4)用两个指针分别向两个端点移动,同时进行比较,数据相同则继续,数据不同则直接返回false。直到遍历完成,最后返回true。
备注:关于单链表的中间节点问题,详见博文“寻找单链表的中间节点“。
有一个注意点如下:
要求:时间复杂度为 O(n),空间时间复杂度为O(1)。
思路分析:回文链表的特点就是对称,那么要判断是否回文,就可以用两个指针指向对称的节点,看它们的数据是否一样。由于是单向链表,不能同时用两个指针,从头尾向内部遍历取值比较。且本题对空间复杂度也有要求,所以可用如下方法实现。
具体步骤如下:
(1)先得到链表的中间节点;
(2)从中间节点的下一个节点开始,反转链表。
(3)从中间节点处,断开原链表。
(4)用两个指针分别向两个端点移动,同时进行比较,数据相同则继续,数据不同则直接返回false。直到遍历完成,最后返回true。
#include <iostream> using namespace std; // 单链表节点结构 typedef struct node { int data; struct node *next; } NODE; // 尾插法创建单链表 NODE *createEnd() { NODE *head = new NODE(); head->next = NULL; NODE *end = head; int a; cin >> a; while (a != 999) { NODE *p = new NODE(); p->data = a; end->next = p; p->next = NULL; end = p; cin >> a; } return head; } // 打印不带头节点的单链表 void print(NODE *head) { while (head != NULL) { cout << head->data << ' '; head = head->next; } } // 快慢指针查找单链表的中间节点(不带头节点的单链表) NODE *FindMid(NODE *head) { NODE *slow = head; // head当作快指针;初始时快、慢指针都指向第一个节点。 while (head != NULL && head->next != NULL && head->next->next != NULL) { head = head->next->next; slow = slow->next; } return slow; } // 反转链表(不带头节点的单链表) NODE *reverseList(NODE *head) { NODE *rHead = NULL; // 反转后链表的第一个节点,先初始化为NULL NODE *p_now = head; // 让当前节点指向第一个节点,即头指针指向的节点(注意:此时是没有头节点的单链表) NODE *p_prev = NULL; // 初始化为NULL;第一次使用时,可作为反转后链表的最后一个节点的next的指向,即NULL while (p_now != NULL) { NODE *p_next = p_now->next; if (p_next == NULL) rHead = p_now; p_now->next = p_prev; p_prev = p_now; p_now = p_next; } return rHead; } // palindrome [ˈpælɪndroʊm] n. 回文(指顺读和倒读都一样的词语) bool isPalindrome(NODE *head) { NODE *mid = FindMid(head); // 找到链表的中间节点(看下方的备注,注意此处FindMid的特点) NODE *rHead = reverseList(mid->next); // 从链表中点的下一个节点开始,反转链表 mid->next = NULL; // 从中点处,断开原链表 while (head != NULL && rHead != NULL) { if (head->data == rHead->data) { head = head->next; rHead = rHead->next; } else return false; } return true; } int main(int argc, const char * argv[]) { NODE *head = createEnd(); print(head->next); cout << endl; if (isPalindrome(head->next)) cout << "是回文结构" << endl; else cout << "不是回文结构" << endl; return 0; }
备注:关于单链表的中间节点问题,详见博文“寻找单链表的中间节点“。
有一个注意点如下:
// 注意,本文中找中间节点时,应使用FindMid的形式,比如{1,2,3,4,5,6},偶数个元素 // 使用 FindMid 找到的中间元素是 3 // 使用 FindMid2 找到的中间元素是 4 // 本文应使用 FindMid 的样式,可以不用考虑链表长度的奇偶。 NODE *FindMid2(NODE *head) { NODE *slow = head; // head当作快指针;初始时快、慢指针都指向第一个节点。 while (head != NULL && head->next != NULL) { head = head->next->next; slow = slow->next; } return slow; }
相关文章推荐
- [C/C++]反转链表
- C#实现基于链表的内存记事本实例
- C#模拟链表数据结构的实例解析
- C语言实现带头结点的链表的创建、查找、插入、删除操作
- C++利用静态成员或类模板构建链表的方法讲解
- C++实现简单的学生管理系统
- Linux内核链表实现过程
- C++链表倒序实现方法
- C#通过链表实现队列的方法
- Node.js环境下JavaScript实现单链表与双链表结构
- C#实现的简单链表类实例
- 找出链表倒数第n个节点元素的二个方法
- Java数据结构之简单链表的定义与实现方法示例
- Java模拟有序链表数据结构的示例
- C语言单循环链表的表示与实现实例详解
- C++实现的链表类实例
- PHP小教程之实现链表
- PHP中模拟链表和链表的基本操作示例
- C语言双向链表的表示与实现实例详解
- js链表操作(实例讲解)