一.需求
使用JAVA实现单链表,使用单链表检测字符串是否是回文串
二.需求分析
回文串最重要的就是对称,那么最重要的问题就是找到那个中心,用快指针每步走两格,当他到达链表末端的时候,慢指针刚好到达中心,慢指针在遍历过程中(快指针到达末端时)把走过的节点进行反向操作,此时从中位点分为前后两部分,此时前半部分的指针开始往回指(取next的时候,取的是前一个节点),而慢指针继续向前,跟前半部分的数据依次进行比对,当慢指针扫完整个链表,就可以判断这是回文串,否则就提前退出,同时在前半部分往回遍历的过程中将前半部分的指针重置成正向。
链表存在奇偶数情况。
奇数的时候,快指针遍历到末端的时候,中点位即中间位置的点,此中位点下一个节点为后半部分比对开始的位置。
偶数的时候,快指针遍历到末端的时候,中点位置此时为下中位点,此中位点就是后半部分比对开始的位置。
三.代码实现
1.单链表类封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | 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.验证的具体方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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 ; } |
四.代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } |
五.完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | 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封装单链表的资料请关注自学编程网其它相关文章!
- 本文固定链接: https://zxbcw.cn/post/200600/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)