一、单向链表
1.定义:
由多个结点组成,每一个结点都由一个数据域和指针域组成,数据域用来存储数据,指针域用来指向其后继结点。
链表的的头结点的数据域不存数据指针域指向第一个正真存储数据的结点。
2.基本实现
1)记录长度
2)判空、清空、移除元素并返回
3)增加元素,指定位置增加元素
4)遍历
5)反转
6)快慢指针
* 求中间值问题:定义两个指针,fast:每次前进2,slow:每次前进1,当fast.next==null时停止;
7)快慢指针判断是否有环,定义两个指针,fast:每次前进2,slow:每次前进1;
若无环则在fast.nest==null时不会相遇。
8)判断环的入口,若有环,在当快慢指针相遇时,再定义一个指针temp,并且与慢指针的步调一致,向后遍历,当temp与slow相遇时,则此处为入口
public class LinkList<T> implements Iterable<T> { //记录头结点 private Node head; //记录链表长度 private int N; //节点类 private class Node{ //存储的数据 T item; //结点 Node next; public Node(T item, Node next) { this.item = item; this.next = next; } } //初始化 public LinkList() { //初始化链表 this.head=new Node(null,null); this.N=0; } //将链表置为空 public void clear(){ head.next=null; this.N=0; } //判断当前链表是否为空 public boolean isEmpry(){ return N==0; } //获取链表的长度 public int length(){ return N; } //获取指定位置的元素 public T get(int i){ //头结点 Node n=head; for (int index=0;index<=i;index++){ n=n.next; } return n.item; } //向链表中添加元素 public void insert(T t){ Node n=head; //找到最后一个结点 while (n.next!=null){ n=n.next; } //创建新的结点 Node NewNode = new Node(t, null); //让当前结点指向最后一个结点 n.next=NewNode; N++; } //向指定位置添加元素 public void insert(int i,T t){ Node pre=head; for(int index=0;index<=i-1;index++){ //i位置的前一个结点 pre=pre.next; } //i位置的结点 Node curr=pre.next; //创建一个新结点 Node NewNode = new Node(t, curr); //前一个结点指向当前结点 pre.next=NewNode; //链表长度增加 N++; } //删除指定位置元素,返回该元素 public T remove(int i){ Node pre=head; for (int index=0;index<=i-1;index++){ pre =pre.next; } //i位置的结点 Node curr=pre.next; //i位置的下一个结点 Node nextNode=curr.next; //前一个指向后一个 pre.next=nextNode; N--; return curr.item; } //查找元素第一次出现的位置 public int indexOf(T t){ Node n=head; for (int i=0;n.next!=null;i++){ n=n.next; if(n.item.equals(t)){ return i; } } return -1; } /** * 链表表遍历 * 1)让类实现Iterable接口,重写iterator方法 * 2)在类内部提供一个内部类SIterator,实现iteator接口,重写hasNext和Next方法 */ @Override public Iterator<T> iterator() { return new SIterator(); } private class SIterator implements Iterator{ private Node n; public SIterator(){ this.n=head; } /** * 是否还有元素 * @return */ @Override public boolean hasNext() { return n.next!=null; } /** * 返回下一个元素 */ @Override public Object next() { n=n.next; return n.item; } } //反转整个链表 public void reverse(){ //链表为空 if(isEmpry()){ return; } reverse(head.next); } //反转指定的节点,并把反转后的结点返回 public Node reverse(Node curr){ if(curr.next==null){ head.next=curr; return curr; } //递归反转当前结点curr的下一个结点,返回值就是链表反转后,当前结点的上一个结点 Node pre=reverse(curr.next); //返回的下一个结点为当前结点 pre.next=curr; //把当前结点的下一个结点变为null curr.next=null; return curr; } //快慢指针求中间值 public T getMid(){ //初始化两个指针 Node fast=head; Node slow=head; while (fast!=null && fast.next!=null){ fast=fast.next.next; slow=slow.next; } return slow.item; } //快慢指针判断是否有环,并返回环的入口 public T isCircle(){ Node n=head; //假设在结点2处模拟一个环 for (int i=0;i<=2;i++){ n=n.next; } Node n2=head; while (n2.next!=null){ n2=n2.next; } n2.next=n; //初始化两个指针 //初始化两个指针 Node fast=head.next; Node slow=head.next; Node temp=null;//零时指针 while (fast!=null && fast.next!=null) { fast = fast.next.next; slow = slow.next; if (fast.equals(slow)) { System.out.println("有环相遇"); temp = head.next; continue; } //让零时指针变换 if (temp != null) { temp = temp.next; if (temp.equals(slow)) { break; } } } return temp.item; } }