基础篇(四):链表

链表-百度百科
手写链表(单链表中结点的定义):

public class SinglyListNode {
    int val;
    SinglyListNode next;
    SinglyListNode(int x){val=x;}
}

在大多数情况下,我们将使用头结点(第一个结点)来表示整个列表。

1.哨兵节点

哨兵节点是为了简化处理链表边界条件而引入的附加链表节点。哨兵节点通常位于链表的头部,它的值没有任何意义。在一个有哨兵节点的链表中,从第2个节点开始才真正保存有意义的信息。

1.1 用哨兵节点简化链表插入操作
向链表尾部添加一个节点。由于通常只有一个指向单向链表头节点的指针,因此需要遍历链表中的节点直至到达链表的尾部,然后在尾部添加一个节点。可以用如下代码实现这个过程:

public ListNode append(ListNode head,int value){
	ListNode newNode=new ListNode(value);
	if(head==null){
		return newNode;
	}
	ListNode node=head;
	while(node.next!=null) {
		node=node.next;
	}
	node.next=newNode;
	return head;
}

向链表的尾部添加一个节点的另一个方法:首先创建一个 哨兵节点,并把该节点当作链表的头节点,然后把原始的链表添加在哨兵节点的后面。当完成添加操作之后,再返回链表真正的头节点,也就是哨兵节点的下一个节点。代码如下:

public ListNode append(ListNode head,int value){
	ListNode dummy=new ListNode(0);
	dummy.next=head;
	ListNode newNode=new ListNode (value);
	ListNode node=dummy;
	while(node.next!=null){
		node=node.next;
	}
	node.next=newNode;
	return dummy.next;
}

将新创建的一个哨兵节点当作链表的头节点,链表无论如何也不会为空。哨兵节点简化了代码的逻辑。

1.2 用哨兵节点简化链表删除操作
从链表中删除第1个值为指定值的节点。通常为了删除一个节点,应该找到被删除节点的前一个节点,然后把该节点的next指针指向它下一节点的下一节点,这样下一个节点没有被其他节点引用,也就相当于被删除了。需要逐一遍历链表中的节点以便找到第1个指定值的节点,代码如下:

public ListNode delete(ListNode head, int value){
	if(head==null){
		return head;
	}
	if(head.val==value){
		return head.next;
	}
	ListNode node=head;
	while(node.next!=null){
		if(node.next.val==value){
			node.next = node.next.next;
			break;
		}
		node=node.next;
	}
	return head;
}

如果在链表的最前面添加一个哨兵节点作为头节点,那么链表就不为空,并且链表的头节点无论如何都不会被删除。因此,也可以用哨兵节点来简化从链表中删除节点的代码逻辑:

public static ListNode delete(ListNode head,int value){
	ListNode dummy=new ListNode(0);
	dummy.next=head;
	ListNode node=dummy;
	while(node.next!=null){
		if(node.next.value==value){
			node.next=node.next.next;
			break;
		}
		node=node.next;
	}
	return dummy.next;

解题小经验:使用哨兵节点可以简化创建或删除链表头节点操作的代码。

new ListNode常用方法

  1. 初始化一个空结点,没有复制,指针指向list
    ListNode list=new ListNode();
  2. 初始化一个空结点,初始值为0,指针指向为list
    ListNode list=new ListNode(0);
  3. 初始化一个空结点,初始赋值为0,并且list的下一个next指针指向head,指针指向为list
    ListNode list=new ListNode(0,head);
  4. 定义一个空链表
    ListNode list=null;

通常定义一个空结点需要有结点的next指针指向,否则,只是定义一个空结点
通常使用以下两种方法:
ListNode list=new ListNode(0,head);
或者
ListNode list=new ListNode(0);
list.next=head;

2.双指针

双指针一般两类,一类是「快慢指针」,一类是「左右指针」。前者主要解决链表中的问题,比如典型的判定链表中是否有环;后者主要解决数组(或字符串)中的问题,如二分查找。

未完,待续

3.反转链表

有些题只有从链表尾节点开始遍历到头节点才容易解决。这个时候可以先将链表反转,然后在反转的链表中从头到尾遍历,这就相当于在原来的链表中从尾到头遍历。

未完,待续

4.双向链表和回文链表

双向链表在单向链表节点的基础上增加了指向前一个节点的指针,这样一来,既可以从头节点开始从前往后遍历到尾节点,也可以从尾节点开始从后往前遍历到头节点。

循环链表既可以是单向链表也可以是双向链表。即使一个循环链表是单向链表,也可以从任意节点出发到达另一个任意节点,因此,在循环链表中任意节点都可以当作链表的头节点。

未完,待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值