链表是由结点的方式来储存的,是链式存储。其的组成需要有data(数据域),指向下一个结点的next,指向前一个结点的pre(双向链表)。链表可以分为有头结点和无头结点的链表。注意:链表是一种逻辑上的顺序存储结构,而物理上不一定是顺序存储结构。(即在实际计算机存储中不一定是按照顺序存储的,但在我们的逻辑上认为,它们就是连续存储的)
单链表:单链表顾名思义,就是只有单向存储,没有双向存储,也即只有一个next结点,没有pre结点。这里可以分为直接把数据添加到末尾和根据数据大小插入到指定的位置。
注意点:因为单链表是单向的,所以单链表的删除与添加都需要找到要添加位置的前一个结点或者要删除结点的前一个结点,这里我们会借助一个cur临时结点要找寻
注意点在于:临时结点的表示含义,要理解好什么时候临时结点指向的是哪个结点。
CRUD的核心点在于next的指向变动,下面附上代码具体实现
package com.liu.linkedlist;
/**
* @author liuweixin
* @create 2021-09-07 8:32
*/
//单链表。实现的是从小到大的排序插入
public class SingleLinkedList {
private Node head = new Node("", 0);//头结点
public static void main(String[] args) {
SingleLinkedList list = new SingleLinkedList();//创建一个链表
list.show();
list.addNode(new Node("a", 1));
list.addNode(new Node("b", 2));
list.addNode(new Node("c", 3));
list.addNode(new Node("d", 4));
list.addNode(new Node("e", 5));
list.show();
list.deleteNode(6);
list.deleteNode(3);
list.show();
list.update(new Node("a1",1));
list.update(new Node("g",111));
list.show();
}
/**
* 添加结点
*
* @param node 要加入的结点
*/
//对结点的操作放到链表中实现
public void addNode(Node node) {
if (head.next == null) {
//只有一个头结点,可以直接把数据加入到链表中
head.next = node;
} else {
Node cur = head.next;//借助辅助结点去寻找到插入位置的前一个结点
while (cur.next != null && cur.next.no < node.no) {//当cur.next.no>node.no时退出循环,此时已找到插入位置的前一个结点。
//通过循环获取到插入位置的前一个结点
cur = cur.next;//cur需要下移,才能找到合适的位置
}
if (cur.next == null) {//找到链表的最后仍然没有比插入结点的no值大的,直接添加到链表的最后
cur.next = node;
return;
}
//此时cur.next.no>node.no,即找到插入位置的前一个结点
node.next = cur.next;//实现结点的传递
cur.next = node;
}
}
/**
* 删除链表的结点
*
* @param no 结点数据的编号
*/
public void deleteNode(int no) {
if (head.next == null) {
System.out.println("链表为空,无法删除");
} else {
Node cur = head.next;//借助辅助结点去寻找到插入位置的前一个结点
while (true) {
if (cur.next == null) {//找到最后还没有找到删除的位置,说明该链表没有对应结点
System.out.println("链表无该节点,无法删除");
return;
}
if (cur.next.no == no) {
//此时已找到删除位置的前一个结点。
if (cur.next.next != null) { //删除结点的下一个结点不为空
cur.next = cur.next.next;
} else {//删除结点的下一个结点为空
cur.next = null;
}
return;//删除完成,结束方法
}
cur = cur.next;
}
}
}
/**
* 更改结点信息
* @param node 要更改的结点
*/
public void update(Node node) {
if (head.next == null) {
System.out.println("链表为空,无法更改");
} else {
Node cur = head;//借助辅助结点去寻找到插入位置的前一个结点
while (true) {
if (cur.next == null) {
if(cur.no!=node.no){
//找到最后还没有找到更新的位置,说明该链表没有对应结点
System.out.println("链表无该节点,无法更新");
}
return;
}
if (cur.next.no == node.no) {
//找到要更新的结点的前一个结点
if (cur.next.next != null) { //更新结点的下一个结点不为空
node.next = cur.next.next;
cur.next = node;//结点的移接
} else {//更新的结点是最后一个结点
cur.next=node;
}
return;
}
cur = cur.next;
}
}
}
/**
* 遍历链表数据
*/
public void show() {
if (head.next == null) {
System.out.println("该链表无数据");
return;
}
Node cur = head.next;
while (cur != null) {//注意这里的指针变化,这里的指针指的是当前遍历的结点,而不是遍历结点的前一个结点,这里跟上面添加和删除的临时结点不同
System.out.println(cur);
cur = cur.next;
}
}
}
class Node {//定义一个结点对象,每一个对象就是一个结点
Node next;
String name;
int no;
public Node(String name, int no) {
this.name = name;
this.no = no;
}
@Override
public String toString() {
return "node{" +
", name='" + name + '\'' +
", no=" + no +
'}';
}
}