用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实现单链表,检测字符串是否是回文串的详细内容,更多关于java封装单链表的资料请关注我们其它相关文章!

(0)

相关推荐

  • java计算任意位水仙花数示例(回文数)

    可计算任意位水仙花数 复制代码 代码如下: public static void main(String[] args) {  int max = 10;  for (int len = 1; len <= max; len++) {   System.out.println(getNarc(len, ""));  } } static StringBuffer strb = new StringBuffer(); static String getNarc(int len, S

  • Java数据结构之简单链表的定义与实现方法示例

    本文实例讲述了Java数据结构之简单链表的定义与实现方法.分享给大家供大家参考,具体如下: 一.概述: 1.原理: 只有一个数据项(链接点Link),每个数据插入时都是对第一个数据的引用. 2.插入数据说明: 当链表没有数据时,插入的值就是第一个数据,如果链表里有数据,就把当前的数据的next指针指向第一个数据. 3.插入数据图: 4.特点:先进后出 5.实现功能: 数据插入,指定位置插入,显示,查询,删除等 6.删除原理 7.插入头节点原理 二.实现: 1.创建节点 /** * @描述 节点

  • Java实现单链表的各种操作

    主要内容: 单链表的基本操作 删除重复数据 找到倒数第k个元素 实现链表的反转 从尾到头输出链表 找到中间节点 检测链表是否有环 在不知道头指针的情况下删除指定节点 如何判断两个链表是否相交并找出相交节点 直接上代码,就是这么奔放~~~ package pers.ty.$1101datastructure; import java.util.Hashtable; /** * @author Administrator * 实现单链表的基本操作,增加删除节点.排序.打印.计算长度 */ publi

  • java 实现单链表逆转详解及实例代码

    java 实现单链表逆转详解 实例代码: class Node { Node next; String name; public Node(String name) { this.name = name; } /** * 打印结点 */ public void show() { Node temp = this; do { System.out.print(temp + "->"); temp = temp.next; }while(temp != null); System.o

  • java判断回文数示例分享

    判断一个数是不是回文数示例,回文数就是原数与其倒置后的数相等,如:123321,到之后仍为123321,即为回文数 题目:一个5位数,判断它是不是回文数.即12321是回文数,个位与万位相同,十位与千位相同. /** * 判断一个数是不是回文数,回文数就是原数与其倒置后的数相等 * 如:123321,到之后仍为123321,即为回文数 * @author lvpeiqiang */ public class HuiWenShu { public boolean isHuiWenShu(int n

  • Java实现单链表翻转实例代码

    Java实现单链表反转,递归和非递归两种形式 /** * 反转单链表 */ /** * 定义链表 * * @author 16026 * */ class Node { int val; Node next; public Node(int val) { this.val = val; } } public class ReverseList { /** * 反转链表 * * @param head * @return */ public static Node reverseList(Node

  • Java实现带头结点的单链表

    链表的特点 1,以节点方式存储,是链式结构. 2,每个节点包含data域,next域:指向下一个节点. 3,链表的各个节点不一定是连续存储. 4,链表分为带头节点和不带头节点两种类型的链表. 实现原理 添加节点:如下图所示,首先遍历原有链表,找到最后一个节点,将要增加的节点添加到该节点的后面.下面介绍如何找到最后一个节点. 思路是这样的,先遍历整个链表,定义一个辅助变量temp,用于暂时存储遍历出来的各个节点.首先将head头节点赋给temp(从头节点开始遍历),通过一个死循环不断的遍历节点的n

  • java实现单链表增删改查的实例代码详解

    package 数据结构算法.链表; /* *定义节点 * 链表由节点构成 */ public class Node<E> { private E e; //数据data private Node<E> next; //指向下一个节点 public Node() { } public Node(E e) { this.e = e; } public Node<E> getNext() { return next; } public void setNext(Node&l

  • java 实现判断回文数字的实例代码

    前言: 有这样一类数字,它们顺着看和倒着看是相同的数,例如:121.656.2332等,这样的数字就称为回文数字.编写一个Java程序,判断从键盘接收的数字是否为回文数字. 2.解题思想 从回文数字的特点出发,弄清楚其特点是解决本问题的关键.解决方案可以通过将该数字倒置的办法来判断它是否是回文数字,例如:586,它的倒置结果为685,因为586!=685,故586不是回文数字. 3.Java代码 import java.util.Scanner; public class Palindrome

  • Java版本的回文字算法(java版本)

    废话不多说了,直接给大家贴代码了,具体代码如下所述: package com.gdh.backtext; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class BackText { String text; public BackText() { super(); this.text = null; } public BackText(String text) { supe

  • Java判断字符串回文的代码实例

    首先,回文是指类似于"12345","abcdcba"的形式,即正念和反念都是一样的字符串 判断字符串是否是回文,这边介绍2种办法 1.将字符串翻转,判断翻转后的字符串和原字符串是否相等 public static void main(String[] args) { String s="abcdcba"; // 用StringBuilder的reverse方法将字符串反转 StringBuilder sb=new StringBuilder(s

  • Java实现查找当前字符串最大回文串代码分享

    先看代码 public class MaxHuiWen { public static void main(String[] args) { // TODO Auto-generated method stub String s = "abb"; MaxHuiWen(s); } //1.输出回文串 public static void MaxHuiWen(String s){ //存储字符串的长度 int length = s.length(); //存储最长的回文串 String M

随机推荐