用JAVA实现单链表,检测字符串是否是回文串
一.需求
使用JAVA实现单链表,使用单链表检测字符串是否是回文串
二.需求分析
回文串最重要的就是对称,那么最重要的问题就是找到那个中心,用快指针每步走两格,当他到达链表末端的时候,慢指针刚好到达中心,慢指针在遍历过程中(快指针到达末端时)把走过的节点进行反向操作,此时从中位点分为前后两部分,此时前半部分的指针开始往回指(取next的时候,取的是前一个节点),而慢指针继续向前,跟前半部分的数据依次进行比对,当慢指针扫完整个链表,就可以判断这是回文串,否则就提前退出,同时在前半部分往回遍历的过程中将前半部分的指针重置成正向。
链表存在奇偶数情况。
奇数的时候,快指针遍历到末端的时候,中点位即中间位置的点,此中位点下一个节点为后半部分比对开始的位置。
偶数的时候,快指针遍历到末端的时候,中点位置此时为下中位点,此中位点就是后半部分比对开始的位置。
三.代码实现
1.单链表类封装
public class ListNode<T> {
/**
* 根节点索引位置
*/
private int foot;
/**
* 代表链表程度
*/
private int count;
/**
* 标识根节点
*/
private Node root;
//链接点类,内部方法实现,外部使用
private class Node {
//数据信息
private T data;
//下一个节点引用
private Node next;
public Node(T data) {
this.data = data;
}
//添加节点
private void add(T data) {
if (this.next == null) {
//如果当前节点的next为null,直接创建一个新的节点
this.next = new Node(data);
} else {
//否则进行递归调用,直到最后在某个为空的节点创建一个新节点
this.next.add(data);
}
}
//删除节点1
public void remove(Node previous, int index) {
if (ListNode.this.foot++ == index) {
//this表示当前要删除的节点
previous.next = this.next;
this.next = null;
ListNode.this.count--;
return;
} else {
//递归删除
this.next.remove(this, index);
}
}
//删除节点2
public void remove(Node previous, T data) {
if (this.data.equals(data)) {
previous.next = this.next;
this.next = null;
ListNode.this.count--;
return;
} else {
if (this.next != null) {
this.next.remove(this, data);
} else {
return;
}
}
}
//修改数据 -- 新数据替换旧数据
public void replace(T oldData, T newData) {
if (this.data.equals(newData)) {
this.data = newData;
} else {
//递归修改,寻找当前节点下一个节点,直到某个节点的值匹配入参
this.next.replace(oldData, newData);
}
}
//修改数据 -- 利用索引修改
public void replace(int index, T newData) {
if (ListNode.this.foot++ == index) {
//找到了某个值的索引和传入的索引相同,直接替换
this.data = newData;
} else {
this.next.replace(index, newData);
}
}
//查询
public T get(int index) {
if (ListNode.this.foot++ == index) {
return this.data;
} else {
return this.next.get(index);
}
}
//链表是否包含某个节点
public boolean contains(T data) {
//如果当前的这个data正好和传入的data匹配
if (this.data.equals(data)) {
return true;
} else {
//如果当前的这个不匹配,则需要查找下一个节点
if (this.next == null) {
return false;
} else {
return this.next.contains(data);
}
}
}
}
public ListNode() {
}
//检查链表是否为空
public boolean isEmpty() {
if (count == 0 || this.root == null) {
return true;
} else {
return false;
}
}
//获取链表的长度
public int size() {
return this.count;
}
//添加
public void add(T data) {
if (this.isEmpty()) { //如果链表为空,新建一个节点
this.root = new Node(data);
} else {
this.root.add(data);
}
this.count++;
}
//删除 -- 按照索引删除
public void remove(int index) {
if (this.isEmpty()) {
return;
}
if (index < 0 || this.count <= index) {
return;
}
if (index == 0) { //想要删除根节点
Node temp = this.root;
this.root = this.root.next;
temp.next = null;
this.count--;
return;
} else {
this.foot = 0;
this.root.remove(this.root, index);
}
}
//根据传入的数值删除
public void remove(T data) {
if (this.isEmpty()) {
return;
}
//如果删除的正好是根节点
if (this.root.data.equals(data)) {
Node temp = this.root;
this.root = this.root.next;
temp.next = null;
this.count--;
return;
} else {
this.root.remove(this.root, data);
}
}
//修改 -- 根据索引修改
public void replace(int index, T newData) {
if (this.isEmpty()) {
return;
}
if (index < 0 || this.count <= index) {
return;
}
this.foot = 0;
this.root.replace(index, newData);
}
//修改 -- 新老数据替换
public void replace(T oldData, T newData) {
if (this.isEmpty()) {
return;
}
this.root.replace(oldData, newData);
}
//查询 --- 根据索引查找
public T get(int index) {
if (this.isEmpty()) {
return null;
}
this.foot = 0;
return this.root.get(index);
}
//是否包含
public boolean contains(T data) {
if (this.isEmpty()) {
return false;
}
return this.root.contains(data);
}
//打印 toArray
public Object[] toArray() {
if (this.isEmpty()) {
return null;
}
int count = this.count;
Object[] retVal = new Object[count];
for (int i = 0; i < count; i++) {
retVal[i] = this.get(i);
}
return retVal;
}
}
2.验证的具体方法
boolean isPalindrome(ListNode.Node head) {
if (head == null || head.next == null) {
return true;
}
//
ListNode.Node prev = null;
//慢指针节点
ListNode.Node slow = head;
//快指针节点
ListNode.Node fast = head;
//奇数的中位节点或者是偶数的下中位节点
ListNode.Node middle = head;
while (fast != null && fast.next != null) {
//快指针每次移动2个节点
fast = fast.next.next;
//慢指针每次移动1个节点
ListNode.Node next = slow.next;
//前半部分的指针反向。反向后前半部分节点的next节点都是他的前一个节点
slow.next = prev;
//当前的慢指针指向前一个节点
prev = slow;
//下一个节点变为慢节点
slow = next;
//记录中位节点
middle = slow;
}
//如果fast不是null,说明此时有奇数个节点,偶数个节点时fast为null
//还没有进行if处理之前slow节点和prev节点在奇偶数的情况下分别为
// a b c d c b a 此种情况下slow节点是d,prev节点是第1个c
// a b c c b a 此种情况下slow节点是第2个c,prev节点是第1个c
if (fast != null) {
//slow取中间节点的下一个节点,做为回文比较的起点
slow = slow.next;
}
//进行if处理结束之后,slow代表的是后半段的第一个节点,指针向后移动
//prev代表的是前半段的最后一个节点,指针向前移动
// a b c d c b a 此种情况下slow节点是第2个c,prev节点是第1个c
// a b c c b a 此种情况下slow节点是第2个c,prev节点是第1个c
//前半部分指针恢复正常处理。将下一个节点记录下来
ListNode.Node next = middle;
while (slow != null) {
//进行数据比对。如果不相等则不是回文
if (slow.data != prev.data) {
return false;
}
//前半部分当前节点
ListNode.Node current = prev;
//prev向前取节点
prev = prev.next;
//slow向后取节点
slow = slow.next;
//前半部分指针恢复正常处理。
current.next = next;
//本轮处理完之后,将next赋值为当前节点
next = current;
}
return true;
}
四.代码测试
public static void main(String[] args) {
ListNode<String> listNode = new ListNode<String>();
listNode.add("a");
listNode.add("b");
listNode.add("c");
listNode.add("d");
listNode.add("e");
listNode.add("f");
listNode.add("e");
listNode.add("d");
listNode.add("c");
listNode.add("b");
listNode.add("a");
ListNode example = new ListNode();
boolean b = example.isPalindrome(listNode.root);
System.out.println("是否是回文:" + b);//true
}
五.完整代码
public class ListNode<T> {
/**
* 根节点索引位置
*/
private int foot;
/**
* 代表链表程度
*/
private int count;
/**
* 标识根节点
*/
private Node root;
//链接点类,内部方法实现,外部使用
private class Node {
//数据信息
private T data;
//下一个节点引用
private Node next;
public Node(T data) {
this.data = data;
}
//添加节点
private void add(T data) {
if (this.next == null) {
//如果当前节点的next为null,直接创建一个新的节点
this.next = new Node(data);
} else {
//否则进行递归调用,直到最后在某个为空的节点创建一个新节点
this.next.add(data);
}
}
//删除节点1
public void remove(Node previous, int index) {
if (ListNode.this.foot++ == index) {
//this表示当前要删除的节点
previous.next = this.next;
this.next = null;
ListNode.this.count--;
return;
} else {
//递归删除
this.next.remove(this, index);
}
}
//删除节点2
public void remove(Node previous, T data) {
if (this.data.equals(data)) {
previous.next = this.next;
this.next = null;
ListNode.this.count--;
return;
} else {
if (this.next != null) {
this.next.remove(this, data);
} else {
return;
}
}
}
//修改数据 -- 新数据替换旧数据
public void replace(T oldData, T newData) {
if (this.data.equals(newData)) {
this.data = newData;
} else {
//递归修改,寻找当前节点下一个节点,直到某个节点的值匹配入参
this.next.replace(oldData, newData);
}
}
//修改数据 -- 利用索引修改
public void replace(int index, T newData) {
if (ListNode.this.foot++ == index) {
//找到了某个值的索引和传入的索引相同,直接替换
this.data = newData;
} else {
this.next.replace(index, newData);
}
}
//查询
public T get(int index) {
if (ListNode.this.foot++ == index) {
return this.data;
} else {
return this.next.get(index);
}
}
//链表是否包含某个节点
public boolean contains(T data) {
//如果当前的这个data正好和传入的data匹配
if (this.data.equals(data)) {
return true;
} else {
//如果当前的这个不匹配,则需要查找下一个节点
if (this.next == null) {
return false;
} else {
return this.next.contains(data);
}
}
}
}
public ListNode() {
}
//检查链表是否为空
public boolean isEmpty() {
if (count == 0 || this.root == null) {
return true;
} else {
return false;
}
}
//获取链表的长度
public int size() {
return this.count;
}
//添加
public void add(T data) {
if (this.isEmpty()) { //如果链表为空,新建一个节点
this.root = new Node(data);
} else {
this.root.add(data);
}
this.count++;
}
//删除 -- 按照索引删除
public void remove(int index) {
if (this.isEmpty()) {
return;
}
if (index < 0 || this.count <= index) {
return;
}
if (index == 0) { //想要删除根节点
Node temp = this.root;
this.root = this.root.next;
temp.next = null;
this.count--;
return;
} else {
this.foot = 0;
this.root.remove(this.root, index);
}
}
//根据传入的数值删除
public void remove(T data) {
if (this.isEmpty()) {
return;
}
//如果删除的正好是根节点
if (this.root.data.equals(data)) {
Node temp = this.root;
this.root = this.root.next;
temp.next = null;
this.count--;
return;
} else {
this.root.remove(this.root, data);
}
}
//修改 -- 根据索引修改
public void replace(int index, T newData) {
if (this.isEmpty()) {
return;
}
if (index < 0 || this.count <= index) {
return;
}
this.foot = 0;
this.root.replace(index, newData);
}
//修改 -- 新老数据替换
public void replace(T oldData, T newData) {
if (this.isEmpty()) {
return;
}
this.root.replace(oldData, newData);
}
//查询 --- 根据索引查找
public T get(int index) {
if (this.isEmpty()) {
return null;
}
this.foot = 0;
return this.root.get(index);
}
//是否包含
public boolean contains(T data) {
if (this.isEmpty()) {
return false;
}
return this.root.contains(data);
}
//打印 toArray
public Object[] toArray() {
if (this.isEmpty()) {
return null;
}
int count = this.count;
Object[] retVal = new Object[count];
for (int i = 0; i < count; i++) {
retVal[i] = this.get(i);
}
return retVal;
}
boolean isPalindrome(ListNode.Node head) {
if (head == null || head.next == null) {
return true;
}
//
ListNode.Node prev = null;
//慢指针节点
ListNode.Node slow = head;
//快指针节点
ListNode.Node fast = head;
//奇数的中位节点或者是偶数的下中位节点
ListNode.Node middle = head;
while (fast != null && fast.next != null) {
//快指针每次移动2个节点
fast = fast.next.next;
//慢指针每次移动1个节点
ListNode.Node next = slow.next;
//前半部分的指针反向。反向后前半部分节点的next节点都是他的前一个节点
slow.next = prev;
//当前的慢指针指向前一个节点
prev = slow;
//下一个节点变为慢节点
slow = next;
//记录中位节点
middle = slow;
}
//如果fast不是null,说明此时有奇数个节点,偶数个节点时fast为null
//还没有进行if处理之前slow节点和prev节点在奇偶数的情况下分别为
// a b c d c b a 此种情况下slow节点是d,prev节点是第1个c
// a b c c b a 此种情况下slow节点是第2个c,prev节点是第1个c
if (fast != null) {
//slow取中间节点的下一个节点,做为回文比较的起点
slow = slow.next;
}
//进行if处理结束之后,slow代表的是后半段的第一个节点,指针向后移动
//prev代表的是前半段的最后一个节点,指针向前移动
// a b c d c b a 此种情况下slow节点是第2个c,prev节点是第1个c
// a b c c b a 此种情况下slow节点是第2个c,prev节点是第1个c
//前半部分指针恢复正常处理。将下一个节点记录下来
ListNode.Node next = middle;
while (slow != null) {
//进行数据比对。如果不相等则不是回文
if (slow.data != prev.data) {
return false;
}
//前半部分当前节点
ListNode.Node current = prev;
//prev向前取节点
prev = prev.next;
//slow向后取节点
slow = slow.next;
//前半部分指针恢复正常处理。
current.next = next;
//本轮处理完之后,将next赋值为当前节点
next = current;
}
return true;
}
public static void main(String[] args) {
ListNode<String> listNode = new ListNode<String>();
listNode.add("a");
listNode.add("b");
listNode.add("c");
listNode.add("d");
listNode.add("e");
listNode.add("f");
listNode.add("e");
listNode.add("d");
listNode.add("c");
listNode.add("b");
listNode.add("a");
ListNode example = new ListNode();
boolean b = example.isPalindrome(listNode.root);
System.out.println("是否是回文:" + b);
}
}
以上是 用JAVA实现单链表,检测字符串是否是回文串 的全部内容, 来源链接: utcz.com/z/338977.html