概述
单线链表:单向链表又叫单链表,是链表的一种。由节点构成,head指针指向第一个称为表头节点,而终止指向最后一个null指针
特点
- 链表连接的方向都是单向的
- 链表的访问要通过顺序从头部开始
- 链表是使用指针进行构造的列表
- 是由一个一个节点组成的链表,又称为节点链表
- 每个节点都有指针成员变量指向链表中的下个节点
结构
说明:可以比喻成火车,head是火车头data是火车厢,每一个火车厢的车厢next都拉着一个下一个车厢
优点
- 单个节点的创建非常方便(增)
- 节点的删除非常方便,不需要线性结构那样移动数据(删)
缺点
- 只能冲头到位遍历,只能后续,无法找到前驱,也就是只能前进
- 查询时搜索遍历需要遍历整个链表,在不好的情况下,可能需要道链尾才能找到
- 链表需要维护next域,暂用内存
案例
创建一个单向列表
public class Node {
//存储节点的值
int val;
//下一个节点地址
Node next;
public Node(int val) {
this.val = val;
}
public Node(int val, com.study.data.linked.Node next) {
this.val = val;
this.next = next;
}
}
测试
1、插头法,从头部上添加数据
输出结果:5->4->3->3->2->NULL
//实际存储的个数,相当于火车车厢的个数
private int size;
//第一个节点,相当于火车头
private Node head;
//在头部上增加链数据(插头罚),如果链表为空,那么就是增加火车头
public void addFirst(int data) {
//要向链表中添加节点,要判断当前的链表是否为空,如果一个都没有,那么就要插入第一个节点
Node node = new Node(data);
if (size == 0) {
head = node;
size++;
} else {
//当前的火车已经存在节点了
// 头部为上一个节点
node.next = head;
head = node;
size++;
}
}
/**
* 用来展示链表
* @return
*/
public String showNode() {
StringBuilder ret = new StringBuilder();
Node node = head;
while (node != null) {
ret.append(node.val).append("->");
// 继续访问下一节车厢
node = node.next;
}
ret.append("NULL");
return ret.toString();
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
System.out.println(test.showNode());
}
2、插尾法(从尾部开始插入数据)
输出结果:2->3->3->4->5->NULL
//插尾法,从尾部开始添加数据
public void addLast(int data) {
//要向链表中添加节点,要判断当前的链表是否为空,如果一个都没有,那么就要插入第一个节点
Node node = new Node(data);
if (size == 0) {
head = node;
size++;
} else {
//当前的火车已经存在节点了
Node last = head;
while (last.next != null) {
last = last.next;
}
// 头部为上一个节点
last.next = node;
size++;
}
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addLast(2);
test.addLast(3);
test.addLast(3);
test.addLast(4);
test.addLast(5);
System.out.println(test.showNode());
}
3、在链表的中间插入位置
输出结果:5->4->4->3->3->2->NULL
图片详解
代码实现
//在链表的中间插入位置
public void addIndex(int index, int data) {
//判断边界条件,判断index的合法性
if (index < 0 || index > size) {
System.out.println("插入链表位置失败....");
return;
}
if (index == 0) {
// 从链表的头部开始插入
addFirst(data);
return;
}
//说明此时index合法,并且时在中间这个位置,此时需要知道index的前驱节点,单链表只能从前往后遍历
//将要插入的链表值添加进去
Node node = new Node(data);
//获取到整个链表值
Node result = head;
for (int i = 0; i < index - 1; i++) {
//移除大于index-1的头部数据
result = result.next;
}
//将上面尾巴数据赋值过去,要注意这里时next,所以实际上是head的next,比如4 0 1 ,next的话是0 1
//node的数据还是刚刚添加的数据,这个时候就会变成了data+result.next的数据
node.next = result.next;
//将result中的next对node进行替换,上面的node已经完成了拼接
result.next = node;
size++;
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.addIndex(2,4);
System.out.println(test.showNode());
}
4、获取下标中的数据
输出结果:4
// 查询index节点上的数据
public int get(int index) {
if (index < 0 || index >= size) {
System.out.println("获取链表位置index值失败...");
return -1;
}
//获取到前一个节点
Node node = head;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.val;
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
System.out.println(test.showNode());
System.out.println("获取节点1的数据" + test.get(1));
}
5、对链表中某个值进行替换
输出结果:5->4->0->3->2->NULL
//对下标的某个值进行替换
public int set(int index, int data) {
if (index < 0 || index >= size) {
System.out.println("修改单链表中的数据失败");
return -1;
}
Node node = head;
for (int i = 0; i < index; i++) {
node = node.next;
}
//需要替换位置的值
int oldData = node.val;
// 进行值替换
node.val = data;
return oldData;
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.set(2,0);
System.out.println(test.showNode());
}
6、判断链表是否包含某个值
输出:true
// 判断链表中是否包含元素data
public boolean contains(int data) {
Node node = head;
while (node != null) {
if (node.val == data) {
System.out.println("找到了元素" + data);
return true;
}
node = node.next;
}
System.out.println("没有找到元素" + data);
return false;
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
System.out.println(test.contains(5));
System.out.println(test.showNode());
}
7、移除链表中第一个值
输出结果:4->3->3->2->NULL
//移除第一个值
public void removeFirst() {
if (size == 0) {
return;
}
Node node = head;
head = node.next;
node.next = null;
size--;
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.removeFirst();
System.out.println(test.showNode());
}
8、通过下标移除对应的值
输出结果:5->4->3->2->NULL
//通过下标移除值
public void removeIndex(int index) {
if (index < 0 || index > size) {
System.out.println("通过下标移除失败,下标异常");
}
if (index == 0) {
removeFirst();
} else {
Node node = head;
for (int i = 0; i < index - 1; i++) {
node = head.next;
}
// node是待删除的头部节点,del就是你要删除的节点
Node del = node.next;
//将两个节点给连接起来
node.next = del.next;
del.next = null;
size--;
}
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.removeIndex(2);
System.out.println(test.showNode());
}
9、删除指定元素的第一个节点
输出:5->4->3->2->NULL
//删除指定元素的第一个节点
public void removeValueFirst(int data) {
//先判断头节点情况,看看头节点是不是正好等于待删除节点
if (head.val == data) {
removeFirst();
} else {
//先找到待删除的节点
Node node = head;
while (node.next != null) {
//找到待删除节点,找到了以后可以直接删除
if (node.next.val == data) {
Node del = node.next;
node.next = del.next;
del.next = null;
size--;
break;
} else {
node = node.next;
}
}
}
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.removeValueFirst(3);
System.out.println(test.showNode());
}
10、删除链表中的所有节点
输出结果:5->4->2->NULL
//删除链表中包含值的所有节点
public void removeValueAll(int data) {
//判断头节点
while (head != null && head.val == data) {
removeFirst();
}
if (head == null) {
System.out.println("当前节点已经为空了!");
return;
}
//头节点处理完毕,并且链表不等于空
Node node = head;
while (node.next != null) {
//12345
if (node.next.val == data) {
Node del = node.next;
node.next = del.next;
del.next = null;
size--;
} else {
node = node.next;
}
}
}
public static void main(String[] args) {
NodeTest test = new NodeTest();
test.addFirst(2);
test.addFirst(3);
test.addFirst(3);
test.addFirst(4);
test.addFirst(5);
test.removeValueAll(3);
System.out.println(test.showNode());
}