在讨论之前,我们首先首先要明白,什么是单链表?
单链表:链接方式存储的线性表
单链表的结点结构
┌──┬──┐
│data│next│
└──┴──┘
data域--存放结点值的数据域
next域--存放结点的直接后继的地址(位置)的指针域(链域)
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
那么我们先用java设计一下我们的单链表
public class MyLinkedList<E> { Node<E> first; Node<E> last; public MyLinkedList() { super(); } public void add(E e) { if (first == null) { first = new Node<E>(e, null); } else { if (last == null) { last = new Node<E>(e, null); first.next = last;// 因为first和last还没建立关系,所以在这里要将他们的关系建立起来 } else { Node<E> n = new Node<>(e, null);// 一个临时的引用n last.next = n;// 将last的next赋值为n的引用 last = n;// 然后再将last重新赋值为n的引用 } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); for (Node<E> n = first; n != null; n = n.next) { sb.append(n.item).append(","); } sb.deleteCharAt(sb.length()-1).append("]"); return sb.toString(); } private static class Node<E> { E item; Node<E> next; Node(E element, Node<E> next) { this.item = element; this.next = next; } } }
注意了,在这里我设计的单链表仅仅是为了符合我们讨论的问题,并不是完整的单链表,同时为了测试,我重写了toString方法。在这个单链表里面,我并没有实现List<E>这个接口,因为要实现的方法太多了,而且first和last这两个成员变量没有用private修饰符修饰,是不符合封装的思想,这里我一切从简。
我们先往里面添加一些数值,顺便测试下我们设计的单链表是否可以
public static void main(String[] args){ MyLinkedList<Integer> list=new MyLinkedList<>(); list.add(2); list.add(1); list.add(5); list.add(8); list.add(7); System.out.println(list.toString()); }
运行结果:
没错,我们设计的单链表没问题
①快慢指针:一个指针每次按着顺序跳两次,而另一个指针只跳一次,当第一个指针跳到的元素为空是,那么第二个指针就处于中间的位置
/** * 获取中间元素 * * @return */ public E getMiddle() { Node<E> n1 = first;// 每次只走一步,慢指针 Node<E> n2 = first;// 每次走两步,快指针 L: while (true) { if (n2.next != null && n2.next.next != null) { n1 = n1.next; n2 = n2.next.next; } else { break L; } } return n1.item; }
将上面的代码添加到MyLinkedList.java里面,测试
public static void main(String[] args){ MyLinkedList<Integer> list=new MyLinkedList<>(); list.add(2); list.add(1); list.add(5); list.add(8); list.add(7); System.out.println(list.toString()); System.out.println(list.getMiddle()); }
结果如下:
时间: 2024-10-10 22:08:19