/*双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方
便地访问它的前驱结点和后继结点。
下图是双向链表的逻辑结构图,和单链表不同的是,双向链表中每个节点包含两个节点的指针引用,和一个数据域,这两个节点分别指向前一个节点和后一个节点;
双向链表的这种结构比起单链表,其改进之处正在于此,通过对前后节点的引用可以使得在整个链表中,通过给定的值,可以从前或者向后遍历,大大提升了遍历
查询的效率,一定程度上解决了单链表的性能问题,但与此同时,链表的存储开销也增大了,我们熟悉的linkedList,其底层就是这个原理实现的。
/**
* 题目:在双链表中删除倒数第K个节点
* 实现函数可以删除双链表中的倒数第K个节点。
* 要求:
* 如果链表长度为N,时间复杂度为O(N),额外空间复杂度达到O(1)。
* 分析:
* 1.如果链表为空或者 K值小于1, 这种情况下, 参数是无效的, 直接返回即可。
* 除此之外, 让链表从头开始走到尾, 每移动一步, 就让 K的值减1。
*
* 链表: 1->2->3, K=4, 链表根本不存在倒数第4个节点
* 走到的节点: 1 -> 2 -> 3
* K变化为: 3 2 1
*
* 链表: 1->2->3, K= 3, 链表倒数第3个节点是l 节点。
* 走到的节点: 1 -> 2 -> 3
* K变化为: 2 I 0
*
* 链表: 1->2->3, K=2, 链表倒数第2个节点是2节点。
* 走到的节点: 1 -> 2 -> 3
* K变化为: 1 0 1
*
* 由以上三种情况可知, 让链表从头开始走到尾, 每移动一步, 就让 K值减 1, 当链表
*走到结尾时, 如果 K值大于0, 说明不用调整链表, 因为链表根本没有倒数第 K个节点,
*此时将原链表直接返回即可;
*
* 如果 K值等于0, 说明链表倒数第K个节点就是头节点, 此时直接返回head.next,
*也就是原链表的第二个节点,让第二个节点作为链表的头返回即可,相当于删除头节点;
*
* 如果K值小于0,首先明确一点, 如果要删除链表的头节点之后的某个节点, 实际上需要
*找到要删除节点的前一个节点, 比如: 1->2->3, 如果想删除节点2, 则需要找到节点1,
*然后把节点1连到节点3上(1->3), 以此来达到删除节点2的目的。
*
* 如果K值小于0, 如何找到要删除节点的前一个节点呢?方法如下:
*1. 重新从头节点开始走, 每移动一步, 就让 K的值加 1。
*2. 当 K等于 0时, 移动停止, 移动到的节点就是要删除节点的前一个节点。
*
* 如果链表长度为N, 要删除倒数第K个节点, 很明显,倒数第K个节点的前一个节点就是
*第 N-K个节点。在第一次遍历后, K的值变为 K-N。第二次遍历时,K的值不断加1,加到 0
*就停止遍历, 第二次遍历当然会停到第 N-K个节点的位置。
*
* 注意:
* 要注意 last指针的重连。
* @author 雪瞳
*
*/
public class DoubleNode {
public int value;
public DoubleNode next;
public DoubleNode last;
public DoubleNode(int data) {
this.value=data;
}
}
public class ReamoNode {
public DoubleNode removeLastKthNode(DoubleNode head , int K) {
if(K<0 || head == null) {
return null;
}
DoubleNode cur = head;
while(cur!=null) {
K = K-1;
cur = cur.next;
}
if(K==0) {
head = head.next;
head.last = null;
}
if(K<0) {
cur = head;
//先自增在判断,如果自增完成后不满足判断条件,说明当前节点cur的下一个节点就是需要删除的节点
while(++K != 0) {
cur = cur.next;
}
//将当前节点与下一个节点的下一节点相连接
DoubleNode newNext =cur.next.next;
cur.next = newNext;
//若newNext不是空则需要将cur和newNext相连
if(newNext != null) {
newNext.last = cur;
}
}
return head;
}
}
import java.util.Random;
import java.util.Scanner;
public class testRemoveNode {
public static void main(String[] args) {
testRemoveNode test = new testRemoveNode();
ReamoNode remove = new ReamoNode();
Random rand = new Random();
DoubleNode nodes[]=new DoubleNode[10];
Scanner sc = new Scanner(System.in);
System.out.print("请输入需要删除倒数第几个节点 K=");
int K = sc.nextInt();
for(int i=0;i<nodes.length;i++) {
nodes[i]=new DoubleNode(rand.nextInt(10));
}
for(int i =0;i<nodes.length-1;i++) {
nodes[i].next=nodes[i+1];
}
test.showNode(nodes[0]);
remove.removeLastKthNode(nodes[0], K);
test.showNode(nodes[0]);
}
public void showNode(DoubleNode head) {
System.out.println("链表内的元素如下所示...");
while(head != null) {
System.out.print(head.value+" ");
head = head.next;
}
System.out.println();
}
}