单链表的介绍
1、链表是以节点的方式来存储
2、每个节点包含一个data域以及next域,next域指向下一个节点;
3、链表的各个节点在内存中不一定是连续存储的。
先创建一个头结点
/**
* 定义Node,每个Node对象就是一个节点
*/
public class Node {
public int no;
public String name;
public Node next;//用于指向下一个节点
public Node(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Node{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
当不考虑插入顺序,直接在尾部加入
思路:
1、先创建一个头结点,作用就是表示单链表的头
2、之后每加入一个节点,就直接加入到链表的最后
3、需要一个辅助变量,来帮助遍历整个链表
//先初始化一个头结点,头结点不要动,不存放具体数据,主要作用就是连接整个链表
private Node head = new Node(0, "");
//返回头结点
public Node getHead() {
return head;
}
//添加节点到单向链表(当不考虑添加顺序时)
//思路:1.找到当前链表的最后节点;2.将最后节点的next指向新的节点。
public void add(Node node) {
//因为head节点不能动,因此我们需要一个临时变量temp
Node temp = head;
//遍历链表,找到最后节点
while (true) {
//找到链表的最后
if (temp.next == null) {
break;
}
//如果没有找到最后,就将temp后移
temp = temp.next;
}
//当退出while循环时,temp就指向了链表的最后
//将最后节点的next指向新的节点。
temp.next = node;
}
当考虑插入顺序时,此时需要注意插入的位置
思路:
1、首先需要找到新添加节点的位置;
2、新节点的next指向辅助变量的next
3、将辅助变量的next赋值给新的节点
//添加节点到单向链表(当考虑编号顺序时)
public void addByOrder(Node node) {
//因为头结点不能动,所以我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
//又因为这是一个单链表,所以找的temp是位于添加位置的前一个节点,否则插入不了
Node temp = head;
//flag用来判断添加的编号是否存在,默认值为false
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no > node.no) {
//说明找到该位置,就在temp的后面插入
break;
} else if (temp.next.no == node.no) {
//说明编号存在
flag = true;
break;
}
//指针后移,遍历当前链表
temp = temp.next;
}
//判断flag的值
if (flag) {
//此时不能添加,说明编号已存在
System.out.printf("编号%d已存在,无法添加\n", node.no);
} else {
//此时可以添加,插入到链表中,temp的后面
node.next = temp.next;
temp.next = node;
}
}
单链表节点的修改
//修改节点的信息,根据no编号来修改,即no编号不能改
public void upDate(Node node) {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空!");
}
//找到需要修改的节点,根据no编号
//定义一个辅助变量
Node temp = head;
//表示是否找到该节点
boolean flag = false;
while (true) {
if (temp.next == null) {
//表示已经遍历完该链表
break;
}
if (temp.no == node.no) {
//找到该节点
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到要修改的节点
if (flag) {
temp.name = node.name;
} else {
//没有找到
System.out.printf("没有找到编号为%d的节点,无法修改\n", node.no);
}
}
单链表节点的删除
思路:
1、head节点不能动,因此我们需要一个temp辅助节点找到待删除节点的前一个节点;
2、比较时,是temp.next.no和需要删除的节点的no比较。
public void deleteDate(int no) {
Node temp = head;
//判断是否找到待删除节点
boolean flag = false;
while (true) {
if (temp.next == null) {
//说明已经到达链表的尾部
break;
}
if (temp.next.no == no) {
//找到要删除的节点
flag = true;
break;
}
temp = temp.next;
}
//对flag进行判断
if (flag) {
//删除节点的核心语句
temp.next = temp.next.next;
} else {
System.out.printf("要删除的%d节点不存在\n", no);
}
}
附上完整代码:
public class SingleLinkedList {
//先初始化一个头结点,头结点不要动,不存放具体数据,主要作用就是连接整个链表
private Node head = new Node(0, "");
//返回头结点
public Node getHead() {
return head;
}
//添加节点到单向链表(当不考虑添加顺序时)
//思路:1.找到当前链表的最后节点;2.将最后节点的next指向新的节点。
public void add(Node node) {
//因为head节点不能动,因此我们需要一个临时变量temp
Node temp = head;
//遍历链表,找到最后节点
while (true) {
//找到链表的最后
if (temp.next == null) {
break;
}
//如果没有找到最后,就将temp后移
temp = temp.next;
}
//当退出while循环时,temp就指向了链表的最后
//将最后节点的next指向新的节点。
temp.next = node;
}
//添加节点到单向链表(当考虑编号顺序时)
public void addByOrder(Node node) {
//因为头结点不能动,所以我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
//又因为这是一个单链表,所以找的temp是位于添加位置的前一个节点,否则插入不了
Node temp = head;
//flag用来判断添加的编号是否存在,默认值为false
boolean flag = false;
while (true) {
if (temp.next == null) {
break;
}
if (temp.next.no > node.no) {
//说明找到该位置,就在temp的后面插入
break;
} else if (temp.next.no == node.no) {
//说明编号存在
flag = true;
break;
}
//指针后移,遍历当前链表
temp = temp.next;
}
//判断flag的值
if (flag) {
//此时不能添加,说明编号已存在
System.out.printf("编号%d已存在,无法添加\n", node.no);
} else {
//此时可以添加,插入到链表中,temp的后面
node.next = temp.next;
temp.next = node;
}
}
//修改节点的信息,根据no编号来修改,即no编号不能改
public void upDate(Node node) {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空!");
}
//找到需要修改的节点,根据no编号
//定义一个辅助变量
Node temp = head;
//表示是否找到该节点
boolean flag = false;
while (true) {
if (temp.next == null) {
//表示已经遍历完该链表
break;
}
if (temp.no == node.no) {
//找到该节点
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到要修改的节点
if (flag) {
temp.name = node.name;
} else {
//没有找到
System.out.printf("没有找到编号为%d的节点,无法修改\n", node.no);
}
}
//删除节点
//思路:1.head节点不能动,因此我们需要一个temp辅助节点找到待删除节点的前一个节点
// 2.比较时,是temp.next.no和需要删除的节点的no比较
public void deleteDate(int no) {
Node temp = head;
//判断是否找到待删除节点
boolean flag = false;
while (true) {
if (temp.next == null) {
//说明已经到达链表的尾部
break;
}
if (temp.next.no == no) {
//找到要删除的节点
flag = true;
break;
}
temp = temp.next;
}
//对flag进行判断
if (flag) {
//删除节点的核心语句
temp.next = temp.next.next;
} else {
System.out.printf("要删除的%d节点不存在\n", no);
}
}
//遍历链表
public void list() {
//判断链表是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
//因为头结点不能动,所以需要一个辅助变量来遍历
Node temp = head.next;
while (true) {
//判断是否到链表最后
if (temp == null) {
break;
}
//输出节点的信息
System.out.println(temp);
//最后要将temp后移,不然会造成死循环
temp = temp.next;
}
}
}
测试代码
public class SingleLinkedListTest {
public static void main(String[] args) {
//1、创建节点
Node node1 = new Node(1, "1");
Node node2 = new Node(2, "2");
Node node3 = new Node(3, "3");
Node node4 = new Node(4, "4");
//2、创建链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
SingleLinkedList singleLinkedList2 = new SingleLinkedList();
//无顺序添加
singleLinkedList.add(node1);
singleLinkedList.add(node3);
singleLinkedList.add(node4);
singleLinkedList.add(node2);
System.out.println("无顺序添加");
singleLinkedList.list();
//有顺序添加
singleLinkedList2.addByOrder(node1);
singleLinkedList2.addByOrder(node3);
singleLinkedList2.addByOrder(node4);
singleLinkedList2.addByOrder(node2);
singleLinkedList2.addByOrder(node2);
System.out.println("有顺序添加");
singleLinkedList2.list();
//测试修改方法
Node newNode = new Node(3, "老吴");
singleLinkedList2.upDate(newNode);
System.out.println("修改之后");
singleLinkedList2.list();
//测试删除方法
singleLinkedList2.deleteDate(4);
System.out.println("删除之后");
singleLinkedList2.list();
}
}