1.链表的概念
数据域:存储元素信息的空间(可以是数组)。
指针域:数据域的后继位置为指针域。用于存放指针。
指针/链:指针用于节点之间的联系。
节点:数据域和指针域共同组成节点。
头节点:头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义。
2.链表的实现
2.1 节点封装类
package com.zr.node;
/**
* 节点封装类
*/
public class Node {
private String nodeName;
private Node next;//节点类
//构建一个节点对象
public Node(String nodeName) {
this.nodeName = nodeName;
}
//返回下一个节点的对象
public Node getNext() {
return this.next;
}
//设置本节点的链域
public void setNext(Node next) {
this.next = next;
}
//返回节点的数据域
public String getName() {
return this.nodeName;
}
//判断是否有下一节点
public boolean hasNext() {
boolean is =false;
if(this.getNext()!=null) {
is = true;
}
return is;
}
}
2.2 Link类
package com.zr.link;
import com.zr.node.Node;
public class Link {
private Node head;//头节点
public Link(String head) {
this.head = new Node(head);
}
//追加节点
public void addNode(String name) {
Node p =head;//p是head的一个指针
Node node =new Node(name);
while(true) {
if(!p.hasNext()) {
p.setNext(node);
break;
}
p=p.getNext();//指针后移
}
}
// 删除节点
public boolean delNode(String nodeName) {
Node p = head;
if (!p.hasNext()) {
System.out.println("此表为空");
return false;
}
while (p.hasNext()) {
if (p.getNext().getName().equals(nodeName)) {
p.setNext(p.getNext().getNext());
break;
}
p = p.getNext();
}
System.out.println("删除节点:" + nodeName);
return true;
}
/*
* 插入节点
*/
public boolean insertNode(String inName,String nodeName) {
Node p = head;
if (!p.hasNext()) {
addNode(nodeName);
return true;
}
while (p.hasNext()) {
if (p.getNext().getName().equals(inName)) {
Node node=new Node(nodeName);
node.setNext(p.getNext().getNext());
p.getNext().setNext(node);
break;
}
p = p.getNext();
}
System.out.println("插入节点:" + nodeName);
return true;
}
// 遍历链表
public void display() {
Node p = head.getNext();
while (p != null) {
System.out.println(p.getName());
p = p.getNext();
}
}
// 定位查找
public void orderFind(int num) {
Node node = head;
int i = 0;
System.out.println("--------开始遍历--------");
while (node != null) {
if (i == num) {
System.out.println("被查找的节点为:" + node.getName());
break;
}
i++;
node = node.getNext();
}
}
// 按内容查找
public void contenFind(String name) {
Node node = head;
int i = 0;
System.out.println("--------开始遍历--------");
while (node != null) {
if (node.getName().equals(name)) {
System.out.println("被查找的节点为:" + node.getName());
break;
}
i++;
node = node.getNext();
}
}
}
3.实例
3.1 LeetCode 2 :两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
思路:
1.创建第三个链表,指针指向这个链表(暂时),后面用于操作。
2.carry用于判断是否进位,sum(和)对十取商。如果carry等于0,即为进位
3.将sum对十取模的值放入第三个链表。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode third =new ListNode(0);//创建第三个链表,用于存储输出的和,默认为0
ListNode forth =third;//指针指向第三个链表
int carry = 0;//判断是否进位
while(l1!=null||l2!=null){
int x =l1!=null?l1.val :0;//取得l1当前节点的值
int y =l2!=null?l2.val:0;//取得l2当前节点的值
int sum =x+y+carry;
carry =sum/10;//判断是否能进位
sum %=10;
forth.next =new ListNode(sum);
forth =forth.next;//指针后移
if(l1.next!=null) l1=l1.next;//更新l1
if(l2.next!=null) l2=l2.next;//更新l2
if(carry==1){//若还有进位,则添加到最后一位
forth.next =new ListNode(carry);
}
}
return third.next;//因为初始位置是0,所以要输出下一位
}
}
3.2 LeetCode 19 :删除链表的倒数第n个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路:
1.核心是双指针,设前指针(start)和后指针(end)。
2.前指针向前移动n,然后两个指针同时向前移动。当链表为null时,end的位置为倒数第n个节点。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode pre =new ListNode(0);//创建第二个链表,用于存储输出的结果,默认为0
pre.next=head;//指针指向head
ListNode start =pre;//将start与pre连接起来
ListNode end = pre;//将end与pre连接起来
while(n!=0){
start=start.next;//节点移动
n--;
}
while(start.next!=null){//前后两个节点相差n,只要将start和end同时移动,且start在最后一个位置,end就在倒数第n个位置
start=start.next;//节点移动
end=end.next;//节点移动
}
end.next=end.next.next;//删除倒数第n个节点,即连线
return pre.next;
}
}