链表是一种常见的基础数据结构,是一种线性表。在计算机科学中,链表作为一种基础的数据结构来生成其他类型的数据结构,链表通常有一串节点构成,每一个节点包含一个数据实例和一个或者两个指向上一个或者下一个数据节点的指针,链表允许插入和移除链表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
1.单向链表
链表中最简单的一种形式,包含两个域,一个数据域和一个指针域,这个指针指向链表中的下一个节点,单链表的最后一个节点指向空。
1.1 单链表的生成
首先定义单链表节点数据类型:
public class Node {
int value;
Node next;
}
利用尾插法生成一个单链表:
public Node createlist(int[] list) {
Node head = new Node();
Node p = head;
for (int i = 0; i < list.length; i++) {
Node r = new Node();
r.value = list[i];
r.next = null;
p.next = r;
p = p.next;
}
return head;
}
1.2 删除链表的第i个节点
删除链表的第i个节点,首先找到第i-1个节点,然后让其后继节点指向第i个节点的下一个节点。
public void Deletelist(Node head,int i){
if (head==null ||i<=0){
return;
}
Node p=head;
int j=0;
while(p!=null&&j<i-1){
p=p.next;
j++;
}
p.next=p.next.next;
}
1.3 在链表的第i个位置插入一个元素
首先找到链表的第i-1个位置,在进行插入之前,需要对i个值进行判断
public void Insertlist(Node head,int i,int value){
if (head==null||i<=0){
return;
}
Node p=head;
int j=0;
while(p!=null&&j<i-1){
p=p.next;
j++;
}
if (p==null){
System.out.println("i is too big");
return;
}
Node node=new Node();
node.value=value;
Node q=p.next;
p.next=node;
node.next=q;
}
1.4 单链表的反转
单链表的反转通过遍历链表,记住当前节点的前一个节点和后一个节点,对链表进行反转。
public Node Reverselist(Node head){
if (head==null||head.next==null){
return head;
}
Node p=head.next;
Node q=head.next.next;
p.next=null;
Node r=new Node();
while(q!=null){
r=q.next;
q.next=p;
p=q;
q=r;
}
head=p;
return head;
}
1.5 判断链表是否存在环
判断链表是否存在着环可以通过快慢指针的方法,设立两个指针,一个指针一次移动一步,另一个一次移动两步,如果某一时刻两个指针相遇的话,则说明链表存在着环。
public boolean hasCycle(Node head){
if (head==null){
return false;
}
Node p=head;
Node q=head;
while(p!=null&&q!=null&&q.next!=null){
p=p.next;
q=q.next.next;
if (p==q){
return true;
}
}
return false;
}
1.6 找出有环链表环开始的地方
借鉴1.5的方法,当两个指针相遇的时候让快指针从头开始,慢指针继续向前遍历,下一次二者相遇的时候就是环开始的地方。
public Node detectCycle(Node head){
if (head==null ||head.next==null){
return null;
}
Node p=head;
Node q=head;
while(p!=null&&q!=null&&q.next!=null){
p=p.next;
q=q.next.next;
if (p==q){
break;
}
}
if (p!=q){
return null;
}
q=head;
while(p!=q){
p=p.next;
q=q.next;
}
return p;
}